From 22de598456cb2fbe306b1fae050d069b17e95037 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 1 Jan 2024 03:46:48 -0500 Subject: [PATCH 001/116] devel release --- CMakeLists.txt | 2 +- Changes | 6 ++++++ configure.ac | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index af9bdf1e0..3e5bfee71 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ cmake_minimum_required(VERSION 3.15) cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime project(Verilator - VERSION 5.020 + VERSION 5.021 HOMEPAGE_URL https://verilator.org LANGUAGES CXX ) diff --git a/Changes b/Changes index f40ca5aa1..a2c83c324 100644 --- a/Changes +++ b/Changes @@ -8,6 +8,12 @@ The changes in each Verilator version are described below. The contributors that suggested a given feature are shown in []. Thanks! +Verilator 5.021 devel +========================== + +**Minor:** + + Verilator 5.020 2024-01-01 ========================== diff --git a/configure.ac b/configure.ac index cb82e3e7b..726446f9a 100644 --- a/configure.ac +++ b/configure.ac @@ -10,7 +10,7 @@ # Then 'make maintainer-dist' #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[5.020 2024-01-01], +AC_INIT([Verilator],[5.021 devel], [https://verilator.org], [verilator],[https://verilator.org]) From 3eaed3b6f52f933c32aa2469264c047a930d0f00 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 1 Jan 2024 16:16:48 +0100 Subject: [PATCH 002/116] Remove deprecated 32-bit pointer mode (#4791). --- .github/workflows/build.yml | 51 ++++++----------------- .github/workflows/coverage.yml | 1 - .github/workflows/format.yml | 1 - Changes | 3 ++ ci/ci-install.bash | 14 ------- ci/ci-script.bash | 10 +---- configure.ac | 24 +---------- docs/guide/deprecations.rst | 5 --- include/verilated.mk.in | 3 -- test_regress/driver.pl | 8 ---- test_regress/t/t_flag_ldflags.pl | 8 ++-- test_regress/t/t_threads_crazy_context.pl | 4 -- 12 files changed, 21 insertions(+), 111 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 42eb92003..653197c85 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -37,34 +37,20 @@ jobs: compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } - # m32 1 is deprecated, not here to speed up regressions - m32: [0] - exclude: - # Build pull requests only with ubuntu-22.04 and without m32 - # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} - # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} - # - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} - # Build -m32 only on ubuntu-22.04 clang++ - - {os: ubuntu-18.04, m32: 1} - - {os: ubuntu-20.04, m32: 1} - - compiler: { cc: gcc, cxx: g++ } - m32: 1 include: # Build GCC 10 on ubuntu-20.04 - os: ubuntu-20.04 compiler: { cc: gcc-10, cxx: g++-10 } - m32: 0 runs-on: ${{ matrix.os }} - name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} ${{ matrix.m32 && '| -m32' || '' }} + name: Build | ${{ matrix.os }} | ${{ matrix.compiler.cc }} env: CI_BUILD_STAGE_NAME: build CI_RUNS_ON: ${{ matrix.os }} - CI_M32: ${{ matrix.m32 }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }} + CACHE_BASE_KEY: build-${{ matrix.os }}-${{ matrix.compiler.cc }} CCACHE_MAXSIZE: 1000M # Per build matrix entry (* 5 = 5000M in total) - VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz + VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz steps: - name: Checkout @@ -108,36 +94,24 @@ jobs: compiler: - { cc: clang, cxx: clang++ } - { cc: gcc, cxx: g++ } - m32: [0] suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1] - exclude: - # Build pull requests only with ubuntu-22.04 and without m32 - # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }} - # - os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }} - # - m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }} - # Build -m32 only on ubuntu-22.04 - - {os: ubuntu-18.04, m32: 1} - - {os: ubuntu-20.04, m32: 1} - - compiler: { cc: gcc, cxx: g++ } - m32: 1 include: - # Test with GCC 10 on ubuntu-20.04 without m32 - - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0} - - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-1} - - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-2} - - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-0} - - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: vltmt-1} + # Test with GCC 10 on ubuntu-20.04 + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-0} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-1} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: dist-vlt-2} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-0} + - {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, suite: vltmt-1} runs-on: ${{ matrix.os }} - name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} ${{ matrix.m32 && '| -m32' || '' }} + name: Test | ${{ matrix.os }} | ${{ matrix.compiler.cc }} | ${{ matrix.suite }} env: CI_BUILD_STAGE_NAME: test CI_RUNS_ON: ${{ matrix.os }} - CI_M32: ${{ matrix.m32 }} CC: ${{ matrix.compiler.cc }} CXX: ${{ matrix.compiler.cxx }} - CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-m32=${{ matrix.m32 }}-${{ matrix.suite }} + CACHE_BASE_KEY: test-${{ matrix.os }}-${{ matrix.compiler.cc }}-${{ matrix.suite }} CCACHE_MAXSIZE: 100M # Per build per suite (* 5 * 5 = 2500M in total) - VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}${{ matrix.m32 && '-m32' || '' }}.tar.gz + VERILATOR_ARCHIVE: verilator-${{ github.sha }}-${{ matrix.os }}-${{ matrix.compiler.cc }}.tar.gz steps: - name: Download tar archive @@ -174,7 +148,6 @@ jobs: env: CI_BUILD_STAGE_NAME: build CI_RUNS_ON: ubuntu-22.04 - CI_M32: 0 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 4dcffead4..8bba01198 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -11,7 +11,6 @@ on: env: CI_OS_NAME: linux CI_COMMIT: ${{ github.sha }} - CI_M32: 0 COVERAGE: 1 VERILATOR_ARCHIVE: verilator-coverage-${{ github.sha }}.tar.gz diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index 3aa88e6a6..df69546d4 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -16,7 +16,6 @@ jobs: CI_OS_NAME: linux CI_RUNS_ON: ubuntu-22.04 CI_COMMIT: ${{ github.sha }} - CI_M32: 0 steps: - name: Checkout uses: actions/checkout@v3 diff --git a/Changes b/Changes index a2c83c324..055678d16 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,9 @@ Verilator 5.021 devel **Minor:** +* Remove deprecated 32-bit pointer mode (`gcc -m32`). + + Verilator 5.020 2024-01-01 ========================== diff --git a/ci/ci-install.bash b/ci/ci-install.bash index 668400b07..07a6141b3 100755 --- a/ci/ci-install.bash +++ b/ci/ci-install.bash @@ -27,12 +27,6 @@ fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } -if [ "$CI_M32" = "0" ]; then - unset CI_M32 -elif [ "$CI_M32" != "1" ]; then - fatal "\$CI_M32 must be '0' or '1'"; -fi - if [ "$CI_OS_NAME" = "linux" ]; then MAKE=make elif [ "$CI_OS_NAME" = "osx" ]; then @@ -77,10 +71,6 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then if [ "$COVERAGE" = 1 ]; then yes yes | sudo cpan -fi Parallel::Forker fi - if [ "$CI_M32" = 1 ]; then - sudo apt-get install gcc-multilib g++-multilib || - sudo apt-get install gcc-multilib g++-multilib - fi elif [ "$CI_OS_NAME" = "osx" ]; then brew update brew install ccache perl gperftools @@ -114,10 +104,6 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then sudo apt-get install libsystemc-dev || sudo apt-get install libsystemc-dev fi - if [ "$CI_M32" = 1 ]; then - sudo apt-get install lib32z1-dev gcc-multilib g++-multilib || - sudo apt-get install lib32z1-dev gcc-multilib g++-multilib - fi elif [ "$CI_OS_NAME" = "osx" ]; then brew update # brew cask install gtkwave # fst2vcd hangs at launch, so don't bother diff --git a/ci/ci-script.bash b/ci/ci-script.bash index ea2389faf..b254a4932 100755 --- a/ci/ci-script.bash +++ b/ci/ci-script.bash @@ -21,12 +21,6 @@ fatal() { echo "ERROR: $(basename "$0"): $1" >&2; exit 1; } -if [ "$CI_M32" = "0" ]; then - unset CI_M32 -elif [ "$CI_M32" != "1" ]; then - fatal "\$CI_M32 must be '0' or '1'"; -fi - if [ "$CI_OS_NAME" = "linux" ]; then export MAKE=make NPROC=$(nproc) @@ -46,7 +40,7 @@ if [ "$CI_BUILD_STAGE_NAME" = "build" ]; then if [ "$COVERAGE" != 1 ]; then autoconf - ./configure --enable-longtests --enable-ccwarn ${CI_M32:+--enable-m32} + ./configure --enable-longtests --enable-ccwarn ccache -z "$MAKE" -j "$NPROC" -k # 22.04: ccache -s -v @@ -91,7 +85,7 @@ elif [ "$CI_BUILD_STAGE_NAME" = "test" ]; then fi # Run sanitize on Ubuntu 22.04 only - [ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && [ "$CI_M32" = "" ] && sanitize='--sanitize' || sanitize='' + [ "$CI_RUNS_ON" = 'ubuntu-22.04' ] && sanitize='--sanitize' || sanitize='' # Run the specified test ccache -z diff --git a/configure.ac b/configure.ac index 726446f9a..7679d98e6 100644 --- a/configure.ac +++ b/configure.ac @@ -67,20 +67,6 @@ AC_ARG_ENABLE([tcmalloc], [CFG_WITH_TCMALLOC=check;]) AC_MSG_RESULT($CFG_WITH_TCMALLOC) -# Flag to enable -m32 build -AC_MSG_CHECKING(whether to use -m32) -AC_ARG_ENABLE([m32], - [AS_HELP_STRING([--enable-m32], - [Use -m32 for all compilation and link, - including Verilator and generated models.])], - [case "${enableval}" in - yes) CFG_ENABLE_M32=yes ;; - no) CFG_ENABLE_M32=no ;; - *) AC_MSG_ERROR([bad value '${enableval}' for --enable-m32]) ;; - esac], - CFG_ENABLE_M32=no) -AC_MSG_RESULT($CFG_ENABLE_M32) - # Flag to enable coverage build AC_MSG_CHECKING(whether to build for coverage collection) AC_ARG_ENABLE([coverage], @@ -319,15 +305,7 @@ AC_DEFUN([_MY_LDLIBS_CHECK_OPT], _MY_LDLIBS_CHECK_IFELSE($2, $1="$$1 $2") ]) -# When using -m32. Check this first as later checks may fail with the -m32 flag. -if test "$CFG_ENABLE_M32" = "yes"; then - _MY_CXX_CHECK_IFELSE( - -m32, - [CXX="$CXX -m32"], - [AC_MSG_ERROR([--enable-m32 was given but compiler does not support -m32])]) -fi - -# Similarly, add the coverage flags early as they influence later checks. +# Add the coverage flags early as they influence later checks. if test "$CFG_ENABLE_COVERAGE" = "yes"; then _MY_CXX_CHECK_OPT(CXX,--coverage) # Otherwise inline may not show as uncovered diff --git a/docs/guide/deprecations.rst b/docs/guide/deprecations.rst index 149cbd370..52d396976 100644 --- a/docs/guide/deprecations.rst +++ b/docs/guide/deprecations.rst @@ -13,8 +13,3 @@ C++11 compiler support Verilator will require C++20 or newer compilers for both compiling Verilator and compiling all Verilated models no sooner than January 2025. - -32-bit compiler support - Verilator currently regresses both 64-bit and 32-bit pointer modes (GCC's - `-m64` and `-m32`). Support for 32-bit `-m32` mode will be deprecated no - sooner than January 2024. diff --git a/include/verilated.mk.in b/include/verilated.mk.in index cc9e615c8..c8cf05d6d 100644 --- a/include/verilated.mk.in +++ b/include/verilated.mk.in @@ -101,9 +101,6 @@ LDFLAGS += $(CFG_LDFLAGS_VERILATED) #OPT = -ggdb -DPRINTINITSTR CPPFLAGS += $(OPT) -CPPFLAGS += $(M32) -LDFLAGS += $(M32) - # On macOS, specify all weak symbols as dynamic_lookup. # Otherwise, you get undefined symbol errors. ifeq ($(UNAME_S),Darwin) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 07db695c2..526ced720 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -640,7 +640,6 @@ sub new { ? " -Wl,-undefined,dynamic_lookup" : " -export-dynamic") . ($opt_verbose ? " -DTEST_VERBOSE=1" : "") - . (cfg_with_m32() ? " -m32" : "") . " -o $self->{obj_dir}/libvpi.so"], tool_c_flags => [], # ATSIM @@ -2432,13 +2431,6 @@ sub cfg_with_ccache { return $_Cfg_with_ccache; } -our $_Cfg_with_m32; - -sub cfg_with_m32 { - $_Cfg_with_m32 ||= `grep "CXX.*=.*-m32" "$ENV{VERILATOR_ROOT}/include/verilated.mk"` ne ""; - return $_Cfg_with_m32; -} - sub tries { # Number of retries when reading logfiles, generally only need many # retries when system is busy running a lot of tests diff --git a/test_regress/t/t_flag_ldflags.pl b/test_regress/t/t_flag_ldflags.pl index 33d73877b..b68cea7ad 100755 --- a/test_regress/t/t_flag_ldflags.pl +++ b/test_regress/t/t_flag_ldflags.pl @@ -10,16 +10,14 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -my $m32 = $Self->cfg_with_m32 ? "-m32" : ""; - run(cmd => ["cd $Self->{obj_dir}" - . " && $ENV{CXX} $m32 -c ../../t/t_flag_ldflags_a.cpp" + . " && $ENV{CXX} -c ../../t/t_flag_ldflags_a.cpp" . " && ar -cr t_flag_ldflags_a.a t_flag_ldflags_a.o" . " && ranlib t_flag_ldflags_a.a "], check_finished => 0); run(cmd => ["cd $Self->{obj_dir}" - . " && $ENV{CXX} $m32 -fPIC -c ../../t/t_flag_ldflags_so.cpp" - . " && $ENV{CXX} $m32 -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"], + . " && $ENV{CXX} -fPIC -c ../../t/t_flag_ldflags_so.cpp" + . " && $ENV{CXX} -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"], check_finished => 0); compile( diff --git a/test_regress/t/t_threads_crazy_context.pl b/test_regress/t/t_threads_crazy_context.pl index 6a3f1512e..73ba5c3b8 100755 --- a/test_regress/t/t_threads_crazy_context.pl +++ b/test_regress/t/t_threads_crazy_context.pl @@ -10,10 +10,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt_all => 1); -if ($Self->cfg_with_m32) { - skip("Does not work with -m32 (resource unavailable)"); -} - top_filename("t/t_threads_crazy.v"); compile( From 3adb31f53b7cee563994df1fee331767c4a95f03 Mon Sep 17 00:00:00 2001 From: Paul Wright <68547250+polmacanceart@users.noreply.github.com> Date: Tue, 2 Jan 2024 01:11:46 +0000 Subject: [PATCH 003/116] Fix $time not rounding up (#4790) (#4792) --- include/verilated_funcs.h | 3 +- test_regress/t/t_time.pl | 23 ++++++++++++ test_regress/t/t_time.v | 75 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 1 deletion(-) create mode 100755 test_regress/t/t_time.pl create mode 100644 test_regress/t/t_time.v diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 9ad3dec61..39d97f83d 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -305,7 +305,8 @@ uint64_t VerilatedContext::time() const VL_MT_SAFE { // Time scaled from 1-per-precision into a module's time units ("Unit"-ed, not "United") // Optimized assuming scale is always constant. // Can't use multiply in Q flavor, as might lose precision -#define VL_TIME_UNITED_Q(scale) (VL_TIME_Q() / static_cast(scale)) +#define VL_TIME_ROUND(t, p) (((t) + ((p) / 2)) / (p)) +#define VL_TIME_UNITED_Q(scale) VL_TIME_ROUND(VL_TIME_Q(), static_cast(scale)) #define VL_TIME_UNITED_D(scale) (VL_TIME_D() / static_cast(scale)) // Return time precision as multiplier of time units diff --git a/test_regress/t/t_time.pl b/test_regress/t/t_time.pl new file mode 100755 index 000000000..0db50fc52 --- /dev/null +++ b/test_regress/t/t_time.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 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(linter => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_time.v b/test_regress/t/t_time.v new file mode 100644 index 000000000..024d1dcb0 --- /dev/null +++ b/test_regress/t/t_time.v @@ -0,0 +1,75 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Paul Wright. +// SPDX-License-Identifier: CC0-1.0 + +/* Working through the $time example from IEEE Std 1364-2005 +** Section 17.7.1 +** The example uses a 10ns timeunit with a 1ns timeprecision +** For 16ns $time should return 2 +** For 32ns $time should return 3 +**/ + +module t (); + timeunit 10ns; + timeprecision 1ns; + + longint should_be_2, should_be_3; + real should_be_1p6, should_be_3p2; + + initial + begin : initial_blk1 + should_be_2 = 0; + should_be_3 = 0; + #(16ns); + $display("$time=%d, $realtime=%g", $time(), $realtime()); + should_be_2 = $time(); + should_be_1p6 = $realtime(); + #(16ns); + $display("$time=%d, $realtime=%g", $time(), $realtime()); + should_be_3 = $time(); + should_be_3p2 = $realtime(); + #(16ns); + $finish(1); + end + initial + begin : initial_blk2 + #(100ns); + $display("%%Error: We should not get here"); + $finish(1); + end + + function bit real_chk(input real tvar, input real evar); + begin + real diff; + diff = tvar - evar; + return (diff < 1e-9) && (diff > -1e-9); + end + endfunction + + final + begin : last_blk + if (should_be_2 != 2) + begin + $display("%%Error: should_be_2 = %0d", + should_be_2); + $stop; + end + if (should_be_3 != 3) + begin + $display("%%Error: should_be_3 = %0d", + should_be_3); + $stop; + end + $display("Info: should_be_2 = %0d", should_be_2); + $display("Info: should_be_3 = %0d", should_be_3); + + chk_2 : assert(should_be_2 == 2); + chk_3 : assert(should_be_3 == 3); + chk_1p6 : assert(real_chk(should_be_1p6, 1.6)); + chk_3p2 : assert(real_chk(should_be_3p2, 3.2)); + $write("*-* All Finished *-*\n"); + end + +endmodule From 719954a24aee181d0e3635183650aa2ad67c0675 Mon Sep 17 00:00:00 2001 From: Mariusz Glebocki Date: Tue, 2 Jan 2024 20:51:40 +0100 Subject: [PATCH 004/116] Internals: Make V3Const.cpp parseable by non-compilers (#4796) --- src/V3Const.cpp | 8 ++++++++ src/astgen | 4 ++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index a4a0e7fc7..8353833e2 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -41,6 +41,14 @@ VL_DEFINE_DEBUG_FUNCTIONS; +#define TREE_SKIP_VISIT(...) +#define TREEOP1(...) +#define TREEOPA(...) +#define TREEOP(...) +#define TREEOPS(...) +#define TREEOPC(...) +#define TREEOPV(...) + //###################################################################### // Utilities diff --git a/src/astgen b/src/astgen index 1be8dff1c..cf247a544 100755 --- a/src/astgen +++ b/src/astgen @@ -245,8 +245,8 @@ class Cpt: self.output_func(lambda self: self._output_line()) self.tree_line(func) didln = False - elif not re.match(r'^\s*/[/\*]\s*TREE', line) and re.search( - r'\s+TREE', line): + elif not re.match(r'^\s*(#define|/[/\*])\s*TREE', + line) and re.search(r'\s+TREE', line): self.error("Unknown astgen line: " + line) else: self.print(line) From e430ea13f479af82c8eb5c8d1ba5e0a60e45cebe Mon Sep 17 00:00:00 2001 From: Marlon James Date: Tue, 2 Jan 2024 13:25:14 -0800 Subject: [PATCH 005/116] Fix `vpi_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795) See IEEE 1800-2017 section 38.6 and 38.7. --- include/verilated_vpi.cpp | 18 +++++++++--------- test_regress/t/t_vpi_memory.cpp | 8 ++++---- 2 files changed, 13 insertions(+), 13 deletions(-) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 80cee6346..c450e1420 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -1991,41 +1991,41 @@ PLI_INT32 vpi_get(PLI_INT32 property, vpiHandle object) { } case vpiType: { const VerilatedVpio* const vop = VerilatedVpio::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return vpiUndefined; return vop->type(); } case vpiConstType: { const VerilatedVpio* const vop = VerilatedVpio::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return vpiUndefined; return vop->constType(); } case vpiDirection: { // By forethought, the directions already are vpi enumerated const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return vpiUndefined; return vop->varp()->vldir(); } case vpiScalar: // FALLTHRU case vpiVector: { const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return vpiUndefined; return (property == vpiVector) ^ (vop->varp()->dims() == 0); } case vpiSize: { const VerilatedVpioVarBase* const vop = VerilatedVpioVarBase::castp(object); - if (VL_UNLIKELY(!vop)) return 0; + if (VL_UNLIKELY(!vop)) return vpiUndefined; return vop->size(); } default: - VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", - __func__, VerilatedVpiError::strFromVpiProp(property)); - return 0; + VL_VPI_ERROR_(__FILE__, __LINE__, "%s: Unsupported property %s, nothing will be returned", + __func__, VerilatedVpiError::strFromVpiProp(property)); + return vpiUndefined; } } PLI_INT64 vpi_get64(PLI_INT32 /*property*/, vpiHandle /*object*/) { VL_VPI_UNIMP_(); - return 0; + return vpiUndefined; } PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) { diff --git a/test_regress/t/t_vpi_memory.cpp b/test_regress/t/t_vpi_memory.cpp index 66014e71d..9ef3fbe97 100644 --- a/test_regress/t/t_vpi_memory.cpp +++ b/test_regress/t/t_vpi_memory.cpp @@ -152,10 +152,10 @@ void _mem_check(const char* name, int size, int left, int right, int words) { // 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); - TEST_CHECK_EQ(should_be_0, 0); - should_be_0 = vpi_get(vpiIndex, iter_h); - TEST_CHECK_EQ(should_be_0, 0); + int should_be_undefined = vpi_get(vpiSize, iter_h); + TEST_CHECK_EQ(should_be_undefined, vpiUndefined); + should_be_undefined = vpi_get(vpiIndex, iter_h); + TEST_CHECK_EQ(should_be_undefined, vpiUndefined); vpiHandle should_be_NULL = vpi_handle(vpiLeftRange, iter_h); TEST_CHECK_EQ(should_be_NULL, 0); should_be_NULL = vpi_handle(vpiRightRange, iter_h); From 0195fe9dfd23955ccbf1ce81f170820ced00c8a6 Mon Sep 17 00:00:00 2001 From: Marlon James Date: Tue, 2 Jan 2024 15:52:57 -0800 Subject: [PATCH 006/116] Add `vpiConstType` support to `vpi_get_str()` (#4797) --- include/verilated_vpi.cpp | 32 +++++++++++++++++++++++++++++ test_regress/t/t_vpi_const_type.cpp | 8 ++++++++ 2 files changed, 40 insertions(+) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index c450e1420..dbccd8fc3 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -855,6 +855,7 @@ public: static const char* strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE; static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_PURE; static const char* strFromVpiProp(PLI_INT32 vpiVal) VL_PURE; + static const char* strFromVpiConstType(PLI_INT32 vpiVal) VL_PURE; }; //====================================================================== @@ -1372,6 +1373,23 @@ const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_PURE { if (vpiVal == vpiUndefined) return "vpiUndefined"; return names[(vpiVal <= vpiIsProtected) ? vpiVal : 0]; } +const char* VerilatedVpiError::strFromVpiConstType(PLI_INT32 constType) VL_PURE { + // clang-format off + static const char* const names[] = { + "*undefined*", + "vpiDecConst", + "vpiRealConst", + "vpiBinaryConst", + "vpiOctConst", + "vpiHexConst", + "vpiStringConst", + "vpiIntConst", + "vpiTimeConst", + }; + // clang-format on + if (VL_UNCOVERABLE(constType < 0)) return names[0]; + return names[(constType <= vpiTimeConst) ? constType : 0]; +} #define SELF_CHECK_RESULT_CSTR(got, exp) \ if (0 != std::strcmp((got), (exp))) { \ @@ -1643,6 +1661,15 @@ void VerilatedVpiError::selfTest() VL_MT_UNSAFE_ONE { SELF_CHECK_ENUM_STR(strFromVpiProp, vpiOffset); SELF_CHECK_ENUM_STR(strFromVpiProp, vpiStop); SELF_CHECK_ENUM_STR(strFromVpiProp, vpiIsProtected); + + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiDecConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiRealConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiBinaryConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiOctConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiHexConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiStringConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiIntConst); + SELF_CHECK_ENUM_STR(strFromVpiConstType, vpiTimeConst); } #undef SELF_CHECK_ENUM_STR @@ -2047,6 +2074,11 @@ PLI_BYTE8* vpi_get_str(PLI_INT32 property, vpiHandle object) { case vpiType: { return const_cast(VerilatedVpiError::strFromVpiObjType(vop->type())); } + case vpiConstType: { + const PLI_INT32 constType = vpi_get(vpiConstType, object); + VL_VPI_ERROR_RESET_(); + return const_cast(VerilatedVpiError::strFromVpiConstType(constType)); + } default: VL_VPI_WARNING_(__FILE__, __LINE__, "%s: Unsupported type %s, nothing will be returned", __func__, VerilatedVpiError::strFromVpiProp(property)); diff --git a/test_regress/t/t_vpi_const_type.cpp b/test_regress/t/t_vpi_const_type.cpp index 587d2ac1d..6c4c25339 100644 --- a/test_regress/t/t_vpi_const_type.cpp +++ b/test_regress/t/t_vpi_const_type.cpp @@ -77,22 +77,30 @@ int mon_check() { CHECK_RESULT_NZ(intHandle) PLI_INT32 intConstType = vpi_get(vpiConstType, intHandle); CHECK_RESULT(intConstType, vpiDecConst) + const char* intConstTypeStr = vpi_get_str(vpiConstType, intHandle); + CHECK_RESULT_CSTR(intConstTypeStr, "vpiDecConst") TestVpiHandle realHandle = vpi_handle_by_name((PLI_BYTE8*)"t.realParam", NULL); CHECK_RESULT_NZ(realHandle) PLI_INT32 realConstType = vpi_get(vpiConstType, realHandle); CHECK_RESULT(realConstType, vpiRealConst) + const char* realConstTypeStr = vpi_get_str(vpiConstType, realHandle); + CHECK_RESULT_CSTR(realConstTypeStr, "vpiRealConst") TestVpiHandle strHandle = vpi_handle_by_name((PLI_BYTE8*)"t.strParam", NULL); CHECK_RESULT_NZ(strHandle) PLI_INT32 strConstType = vpi_get(vpiConstType, strHandle); CHECK_RESULT(strConstType, vpiStringConst) + const char* strConstTypeStr = vpi_get_str(vpiConstType, strHandle); + CHECK_RESULT_CSTR(strConstTypeStr, "vpiStringConst") TestVpiHandle sigHandle = vpi_handle_by_name((PLI_BYTE8*)"t.signal", NULL); CHECK_RESULT_NZ(sigHandle) PLI_INT32 sigConstType = vpi_get(vpiConstType, sigHandle); // t.signal is not constant CHECK_RESULT(sigConstType, vpiUndefined) + const char* sigConstTypeStr = vpi_get_str(vpiConstType, sigHandle); + CHECK_RESULT_CSTR(sigConstTypeStr, "*undefined*") TestVpiHandle leftHandle = vpi_handle(vpiLeftRange, sigHandle); CHECK_RESULT_NZ(leftHandle) PLI_INT32 leftConstType = vpi_get(vpiConstType, leftHandle); From 8ea814e4b4ce7416188130647c87dea41401a5b6 Mon Sep 17 00:00:00 2001 From: Marlon James Date: Tue, 2 Jan 2024 15:57:34 -0800 Subject: [PATCH 007/116] Fix VPI parameter iteration (#4798) --- include/verilated_vpi.cpp | 15 ++++++++++++--- test_regress/t/t_vpi_package.cpp | 4 +++- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index dbccd8fc3..03ad2abe9 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -419,10 +419,19 @@ public: } if (m_onlyParams && !m_it->second.isParam()) continue; if (VL_UNLIKELY(m_topscopep)) { - if (const VerilatedVar* topvarp = m_topscopep->varFind(m_it->second.name())) - return ((new VerilatedVpioVar{topvarp, m_topscopep})->castVpiHandle()); + if (const VerilatedVar* topvarp = m_topscopep->varFind(m_it->second.name())) { + if (topvarp->isParam()) { + return ((new VerilatedVpioParam{topvarp, m_topscopep})->castVpiHandle()); + } else { + return ((new VerilatedVpioVar{topvarp, m_topscopep})->castVpiHandle()); + } + } + } + if (m_it->second.isParam()) { + return ((new VerilatedVpioParam{&(m_it->second), m_scopep})->castVpiHandle()); + } else { + return ((new VerilatedVpioVar{&(m_it->second), m_scopep})->castVpiHandle()); } - return ((new VerilatedVpioVar{&(m_it->second), m_scopep})->castVpiHandle()); } } }; diff --git a/test_regress/t/t_vpi_package.cpp b/test_regress/t/t_vpi_package.cpp index b171b3fbe..7d16c2283 100644 --- a/test_regress/t/t_vpi_package.cpp +++ b/test_regress/t/t_vpi_package.cpp @@ -75,7 +75,9 @@ int count_params(TestVpiHandle& handle, int expectedParams) { int params = 0; while (true) { TestVpiHandle handle = vpi_scan(it); - if (handle == NULL) break; + if (!handle) break; + const int vpi_type = vpi_get(vpiType, handle); + CHECK_RESULT(vpi_type, vpiParameter); params++; } it.freed(); From ec01008fe391bf69e4d104224edf00d78c1afc2c Mon Sep 17 00:00:00 2001 From: Pengcheng Xu Date: Wed, 3 Jan 2024 13:11:50 +0100 Subject: [PATCH 008/116] Change zero replication width error to ZEROREPL warning (#4753) (#4762) --- docs/CONTRIBUTORS | 1 + docs/guide/warnings.rst | 43 ++++++++++++++++++++++++++++++ src/V3Error.h | 5 ++-- src/V3Width.cpp | 2 +- test_regress/t/t_math_repl_bad.out | 6 ++--- 5 files changed, 51 insertions(+), 6 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 522941a52..13bb845d0 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -134,6 +134,7 @@ Oleh Maksymenko Patrick Stewart Paul Wright Pawel Sagan +Pengcheng Xu Peter Debacker Peter Horvath Peter Monsson diff --git a/docs/guide/warnings.rst b/docs/guide/warnings.rst index 12e854f35..a09a6203e 100644 --- a/docs/guide/warnings.rst +++ b/docs/guide/warnings.rst @@ -2131,3 +2131,46 @@ List Of Warnings Inactive region. Such processes do get resumed in the same time slot somewhere in the Active region. Issued only if Verilator is run with the :vlopt:`--timing` option. + +.. option:: ZEROREPL + + Warns that zero is used as the replication value in the replication + operator. This is specified as an error by IEEE 1800-2017 11.4.12.1. + + Faulty example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 5 + + module dut + #(parameter int MY_PARAM = 0); + reg [7:0] data; + always @* begin + data = {MY_PARAM{1'b1}}; //<--- WARNING + end + endmodule + + Results in the following error: + + .. code-block:: + + %Error-ZEROREPL: test.v:5:22: Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1) + + Note that in some cases, this warning may be false, when a condition + upstream or downstream of the access means the zero replication will + never execute or be used. + + Repaired example: + + .. code-block:: sv + :linenos: + :emphasize-lines: 2 + + module dut + #(parameter int MY_PARAM = 1); //<--- REPAIRED + reg [7:0] data; + always @* begin + data = {MY_PARAM{1'b1}}; + end + endmodule diff --git a/src/V3Error.h b/src/V3Error.h index 51de65960..0643ff8bf 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -165,6 +165,7 @@ public: WIDTHTRUNC, // Width mismatch- lhs < rhs WIDTHXZEXPAND, // Width mismatch- lhs > rhs xz filled ZERODLY, // #0 delay + ZEROREPL, // Replication width of zero _ENUM_MAX // ***Add new elements below also*** }; @@ -210,7 +211,7 @@ public: "UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNOPTTHREADS", "UNPACKED", "UNSIGNED", "UNUSEDGENVAR", "UNUSEDPARAM", "UNUSEDSIGNAL", "USERERROR", "USERFATAL", "USERINFO", "USERWARN", - "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", + "VARHIDDEN", "WAITCONST", "WIDTH", "WIDTHCONCAT", "WIDTHEXPAND", "WIDTHTRUNC", "WIDTHXZEXPAND", "ZERODLY", "ZEROREPL", " MAX" }; // clang-format on @@ -228,7 +229,7 @@ public: return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED || m_e == ENDLABEL || m_e == ENUMVALUE || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL - || m_e == PROCASSWIRE // Says IEEE + || m_e == PROCASSWIRE || m_e == ZEROREPL // Says IEEE ); } // Warnings to mention manual diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 93ce607c1..bbc9542f7 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -781,7 +781,7 @@ class WidthVisitor final : public VNVisitor { if (!constp) nodep->v3error("Replication value isn't a constant."); if (times == 0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3error("Replication value of 0 is only legal under a concatenation" + nodep->v3warn(ZEROREPL, "Replication value of 0 is only legal under a concatenation" " (IEEE 1800-2017 11.4.12.1)"); times = 1; // Set to 1, so we can continue looking for errors } diff --git a/test_regress/t/t_math_repl_bad.out b/test_regress/t/t_math_repl_bad.out index d39d2f109..380f0ff1b 100644 --- a/test_regress/t/t_math_repl_bad.out +++ b/test_regress/t/t_math_repl_bad.out @@ -1,12 +1,12 @@ -%Error: t/t_math_repl_bad.v:12:14: Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1) - : ... note: In instance 't' +%Error-ZEROREPL: t/t_math_repl_bad.v:12:14: Replication value of 0 is only legal under a concatenation (IEEE 1800-2017 11.4.12.1) + : ... note: In instance 't' 12 | o = {0 {1'b1}}; | ^ + ... For error description see https://verilator.org/warn/ZEROREPL?v=latest %Warning-WIDTHEXPAND: t/t_math_repl_bad.v:12:9: Operator ASSIGN expects 32 bits on the Assign RHS, but Assign RHS's REPLICATE generates 1 bits. : ... note: In instance 't' 12 | o = {0 {1'b1}}; | ^ - ... For warning description see https://verilator.org/warn/WIDTHEXPAND?v=latest ... Use "/* verilator lint_off WIDTHEXPAND */" and lint_on around source to disable this message. %Error: t/t_math_repl_bad.v:13:43: Replication value isn't a constant. : ... note: In instance 't' From 4172c0f29ee2721d16dd114cf9b7d9cb84cac75c Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 3 Jan 2024 12:13:21 +0000 Subject: [PATCH 009/116] Apply 'make format' --- src/V3Error.h | 4 ++-- src/V3Width.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/V3Error.h b/src/V3Error.h index 0643ff8bf..e1032a0dd 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -228,8 +228,8 @@ public: bool pretendError() const VL_MT_SAFE { return (m_e == ASSIGNIN || m_e == BADSTDPRAGMA || m_e == BLKANDNBLK || m_e == BLKLOOPINIT || m_e == CONTASSREG || m_e == ENCAPSULATED || m_e == ENDLABEL || m_e == ENUMVALUE - || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL - || m_e == PROCASSWIRE || m_e == ZEROREPL // Says IEEE + || m_e == IMPURE || m_e == PINNOTFOUND || m_e == PKGNODECL || m_e == PROCASSWIRE + || m_e == ZEROREPL // Says IEEE ); } // Warnings to mention manual diff --git a/src/V3Width.cpp b/src/V3Width.cpp index bbc9542f7..47d572b93 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -781,8 +781,9 @@ class WidthVisitor final : public VNVisitor { if (!constp) nodep->v3error("Replication value isn't a constant."); if (times == 0 && !VN_IS(nodep->backp(), Concat)) { // Concat Visitor will clean it up. - nodep->v3warn(ZEROREPL, "Replication value of 0 is only legal under a concatenation" - " (IEEE 1800-2017 11.4.12.1)"); + nodep->v3warn(ZEROREPL, + "Replication value of 0 is only legal under a concatenation" + " (IEEE 1800-2017 11.4.12.1)"); times = 1; // Set to 1, so we can continue looking for errors } nodep->dtypeSetLogicUnsized((nodep->srcp()->width() * times), From 2be6f038484f1636c1430ebf871eb7c89ca58c19 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 3 Jan 2024 20:51:47 -0500 Subject: [PATCH 010/116] Commentary: runtime debugging --- docs/guide/simulating.rst | 31 ++++++++++++++++++++++++------- 1 file changed, 24 insertions(+), 7 deletions(-) diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index aadf5deab..3890fc75a 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -506,12 +506,29 @@ Runtime Debugging ================= To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a -similar tool. Typically you will want to have debugger symbols inserted by -the compiler, assertions enabled in the C library, and assertions enabled -in the Verilated library. (These options slow down the executable, so do -this only when debugging.) To enable this, Verilate with: +similar tool, e.g.: - -CFLAGS -ggdb -LDFLAGS -ggdb -CFLAGS -DVL_DEBUG=1 -CFLAGS -D_GLIBCXX_DEBUG + .. code-block:: bash -The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options pass arguments -directly to the compiler or linker. + gdb obj_dir/Vmodel + run {Vmodel_command_arguments} + {segmentation faults} + bt + +Typically you will want to have debugger symbols inserted by the compiler, +assertions enabled in the C library, assertions enabled in the Verilated +library, and the sanitizer enabled to look for bad memory or undefined +operations. (These options slow down the executable, so do this only when +debugging.) To enable these, Verilate with: + + .. code-block:: bash + + -CFLAGS -ggdb -LDFLAGS -ggdb + -CFLAGS -DVL_DEBUG=1 + -CFLAGS -D_GLIBCXX_DEBUG + -CFLAGS -fsanitize=address,undefined -LDFLAGS -fsanitize=address,undefined + +The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options used here pass the +following argument into the generated Makefile for use as compiler or +linker options respectively. If you are using your own Makefiles, adapt +appropriately to pass the suggested flags to the compiler and linker. From 1a0c8f15738a23100bdee27705ac2ff22801620f Mon Sep 17 00:00:00 2001 From: Chykon Date: Thu, 4 Jan 2024 18:47:22 +0300 Subject: [PATCH 011/116] Commentary: Add a link to `Create-Binary Execution` to the list of examples (#4802) --- docs/CONTRIBUTORS | 1 + docs/guide/examples.rst | 1 + 2 files changed, 2 insertions(+) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 13bb845d0..b5efe1199 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -22,6 +22,7 @@ Cameron Kirk Chih-Mao Chen Chris Randall Chuxuan Wang +Chykon Conor McCullough Dan Petrisko Daniel Bates diff --git a/docs/guide/examples.rst b/docs/guide/examples.rst index 71b65ae97..c2328b8da 100644 --- a/docs/guide/examples.rst +++ b/docs/guide/examples.rst @@ -9,6 +9,7 @@ Examples This section covers the following examples: +* :ref:`Example Create-Binary Execution` * :ref:`Example C++ Execution` * :ref:`Example SystemC Execution` * :ref:`Examples in the Distribution` From 47b129bf07b9722049cb73f8064c56464d38451b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 Jan 2024 07:14:40 -0500 Subject: [PATCH 012/116] Commentary --- include/verilated.h | 1 + 1 file changed, 1 insertion(+) diff --git a/include/verilated.h b/include/verilated.h index e82b75e80..14aa42e99 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -971,6 +971,7 @@ void VerilatedContext::timeprecision(int value) VL_MT_SAFE { } else if (sc_res == sc_core::sc_time(1, sc_core::SC_FS)) { sc_prec = 15; } + // SC_AS, SC_ZS, SC_YS not supported as no Verilog equivalent; will error below #endif } #if VM_SC From a36a07c2970b8251a1116e3bce158153fb6eac66 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 Jan 2024 18:00:06 -0500 Subject: [PATCH 013/116] Internals: Favor UASSERT over v3fatalSrc. No functional change intended. --- src/V3EmitCFunc.cpp | 2 +- src/V3EmitCFunc.h | 4 ++-- src/V3Error.cpp | 5 ++--- src/V3File.cpp | 2 +- src/V3GraphAcyc.cpp | 2 +- src/V3Life.cpp | 2 +- src/V3Number.cpp | 10 ++++------ src/V3Partition.cpp | 2 +- src/V3PreProc.cpp | 20 +++++--------------- src/V3Split.cpp | 2 +- src/V3SplitAs.cpp | 9 ++++----- src/V3Task.cpp | 9 ++++----- src/V3Trace.cpp | 2 +- src/V3Width.cpp | 27 +++++++++++++-------------- 14 files changed, 41 insertions(+), 57 deletions(-) diff --git a/src/V3EmitCFunc.cpp b/src/V3EmitCFunc.cpp index e4458b478..d0e51630e 100644 --- a/src/V3EmitCFunc.cpp +++ b/src/V3EmitCFunc.cpp @@ -732,7 +732,7 @@ string EmitCFunc::emitVarResetRecurse(const AstVar* varp, const string& varNameP string out; if (varp->valuep()) { const AstConst* const constp = VN_AS(varp->valuep(), Const); - if (!constp) varp->v3fatalSrc("non-const initializer for variable"); + UASSERT_OBJ(constp, varp, "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"; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index a264bbd26..8c75f0462 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -993,14 +993,14 @@ public: } void visit(AstTime* nodep) override { puts("VL_TIME_UNITED_Q("); - if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); + UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); } void visit(AstTimeD* nodep) override { puts("VL_TIME_UNITED_D("); - if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$realtime has no units"); + UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$realtime has no units"); puts(cvtToStr(nodep->timeunit().multiplier() / v3Global.rootp()->timeprecision().multiplier())); puts(")"); diff --git a/src/V3Error.cpp b/src/V3Error.cpp index 908e597f3..c490fd00f 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -256,9 +256,8 @@ void V3Error::init() { describedEachWarn(static_cast(i), false); pretendError(static_cast(i), V3ErrorCode{i}.pretendError()); } - if (VL_UNCOVERABLE(string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} != " MAX")) { - v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged"); - } + UASSERT(std::string{V3ErrorCode{V3ErrorCode::_ENUM_MAX}.ascii()} == " MAX", + "Enum table in V3ErrorCode::EC_ascii() is munged"); } string V3Error::lineStr(const char* filename, int lineno) VL_PURE { diff --git a/src/V3File.cpp b/src/V3File.cpp index 7e490769d..4db49c97a 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -605,7 +605,7 @@ VInFilter::~VInFilter() { } bool VInFilter::readWholefile(const string& filename, VInFilter::StrList& outl) { - if (!m_impp) v3fatalSrc("readWholefile on invalid filter"); + UASSERT(m_impp, "readWholefile on invalid filter"); return m_impp->readWholefile(filename, outl); } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 302b109ae..994bb7bd2 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -65,7 +65,7 @@ private: using OrigEdgeList = std::list; // List of orig edges, see also GraphAcyc's decl V3GraphEdge* origEdgep() const { const OrigEdgeList* const oEListp = static_cast(userp()); - if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this); + UASSERT(oEListp, "No original edge associated with acyc edge " << this); return (oEListp->front()); } diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 48d4f107e..0d057d373 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -206,7 +206,7 @@ public: } void lifeToAbove() { // Any varrefs under a if/else branch affect statements outside and after the if/else - if (!m_aboveLifep) v3fatalSrc("Pushing life when already at the top level"); + UASSERT(m_aboveLifep, "Pushing life when already at the top level"); for (auto& itr : m_map) { AstVarScope* const nodep = itr.first; m_aboveLifep->complexAssignFind(nodep); diff --git a/src/V3Number.cpp b/src/V3Number.cpp index e6263c18e..21d4a1e9d 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -429,7 +429,7 @@ V3Number& V3Number::setLongS(int32_t value) { return *this; } V3Number& V3Number::setDouble(double value) { - if (VL_UNCOVERABLE(width() != 64)) v3fatalSrc("Real operation on wrong sized number"); + UASSERT(width() == 64, "Real operation on wrong sized number"); m_data.setDouble(); union { double d; @@ -920,9 +920,7 @@ uint32_t V3Number::toUInt() const VL_MT_SAFE { } double V3Number::toDouble() const VL_MT_SAFE { - if (VL_UNCOVERABLE(!isDouble() || width() != 64)) { - v3fatalSrc("Real operation on wrong sized/non-real number"); - } + UASSERT(isDouble() && width() == 64, "Real operation on wrong sized/non-real number"); union { double d; uint32_t u[2]; @@ -2395,7 +2393,7 @@ V3Number& V3Number::opRToIRoundS(const V3Number& lhs) { V3Number& V3Number::opRealToBits(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); NUM_ASSERT_DOUBLE_ARGS1(lhs); - if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); + UASSERT(lhs.width() == 64 && width() == 64, "Real operation on wrong sized number"); union { double m_d; uint64_t m_v; @@ -2405,7 +2403,7 @@ V3Number& V3Number::opRealToBits(const V3Number& lhs) { } V3Number& V3Number::opBitsToRealD(const V3Number& lhs) { NUM_ASSERT_OP_ARGS1(lhs); - if (lhs.width() != 64 || width() != 64) v3fatalSrc("Real operation on wrong sized number"); + UASSERT(lhs.width() == 64 && width() == 64, "Real operation on wrong sized number"); union { double m_d; uint64_t m_v; diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index d73b45e46..ac3a7dbfb 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -2777,7 +2777,7 @@ void V3Partition::go(V3Graph* mtasksp) { mtasksp->orderPreRanked(); const int targetParFactor = v3Global.opt.threads(); - if (targetParFactor < 2) v3fatalSrc("We should not reach V3Partition when --threads <= 1"); + UASSERT(targetParFactor >= 2, "Should not reach V3Partition when --threads <= 1"); // Set cpLimit to roughly totalGraphCost / nThreads // diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 26bbba4bd..4a8c103f3 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -1180,9 +1180,7 @@ int V3PreProcImp::getStateToken() { stateChange(ps_DEFARG); goto next_tok; } else { - if (VL_UNCOVERABLE(m_defRefs.empty())) { - v3fatalSrc("Shouldn't be in DEFPAREN w/o active defref"); - } + UASSERT(!m_defRefs.empty(), "Shouldn't be in DEFPAREN w/o active defref"); const VDefineRef* const refp = &(m_defRefs.top()); error(std::string{"Expecting ( to begin argument list for define reference `"} + refp->name() + "\n"); @@ -1191,9 +1189,7 @@ int V3PreProcImp::getStateToken() { } } case ps_DEFARG: { - if (VL_UNCOVERABLE(m_defRefs.empty())) { - v3fatalSrc("Shouldn't be in DEFARG w/o active defref"); - } + UASSERT(!m_defRefs.empty(), "Shouldn't be in DEFARG w/o active defref"); VDefineRef* refp = &(m_defRefs.top()); refp->nextarg(refp->nextarg() + m_lexp->m_defValue); m_lexp->m_defValue = ""; @@ -1218,9 +1214,7 @@ int V3PreProcImp::getStateToken() { statePop(); if (state() == ps_JOIN) { // Handle {left}```FOO(ARG) where `FOO(ARG) might be empty - if (VL_UNCOVERABLE(m_joinStack.empty())) { - v3fatalSrc("`` join stack empty, but in a ``"); - } + UASSERT(!m_joinStack.empty(), "`` join stack empty, but in a ``"); const string lhs = m_joinStack.top(); m_joinStack.pop(); out.insert(0, lhs); @@ -1308,9 +1302,7 @@ int V3PreProcImp::getStateToken() { } case ps_JOIN: { if (tok == VP_SYMBOL || tok == VP_TEXT) { - if (VL_UNCOVERABLE(m_joinStack.empty())) { - v3fatalSrc("`` join stack empty, but in a ``"); - } + UASSERT(!m_joinStack.empty(), "`` join stack empty, but in a ``"); const string lhs = m_joinStack.top(); m_joinStack.pop(); UINFO(5, "`` LHS:" << lhs << endl); @@ -1446,9 +1438,7 @@ int V3PreProcImp::getStateToken() { if (m_defRefs.empty()) { // Just output the substitution if (state() == ps_JOIN) { // Handle {left}```FOO where `FOO might be empty - if (VL_UNCOVERABLE(m_joinStack.empty())) { - v3fatalSrc("`` join stack empty, but in a ``"); - } + UASSERT(!m_joinStack.empty(), "`` join stack empty, but in a ``"); const string lhs = m_joinStack.top(); m_joinStack.pop(); out.insert(0, lhs); diff --git a/src/V3Split.cpp b/src/V3Split.cpp index 75735761b..b2e7e8d22 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -302,7 +302,7 @@ private: } void scoreboardPopStmt() { // UINFO(9, " pop" << endl); - if (m_stmtStackps.empty()) v3fatalSrc("Stack underflow"); + UASSERT(!m_stmtStackps.empty(), "Stack underflow"); m_stmtStackps.pop_back(); } diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index b048692e5..e63f0d8e8 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -162,11 +162,10 @@ class SplitAsVisitor final : public VNVisitor { if (splitVscp) { UINFO(3, "Split " << nodep << endl); UINFO(3, " For " << splitVscp << endl); - if (splitVscp == lastSplitVscp) { - // We did this last time! Something's stuck! - nodep->v3fatalSrc("Infinite loop in isolate_assignments removal for: " - << splitVscp->prettyNameQ()); - } + // If we did this last time! Something's stuck! + UASSERT_OBJ(splitVscp != lastSplitVscp, nodep, + "Infinite loop in isolate_assignments removal for: " + << splitVscp->prettyNameQ()); lastSplitVscp = splitVscp; splitAlways(nodep, splitVscp); ++m_statSplits; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 21c494a6d..021da7f20 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1033,11 +1033,10 @@ class TaskVisitor final : public VNVisitor { if (portp->isDpiOpenArray()) { AstNodeDType* const dtypep = portp->dtypep()->skipRefp(); - if (VN_IS(dtypep, DynArrayDType) || VN_IS(dtypep, QueueDType)) { - v3fatalSrc("Passing dynamic array or queue as actual argument to DPI " - "open array is not yet supported"); - } - + UASSERT_OBJ(!VN_IS(dtypep, DynArrayDType) && !VN_IS(dtypep, QueueDType), + portp, + "Passing dynamic array or queue as actual argument to DPI " + "open array is not yet supported"); // Ideally we'd make a table of variable // characteristics, and reuse it wherever we can // At least put them into the module's CTOR as static? diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 5c64abda0..6be90173a 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -76,7 +76,7 @@ public: ~TraceActivityVertex() override = default; // ACCESSORS AstNode* insertp() const { - if (!m_insertp) v3fatalSrc("Null insertp; probably called on a special always/slow."); + UASSERT(m_insertp, "Null insertp; probably called on a special always/slow"); return m_insertp; } string name() const override { diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 47d572b93..13afe74f3 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -137,7 +137,7 @@ public: bool selfDtm() const { return m_dtypep == nullptr; } AstNodeDType* dtypep() const { // Detect where overrideDType is probably the intended call - if (!m_dtypep) v3fatalSrc("Width dtype request on self-determined or preliminary VUP"); + UASSERT(m_dtypep, "Width dtype request on self-determined or preliminary VUP"); return m_dtypep; } AstNodeDType* dtypeNullp() const { return m_dtypep; } @@ -147,15 +147,15 @@ public: return dtp; } AstNodeDType* dtypeOverridep(AstNodeDType* defaultp) const { - if (m_stage == PRELIM) v3fatalSrc("Parent dtype should be a final-stage action"); + UASSERT(m_stage != PRELIM, "Parent dtype should be a final-stage action"); return m_dtypep ? m_dtypep : defaultp; } int width() const { - if (!m_dtypep) v3fatalSrc("Width request on self-determined or preliminary VUP"); + UASSERT(m_dtypep, "Width request on self-determined or preliminary VUP"); return m_dtypep->width(); } int widthMin() const { - if (!m_dtypep) v3fatalSrc("Width request on self-determined or preliminary VUP"); + UASSERT(m_dtypep, "Width request on self-determined or preliminary VUP"); return m_dtypep->widthMin(); } bool prelim() const { return m_stage & PRELIM; } @@ -366,7 +366,7 @@ class WidthVisitor final : public VNVisitor { if (m_vup->prelim()) { // First stage evaluation iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH); } - if (!nodep->dtypep()->widthSized()) nodep->v3fatalSrc("RToIRoundS should be presized"); + UASSERT_OBJ(nodep->dtypep()->widthSized(), nodep, "RToIRoundS should be presized"); } // Widths: Output integer unsigned, input real @@ -1442,10 +1442,10 @@ class WidthVisitor final : public VNVisitor { // Need to round to time units and precision userIterateAndNext(nodep->lhsp(), WidthVP{SELF, BOTH}.p()); const AstConst* const constp = VN_CAST(nodep->lhsp(), Const); - if (!constp || !constp->isDouble()) nodep->v3fatalSrc("Times should be doubles"); - if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time import no units"); + UASSERT_OBJ(constp && constp->isDouble(), nodep, "Times should be doubles"); + UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, "$time import no units"); double time = constp->num().toDouble(); - if (v3Global.rootp()->timeprecision().isNone()) nodep->v3fatalSrc("Never set precision?"); + UASSERT_OBJ(!v3Global.rootp()->timeprecision().isNone(), nodep, "Never set precision?"); time /= nodep->timeunit().multiplier(); // IEEE claims you should round to time precision here, but no simulator seems to do this AstConst* const newp = new AstConst{nodep->fileline(), AstConst::RealDouble{}, time}; @@ -2730,7 +2730,7 @@ class WidthVisitor final : public VNVisitor { userIterateChildren(nodep, WidthVP{SELF, BOTH}.p()); if (debug() >= 9) nodep->dumpTree("- mbs-ic: "); // Find the fromp dtype - should be a class - if (!nodep->fromp()->dtypep()) nodep->fromp()->v3fatalSrc("Unlinked data type"); + UASSERT_OBJ(nodep->fromp()->dtypep(), nodep->fromp(), "Unlinked data type"); AstNodeDType* const fromDtp = nodep->fromp()->dtypep()->skipRefToEnump(); UINFO(9, " from dt " << fromDtp << endl); if (AstNodeUOrStructDType* const adtypep = VN_CAST(fromDtp, NodeUOrStructDType)) { @@ -5024,9 +5024,8 @@ class WidthVisitor final : public VNVisitor { if (argp) { AstNodeExpr* const nextp = VN_AS(argp->nextp(), NodeExpr); if (argp->isDouble()) ch = '^'; // Convert it - if (nodep->timeunit().isNone()) { - nodep->v3fatalSrc("display %t has no time units"); - } + UASSERT_OBJ(!nodep->timeunit().isNone(), nodep, + "display %t has no time units"); argp = nextp; } break; @@ -5309,8 +5308,8 @@ class WidthVisitor final : public VNVisitor { userIterateAndNext(nodep->exprp(), WidthVP{nodep->modVarp()->dtypep(), PRELIM}.p()); AstNodeDType* modDTypep = nodep->modVarp()->dtypep(); AstNodeDType* conDTypep = nodep->exprp()->dtypep(); - if (!modDTypep) nodep->v3fatalSrc("Unlinked pin data type"); - if (!conDTypep) nodep->v3fatalSrc("Unlinked pin data type"); + UASSERT_OBJ(modDTypep, nodep, "Unlinked pin data type"); + UASSERT_OBJ(conDTypep, nodep, "Unlinked pin data type"); modDTypep = modDTypep->skipRefp(); conDTypep = conDTypep->skipRefp(); AstNodeDType* subDTypep = modDTypep; From 5294140753b05cf9c71b5b6d116130e40f1e6315 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 Jan 2024 18:07:24 -0500 Subject: [PATCH 014/116] Fix delays using wrong timeunits when modules inlined (#4806). --- Changes | 2 +- src/V3AssertPre.cpp | 4 +- src/V3AstNodeOther.h | 5 ++- src/V3LinkParse.cpp | 7 +++ src/V3Timing.cpp | 19 ++++----- test_regress/t/t_timing_timescale.out | 26 ++++++++++++ test_regress/t/t_timing_timescale.pl | 24 +++++++++++ test_regress/t/t_timing_timescale.v | 61 +++++++++++++++++++++++++++ 8 files changed, 135 insertions(+), 13 deletions(-) create mode 100644 test_regress/t/t_timing_timescale.out create mode 100755 test_regress/t/t_timing_timescale.pl create mode 100644 test_regress/t/t_timing_timescale.v diff --git a/Changes b/Changes index 055678d16..414a560c3 100644 --- a/Changes +++ b/Changes @@ -14,7 +14,7 @@ Verilator 5.021 devel **Minor:** * Remove deprecated 32-bit pointer mode (`gcc -m32`). - +* Fix delays using wrong timeunits when modules inlined (#4806). [Paul Wright] Verilator 5.020 2024-01-01 diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 40803b5c4..34104eab2 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -189,7 +189,9 @@ private: m_clockingp->addNextHere(new AstAlwaysObserved{ flp, new AstSenTree{flp, m_clockingp->sensesp()->cloneTree(false)}, forkp}); if (v3Global.opt.timing().isSetTrue()) { - assignp->timingControlp(new AstDelay{flp, skewp->unlinkFrBack(), false}); + AstDelay* const delayp = new AstDelay{flp, skewp->unlinkFrBack(), false}; + delayp->timeunit(m_modp->timeunit()); + assignp->timingControlp(delayp); } else if (v3Global.opt.timing().isSetFalse()) { nodep->v3warn(E_NOTIMING, "Clocking output skew greater than #0 requires --timing"); diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 48839a26e..ee2b52808 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2728,6 +2728,7 @@ class AstDelay final : public AstNodeStmt { // Delay statement // @astgen op1 := lhsp : AstNodeExpr // Delay value // @astgen op2 := stmtsp : List[AstNode] // Statements under delay + VTimescale m_timeunit; // Delay's time unit const bool m_isCycle; // True if it is a cycle delay public: @@ -2739,8 +2740,10 @@ public: ASTGEN_MEMBERS_AstDelay; void dump(std::ostream& str) const override; bool isTimingControl() const override { return true; } - bool isCycleDelay() const { return m_isCycle; } bool same(const AstNode* /*samep*/) const override { return true; } + void timeunit(const VTimescale& flag) { m_timeunit = flag; } + VTimescale timeunit() const { return m_timeunit; } + bool isCycleDelay() const { return m_isCycle; } }; class AstDisable final : public AstNodeStmt { string m_name; // Name of block diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 728539c2a..5d3e36da8 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -536,6 +536,13 @@ class LinkParseVisitor final : public VNVisitor { VL_DO_DANGLING(nodep->deleteTree(), nodep); } + void visit(AstDelay* nodep) override { + cleanFileline(nodep); + UASSERT_OBJ(m_modp, nodep, "Delay not under module"); + nodep->timeunit(m_modp->timeunit()); + iterateChildren(nodep); + } + void visit(AstNodeForeach* nodep) override { // FOREACH(array, loopvars, body) UINFO(9, "FOREACH " << nodep << endl); diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index 3ed545153..b9993687a 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -472,7 +472,6 @@ class TimingControlVisitor final : public VNVisitor { AstScope* m_scopep = nullptr; // Current scope AstActive* m_activep = nullptr; // Current active AstNode* m_procp = nullptr; // NodeProcedure/CFunc/Begin we're under - double m_timescaleFactor = 1.0; // Factor to scale delays by int m_forkCnt = 0; // Number of forks inside a module bool m_underJumpBlock = false; // True if we are inside of a jump-block bool m_underProcedure = false; // True if we are under an always or initial @@ -548,8 +547,10 @@ class TimingControlVisitor final : public VNVisitor { return stmtp == nodep ? nullptr : stmtp; } // Calculate the factor to scale delays by - double calculateTimescaleFactor(VTimescale timeunit) const { - int scalePowerOfTen = timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen(); + double calculateTimescaleFactor(AstNode* nodep, VTimescale timeunit) const { + UASSERT_OBJ(!timeunit.isNone(), nodep, "timenunit must be set"); + const int scalePowerOfTen + = timeunit.powerOfTen() - m_netlistp->timeprecision().powerOfTen(); return std::pow(10.0, scalePowerOfTen); } // Creates the global delay scheduler variable @@ -782,8 +783,6 @@ class TimingControlVisitor final : public VNVisitor { UASSERT(!m_classp, "Module or class under class"); VL_RESTORER(m_classp); m_classp = VN_CAST(nodep, Class); - VL_RESTORER(m_timescaleFactor); - m_timescaleFactor = calculateTimescaleFactor(nodep->timeunit()); VL_RESTORER(m_forkCnt); m_forkCnt = 0; iterateChildren(nodep); @@ -895,20 +894,20 @@ class TimingControlVisitor final : public VNVisitor { "Cycle delays should have been handled in V3AssertPre"); FileLine* const flp = nodep->fileline(); AstNodeExpr* valuep = V3Const::constifyEdit(nodep->lhsp()->unlinkFrBack()); - auto* const constp = VN_CAST(valuep, Const); + AstConst* const constp = VN_CAST(valuep, Const); if (!constp || !constp->isZero()) { // Scale the delay + const double timescaleFactor = calculateTimescaleFactor(nodep, nodep->timeunit()); if (valuep->dtypep()->isDouble()) { valuep = new AstRToIRoundS{ - flp, - new AstMulD{flp, valuep, - new AstConst{flp, AstConst::RealDouble{}, m_timescaleFactor}}}; + flp, new AstMulD{flp, valuep, + new AstConst{flp, AstConst::RealDouble{}, timescaleFactor}}}; valuep->dtypeSetBitSized(64, VSigning::UNSIGNED); } else { valuep->dtypeSetBitSized(64, VSigning::UNSIGNED); valuep = new AstMul{flp, valuep, new AstConst{flp, AstConst::Unsized64{}, - static_cast(m_timescaleFactor)}}; + static_cast(timescaleFactor)}}; } } // Replace self with a 'co_await dlySched.delay()' diff --git a/test_regress/t/t_timing_timescale.out b/test_regress/t/t_timing_timescale.out new file mode 100644 index 000000000..041fa0bc7 --- /dev/null +++ b/test_regress/t/t_timing_timescale.out @@ -0,0 +1,26 @@ +[0] clkb is 1 +[5e-07] clkb is 0 +[1e-06] clkb is 1 +[1.5e-06] clkb is 0 +[1.75e-06] Initial finishing, clkb = 0 +[2e-06] clkb is 1 +[2.5e-06] clkb is 0 +[3e-06] clkb is 1 +[3.5e-06] clkb is 0 +[4e-06] clkb is 1 +[4.5e-06] clkb is 0 +[5e-06] clkb is 1 +[5.5e-06] clkb is 0 +[6e-06] clkb is 1 +[6.5e-06] clkb is 0 +[7e-06] clkb is 1 +[7.5e-06] clkb is 0 +[8e-06] clkb is 1 +[8.5e-06] clkb is 0 +[9e-06] clkb is 1 +[9.5e-06] clkb is 0 +[1e-05] clkb is 1 +[1e-05] Finishing (TOP.t.bot) +*-* All Finished *-* +[10500] final (TOP.t) +[1.05e-05] final (TOP.t.bot) count was 21 diff --git a/test_regress/t/t_timing_timescale.pl b/test_regress/t/t_timing_timescale.pl new file mode 100755 index 000000000..3feb337e3 --- /dev/null +++ b/test_regress/t/t_timing_timescale.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2023 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + verilator_flags2 => ["--exe --main --timing"], + make_main => 0, + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_timing_timescale.v b/test_regress/t/t_timing_timescale.v new file mode 100644 index 000000000..1ec17d076 --- /dev/null +++ b/test_regress/t/t_timing_timescale.v @@ -0,0 +1,61 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Paul Wright. +// SPDX-License-Identifier: CC0-1.0 + +module t; + timeunit 1ns; + timeprecision 1ps; + logic clkb, clk; + + initial begin + clkb = 0; + end + + always @(clk) begin + clkb <= ~clk; + end + + bot bot (.clkb(clkb), .clk(clk)); + + final begin + $display("[%g] final (%m)", $realtime()); + end +endmodule + +module bot (input logic clkb, output logic clk); + timeunit 1s; + timeprecision 1fs; + integer count; + real delay; + + initial begin + count = 0; + delay = 500e-9; + clk = clkb; + #(3.5 * delay) $display("[%g] Initial finishing, clkb = %b", $realtime(), clkb); + end + + always @(clkb) begin + $display("[%g] clkb is %b", $realtime(), clkb); + count++; + #(delay) clk = clkb; + end + + always @(count) begin + if (count > 20) begin + $display("[%g] Finishing (%m)", $realtime()); + if ($realtime() < (delay * 20)) begin + $display("[%g] %%Error: That was too quick!", $realtime()); + end + $write("*-* All Finished *-*\n"); + $finish; + end + end + + final begin + $display("[%g] final (%m) count was %0d", $realtime(), count); + end + +endmodule From acbbb2594a88721caff63214ba5f7ed6f6108f84 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 5 Jan 2024 18:25:39 -0500 Subject: [PATCH 015/116] Tests: Make some tests single-threaded only, for faster regressions --- test_regress/t/t_lint_block_redecl_bad.pl | 2 +- test_regress/t/t_lint_implicit.pl | 2 +- test_regress/t/t_lint_implicit_port.pl | 2 +- test_regress/t/t_var_pins_cc.pl | 2 +- test_regress/t/t_var_pins_sc1.pl | 2 +- test_regress/t/t_var_pins_sc2.pl | 2 +- test_regress/t/t_var_pins_sc32.pl | 2 +- test_regress/t/t_var_pins_sc64.pl | 2 +- test_regress/t/t_var_pins_sc_biguint.pl | 2 +- test_regress/t/t_var_pins_sc_uint.pl | 2 +- test_regress/t/t_var_pins_sc_uint_biguint.pl | 2 +- test_regress/t/t_var_pins_scui.pl | 2 +- test_regress/t/t_var_sc_bv.pl | 2 +- 13 files changed, 13 insertions(+), 13 deletions(-) diff --git a/test_regress/t/t_lint_block_redecl_bad.pl b/test_regress/t/t_lint_block_redecl_bad.pl index dbc9830f6..b5861b2ab 100755 --- a/test_regress/t/t_lint_block_redecl_bad.pl +++ b/test_regress/t/t_lint_block_redecl_bad.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); lint( fails => 1, diff --git a/test_regress/t/t_lint_implicit.pl b/test_regress/t/t_lint_implicit.pl index f6e2fa210..f666ab867 100755 --- a/test_regress/t/t_lint_implicit.pl +++ b/test_regress/t/t_lint_implicit.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); compile( verilator_flags2 => ["-Wno-IMPLICIT"], diff --git a/test_regress/t/t_lint_implicit_port.pl b/test_regress/t/t_lint_implicit_port.pl index f6e2fa210..f666ab867 100755 --- a/test_regress/t/t_lint_implicit_port.pl +++ b/test_regress/t/t_lint_implicit_port.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); compile( verilator_flags2 => ["-Wno-IMPLICIT"], diff --git a/test_regress/t/t_var_pins_cc.pl b/test_regress/t/t_var_pins_cc.pl index b8e67d8a0..e8330324e 100755 --- a/test_regress/t/t_var_pins_cc.pl +++ b/test_regress/t/t_var_pins_cc.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc1.pl b/test_regress/t/t_var_pins_sc1.pl index 0c84b2e84..c7e21f8f3 100755 --- a/test_regress/t/t_var_pins_sc1.pl +++ b/test_regress/t/t_var_pins_sc1.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc2.pl b/test_regress/t/t_var_pins_sc2.pl index 9bc19ebcd..4380d3993 100755 --- a/test_regress/t/t_var_pins_sc2.pl +++ b/test_regress/t/t_var_pins_sc2.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc32.pl b/test_regress/t/t_var_pins_sc32.pl index 491a10919..350d5227c 100755 --- a/test_regress/t/t_var_pins_sc32.pl +++ b/test_regress/t/t_var_pins_sc32.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc64.pl b/test_regress/t/t_var_pins_sc64.pl index 2eebd0958..500f57ae4 100755 --- a/test_regress/t/t_var_pins_sc64.pl +++ b/test_regress/t/t_var_pins_sc64.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc_biguint.pl b/test_regress/t/t_var_pins_sc_biguint.pl index bd1895f16..ad87f7295 100755 --- a/test_regress/t/t_var_pins_sc_biguint.pl +++ b/test_regress/t/t_var_pins_sc_biguint.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc_uint.pl b/test_regress/t/t_var_pins_sc_uint.pl index 6b23397d3..70333a0b5 100755 --- a/test_regress/t/t_var_pins_sc_uint.pl +++ b/test_regress/t/t_var_pins_sc_uint.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_sc_uint_biguint.pl b/test_regress/t/t_var_pins_sc_uint_biguint.pl index 3b0e9729d..480eca2b4 100755 --- a/test_regress/t/t_var_pins_sc_uint_biguint.pl +++ b/test_regress/t/t_var_pins_sc_uint_biguint.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_pins_scui.pl b/test_regress/t/t_var_pins_scui.pl index 34a1424d5..124313eea 100755 --- a/test_regress/t/t_var_pins_scui.pl +++ b/test_regress/t/t_var_pins_scui.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); top_filename("t/t_var_pinsizes.v"); diff --git a/test_regress/t/t_var_sc_bv.pl b/test_regress/t/t_var_sc_bv.pl index 0091e49f0..32ebabeb3 100755 --- a/test_regress/t/t_var_sc_bv.pl +++ b/test_regress/t/t_var_sc_bv.pl @@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(vlt_all => 1); +scenarios(vlt => 1); compile( make_top_shell => 0, From 7507c5f56c67aae1c5018844e0f3e10837af711e Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sat, 6 Jan 2024 19:01:35 +0800 Subject: [PATCH 016/116] Support SystemC 3.0.0 public review version (#4805) (#4807) --- include/verilated_sc_trace.h | 50 +++++++++++++++++++++++++++++------- 1 file changed, 41 insertions(+), 9 deletions(-) diff --git a/include/verilated_sc_trace.h b/include/verilated_sc_trace.h index dd24b0624..8ce5ae7e1 100644 --- a/include/verilated_sc_trace.h +++ b/include/verilated_sc_trace.h @@ -24,8 +24,13 @@ #include "verilated.h" #include "verilated_sc.h" -#if SYSTEMC_VERSION < 20140417 // SystemC's simulation phase callback introduced in 2.3.1 -#define _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK +#if SYSTEMC_VERSION >= 20140417 && SYSTEMC_VERSION < 20231124 +// SystemC's simulation phase callback introduced in 2.3.1, and removed since 3.0.0 (PubRev) +#define _VL_HAVE_SYSTEMC_PHASE_CALLBACK +#endif +#if SYSTEMC_VERSION >= 20231124 +// SystemC's stage callback introduced in 3.0.0 (PubRev) +#define _VL_HAVE_SYSTEMC_STAGE_CALLBACK #endif //============================================================================= @@ -49,6 +54,9 @@ /// instead. class VerilatedScTraceBase VL_NOT_FINAL : private sc_core::sc_object, +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK + private sc_core::sc_stage_callback_if, +#endif private sc_core::sc_trace_file { bool m_enableDeltaCycles = false; bool m_traceFileAdded = false; @@ -56,8 +64,8 @@ class VerilatedScTraceBase VL_NOT_FINAL : private sc_core::sc_object, public: void enableDeltaCycles(bool flag = true) { -#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK using namespace sc_core; +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK // Save old report handler before overriding it const auto oldHandler = sc_report_handler::get_handler(); // Override the old handler to hide 'phase callbacks not enabled' message @@ -70,6 +78,13 @@ public: } // Restore the old handler sc_report_handler::set_handler(oldHandler); +#endif +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK + if (flag) { + sc_register_stage_callback(*this, SC_POST_UPDATE); + } else { + sc_unregister_stage_callback(*this, SC_POST_UPDATE); + } #endif m_enableDeltaCycles = flag; } @@ -81,15 +96,20 @@ protected: registerTraceCallback(); }; ~VerilatedScTraceBase() override { -#if SYSTEMC_VERSION >= 20140417 // remove_trace_file added in 2.3.1 + using namespace sc_core; +#if SYSTEMC_VERSION >= 20140417 && SYSTEMC_VERSION < 20231124 + // remove_trace_file added in 2.3.1 and removed in 3.0.0 // Phase callback is automatically unregistered in ~sc_object(). Only the trace file is // needed to be removed here if (m_traceFileAdded) simcontext()->remove_trace_file(this); +#endif +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK + sc_unregister_stage_callback(*this, SC_PRE_TIMESTEP | SC_POST_UPDATE); #endif }; void registerTraceCallback() { -#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK using namespace sc_core; +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK // Save old report handler before overriding it const auto oldHandler = sc_report_handler::get_handler(); // Override the old handler to hide 'phase callbacks not enabled' message @@ -98,13 +118,18 @@ protected: phase_cb_mask cb_mask = sc_object::register_simulation_phase_callback(SC_BEFORE_TIMESTEP); if (cb_mask == SC_UNITIALIZED) { #endif +#if SYSTEMC_VERSION < 20231124 // add_trace_file removed in 3.0.0 // Phase callback not enabled, use trace file instead simcontext()->add_trace_file(this); m_traceFileAdded = true; -#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK +#endif +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK } // Restore the old handler sc_report_handler::set_handler(oldHandler); +#endif +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK + sc_register_stage_callback(*this, SC_PRE_TIMESTEP); #endif } static std::string getScTimeUnit() { @@ -129,9 +154,13 @@ protected: } // METHODS - for SC kernel -#ifndef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK // Override sc_object. Called if using phase callback void simulation_phase_callback() final { cycle(); } +#endif +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK + // Override sc_stage_callback_if. Called if using stage callback + void stage_callback(const sc_core::sc_stage&) final { cycle(); } #endif // Override sc_trace_file. Called if using trace file void cycle(bool delta_cycle) final { @@ -205,8 +234,11 @@ private: #undef DECL_TRACE_METHOD_B }; -#ifdef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK -#undef _VERILATOR_SYSTEMC_NO_PHASE_CALLBACK +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK +#undef _VL_HAVE_SYSTEMC_PHASE_CALLBACK +#endif +#ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK +#undef _VL_HAVE_SYSTEMC_STAGE_CALLBACK #endif #endif // Guard From 0ca90257a52d756806d8719015de0dea0356d364 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 Jan 2024 16:14:58 -0500 Subject: [PATCH 017/116] Add predicted stack overflow warning (#4799). --- Changes | 1 + include/verilated.cpp | 28 +++++ include/verilated.h | 1 + src/CMakeLists.txt | 4 +- src/Makefile_obj.in | 1 + src/V3EmitCSyms.cpp | 10 ++ src/V3InstrCount.cpp | 10 +- src/V3Options.cpp | 1 + src/V3Options.h | 2 + src/V3StackCount.cpp | 202 ++++++++++++++++++++++++++++++++ src/V3StackCount.h | 38 ++++++ test_regress/t/t_stack_check.pl | 24 ++++ test_regress/t/t_stack_check.v | 14 +++ 13 files changed, 330 insertions(+), 6 deletions(-) create mode 100644 src/V3StackCount.cpp create mode 100644 src/V3StackCount.h create mode 100755 test_regress/t/t_stack_check.pl create mode 100644 test_regress/t/t_stack_check.v diff --git a/Changes b/Changes index 414a560c3..c06d4479f 100644 --- a/Changes +++ b/Changes @@ -13,6 +13,7 @@ Verilator 5.021 devel **Minor:** +* Add predicted stack overflow warning (#4799). * Remove deprecated 32-bit pointer mode (`gcc -m32`). * Fix delays using wrong timeunits when modules inlined (#4806). [Paul Wright] diff --git a/include/verilated.cpp b/include/verilated.cpp index 4631e8644..1a32e2b1d 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -71,6 +71,11 @@ # include # define _VL_HAVE_STACKTRACE #endif +#if defined(__linux) || (defined(__APPLE__) && defined(__MACH__)) +# include +# include +# define _VL_HAVE_GETRLIMIT +#endif #include "verilated_threads.h" // clang-format on @@ -2995,6 +3000,29 @@ void Verilated::scTraceBeforeElaborationError() VL_MT_SAFE { VL_UNREACHABLE; } +void Verilated::stackCheck(QData needSize) VL_MT_UNSAFE { + // Slowpath - Called only when constructing +#ifdef _VL_HAVE_GETRLIMIT + QData haveSize = 0; + rlimit rlim; + if (0 == getrlimit(RLIMIT_STACK, &rlim)) { + haveSize = rlim.rlim_cur; + if (haveSize == RLIM_INFINITY) haveSize = rlim.rlim_max; + if (haveSize == RLIM_INFINITY) haveSize = 0; + } + // VL_PRINTF_MT("-Info: stackCheck(%" PRIu64 ") have %" PRIu64 "\n", needSize, haveSize); + // Check for 1.5x need, but suggest 2x so small model increase won't cause warning + // if the user follows the suggestions + if (VL_UNLIKELY(haveSize && needSize && haveSize < (needSize + needSize / 2))) { + VL_PRINTF_MT("%%Warning: System has stack size %" PRIu64 " kb" + " which may be too small; suggest at least 'ulimit -c %" PRIu64 "'\n", + haveSize / 1024, (needSize * 2) / 1024); + } +#else + if (false && needSize) {} // Unused argument +#endif +} + void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE { #if defined(_WIN32) || defined(__MINGW32__) ::mkdir(dirname); diff --git a/include/verilated.h b/include/verilated.h index 14aa42e99..89181ace1 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -898,6 +898,7 @@ public: static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE; static void scTimePrecisionError(int sc_prec, int vl_prec) VL_ATTR_NORETURN VL_MT_SAFE; static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE; + static void stackCheck(QData needSize) VL_MT_UNSAFE; // Internal: Get and set DPI context static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; } diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61c05a21d..db970c21a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -149,6 +149,7 @@ set(HEADERS V3Split.h V3SplitAs.h V3SplitVar.h + V3StackCount.h V3Stats.h V3StdFuture.h V3String.h @@ -258,8 +259,8 @@ set(COMMON_SOURCES V3LinkDot.cpp V3LinkInc.cpp V3LinkJump.cpp - V3LinkLevel.cpp V3LinkLValue.cpp + V3LinkLevel.cpp V3LinkParse.cpp V3LinkResolve.cpp V3Localize.cpp @@ -289,6 +290,7 @@ set(COMMON_SOURCES V3Split.cpp V3SplitAs.cpp V3SplitVar.cpp + V3StackCount.cpp V3Stats.cpp V3StatsReport.cpp V3String.cpp diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 857ce1c7b..99b284757 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -281,6 +281,7 @@ RAW_OBJS_PCH_ASTNOMT = \ V3Split.o \ V3SplitAs.o \ V3SplitVar.o \ + V3StackCount.o \ V3Subst.o \ V3TSP.o \ V3Table.o \ diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 8ddd82a6e..217645f73 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -20,6 +20,8 @@ #include "V3EmitCBase.h" #include "V3LanguageWords.h" #include "V3PartitionGraph.h" +#include "V3StackCount.h" +#include "V3Stats.h" #include #include @@ -810,6 +812,14 @@ void EmitCSyms::emitSymImp() { } puts("{\n"); + { + puts(" // Check resources\n"); + uint64_t stackSize = V3StackCount::count(v3Global.rootp()); + if (v3Global.opt.debugStackCheck()) stackSize += 1024 * 1024 * 1024; + V3Stats::addStat("Stack size prediction (bytes)", stackSize); + puts(" Verilated::stackCheck(" + cvtToStr(stackSize) + ");\n"); + } + if (v3Global.opt.profPgo()) { puts("// Configure profiling for PGO\n"); if (v3Global.opt.mtasks()) { diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 704df1abc..71a05e976 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -71,7 +71,7 @@ public: : m_startNodep{nodep} , m_assertNoDups{assertNoDups} , m_osp{osp} { - if (nodep) iterateConst(nodep); + iterateConstNull(nodep); } ~InstrCountVisitor() override = default; @@ -208,12 +208,12 @@ private: const uint32_t elseCount = m_instrCount; reset(); - if (ifCount < elseCount) { - m_instrCount = savedCount + elseCount; - if (nodep->thenp()) nodep->thenp()->user2(0); // Don't dump it - } else { + if (ifCount >= elseCount) { m_instrCount = savedCount + ifCount; if (nodep->elsep()) nodep->elsep()->user2(0); // Don't dump it + } else { + m_instrCount = savedCount + elseCount; + if (nodep->thenp()) nodep->thenp()->user2(0); // Don't dump it } } void visit(AstCAwait* nodep) override { diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 7a72a8dc5..340f4c48f 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -1166,6 +1166,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, DECL_OPTION("-debug-protect", OnOff, &m_debugProtect).undocumented(); DECL_OPTION("-debug-self-test", OnOff, &m_debugSelfTest).undocumented(); DECL_OPTION("-debug-sigsegv", CbCall, throwSigsegv).undocumented(); // See also --debug-abort + DECL_OPTION("-debug-stack-check", OnOff, &m_debugStackCheck).undocumented(); DECL_OPTION("-decoration", OnOff, &m_decoration); DECL_OPTION("-dpi-hdr-only", OnOff, &m_dpiHdrOnly); DECL_OPTION("-dump-", CbPartialMatch, [this](const char* optp) { m_dumpLevel[optp] = 3; }); diff --git a/src/V3Options.h b/src/V3Options.h index bed53babe..5db70ffe6 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -243,6 +243,7 @@ private: bool m_debugPartition = false; // main switch: --debug-partition bool m_debugProtect = false; // main switch: --debug-protect bool m_debugSelfTest = false; // main switch: --debug-self-test + bool m_debugStackCheck = false; // main switch: --debug-stack-check bool m_decoration = true; // main switch: --decoration bool m_dpiHdrOnly = false; // main switch: --dpi-hdr-only bool m_exe = false; // main switch: --exe @@ -471,6 +472,7 @@ public: bool debugPartition() const { return m_debugPartition; } bool debugProtect() const VL_MT_SAFE { return m_debugProtect; } bool debugSelfTest() const { return m_debugSelfTest; } + bool debugStackCheck() const { return m_debugStackCheck; } bool decoration() const VL_MT_SAFE { return m_decoration; } bool dpiHdrOnly() const { return m_dpiHdrOnly; } bool dumpDefines() const { return m_dumpLevel.count("defines") && m_dumpLevel.at("defines"); } diff --git a/src/V3StackCount.cpp b/src/V3StackCount.cpp new file mode 100644 index 000000000..f500b8602 --- /dev/null +++ b/src/V3StackCount.cpp @@ -0,0 +1,202 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Estimate stack size to run the AST subtree. +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2024 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 "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT + +#include "V3StackCount.h" + +VL_DEFINE_DEBUG_FUNCTIONS; + +/// Estimate the stack byte size for executing all logic within and below a +/// given AST node. This is very rough, only for warning when stack is too +/// small. + +class StackCountVisitor final : public VNVisitorConst { + // NODE STATE + // AstNode::user2() -> int. Path cost + 1, + const VNUser2InUse m_inuser2; + + // MEMBERS + uint64_t m_stackSize = 0; // Running count of instructions + bool m_tracingCall = false; // Iterating into a CCall to a CFunc + bool m_ignoreRemaining = false; // Ignore remaining statements in the block + bool m_inCFunc = false; // Inside function + + // TYPES + // Little class to cleanly call startVisitBase/endVisitBase + class VisitBase final { + // MEMBERS + uint32_t m_savedCount; + AstNode* const m_nodep; + StackCountVisitor* const m_visitor; + + public: + // CONSTRUCTORS + VisitBase(StackCountVisitor* visitor, AstNode* nodep) + : m_nodep{nodep} + , m_visitor{visitor} { + m_savedCount = m_visitor->startVisitBase(nodep); + } + ~VisitBase() { m_visitor->endVisitBase(m_savedCount, m_nodep); } + + private: + VL_UNCOPYABLE(VisitBase); + }; + +public: + // CONSTRUCTORS + StackCountVisitor(AstNode* nodep) { iterateConstNull(nodep); } + ~StackCountVisitor() override = default; + + // METHODS + uint32_t stackSize() const { return m_stackSize; } + +private: + void reset() { + m_stackSize = 0; + m_ignoreRemaining = false; + } + uint32_t startVisitBase(AstNode* nodep) { + UASSERT_OBJ(!m_ignoreRemaining, nodep, "Should not reach here if ignoring"); + + // Save the count, and add it back in during ~VisitBase This allows + // debug prints to show local cost of each subtree, so we can see a + // hierarchical view of the cost when in debug mode. + const uint32_t savedCount = m_stackSize; + m_stackSize = 0; + return savedCount; + } + void endVisitBase(uint32_t savedCount, AstNode* nodep) { + UINFO(8, "cost " << std::setw(6) << std::left << m_stackSize << " " << nodep << endl); + if (!m_ignoreRemaining) m_stackSize += savedCount; + } + + // VISITORS + void visit(AstNodeIf* nodep) override { + if (m_ignoreRemaining) return; + const VisitBase vb{this, nodep}; + iterateAndNextConstNull(nodep->condp()); + const uint32_t savedCount = m_stackSize; + + UINFO(8, "thensp:\n"); + reset(); + iterateAndNextConstNull(nodep->thensp()); + uint32_t ifCount = m_stackSize; + if (nodep->branchPred().unlikely()) ifCount = 0; + + UINFO(8, "elsesp:\n"); + reset(); + iterateAndNextConstNull(nodep->elsesp()); + uint32_t elseCount = m_stackSize; + if (nodep->branchPred().likely()) elseCount = 0; + + reset(); + if (ifCount >= elseCount) { + m_stackSize = savedCount + ifCount; + if (nodep->elsesp()) nodep->elsesp()->user2(0); // Don't dump it + } else { + m_stackSize = savedCount + elseCount; + if (nodep->thensp()) nodep->thensp()->user2(0); // Don't dump it + } + } + void visit(AstNodeCond* nodep) override { + if (m_ignoreRemaining) return; + // Just like if/else above, the ternary operator only evaluates + // one of the two expressions, so only count the max. + const VisitBase vb{this, nodep}; + iterateAndNextConstNull(nodep->condp()); + const uint32_t savedCount = m_stackSize; + + UINFO(8, "?\n"); + reset(); + iterateAndNextConstNull(nodep->thenp()); + const uint32_t ifCount = m_stackSize; + + UINFO(8, ":\n"); + reset(); + iterateAndNextConstNull(nodep->elsep()); + const uint32_t elseCount = m_stackSize; + + reset(); + if (ifCount >= elseCount) { + m_stackSize = savedCount + ifCount; + if (nodep->elsep()) nodep->elsep()->user2(0); // Don't dump it + } else { + m_stackSize = savedCount + elseCount; + if (nodep->thenp()) nodep->thenp()->user2(0); // Don't dump it + } + } + void visit(AstFork* nodep) override { + if (m_ignoreRemaining) return; + const VisitBase vb{this, nodep}; + uint32_t totalCount = m_stackSize; + VL_RESTORER(m_ignoreRemaining); + // Sum counts in each statement + for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) { + reset(); + iterateConst(stmtp); + totalCount += m_stackSize; + } + m_stackSize = totalCount; + } + void visit(AstNodeCCall* nodep) override { + if (m_ignoreRemaining) return; + const VisitBase vb{this, nodep}; + iterateChildrenConst(nodep); + m_tracingCall = true; + iterateConst(nodep->funcp()); + UASSERT_OBJ(!m_tracingCall, nodep, "visit(AstCFunc) should have cleared m_tracingCall."); + } + void visit(AstCFunc* nodep) override { + // Don't count a CFunc other than by tracing a call or counting it + // from the root + if (!m_tracingCall && !nodep->entryPoint()) return; + m_tracingCall = false; + if (nodep->recursive()) return; + if (!nodep->user2()) { // Short circuit + VL_RESTORER(m_ignoreRemaining); + VL_RESTORER(m_stackSize); + VL_RESTORER(m_inCFunc); + m_tracingCall = false; + m_stackSize = 0; + m_inCFunc = true; + const VisitBase vb{this, nodep}; + iterateChildrenConst(nodep); + nodep->user2(m_stackSize + 1); + } + m_stackSize += nodep->user2() - 1; + m_tracingCall = false; + } + void visit(AstVar* nodep) override { + if (!m_inCFunc) return; + m_stackSize += nodep->isRef() ? sizeof(void*) : nodep->dtypep()->widthTotalBytes(); + iterateChildrenConst(nodep); + } + + void visit(AstNodeExpr* nodep) override {} // Short-circuit + void visit(AstNode* nodep) override { + if (m_ignoreRemaining) return; + const VisitBase vb{this, nodep}; + iterateChildrenConst(nodep); + } + + VL_UNCOPYABLE(StackCountVisitor); +}; + +uint64_t V3StackCount::count(AstNode* nodep) { + const StackCountVisitor visitor{nodep}; + return visitor.stackSize(); +} diff --git a/src/V3StackCount.h b/src/V3StackCount.h new file mode 100644 index 000000000..3a8e15d50 --- /dev/null +++ b/src/V3StackCount.h @@ -0,0 +1,38 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// DESCRIPTION: Verilator: Estimate stackuction count to run the logic +// we would generate for any given AST subtree. +// +// Code available from: https://verilator.org +// +//************************************************************************* +// +// Copyright 2003-2024 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_V3STACKCOUNT_H_ +#define VERILATOR_V3STACKCOUNT_H_ + +#include "config_build.h" +#include "verilatedos.h" + +#include "V3ThreadSafety.h" + +class AstNode; + +class V3StackCount final { +public: + // Return the estimate count of bytes needed in stack we'd incur while + // running code in and under nodep. + // + // This is a rough estimate; we don't know what path we'll take through + // conditionals in nodep, so we assume we take the longest path. + static uint64_t count(AstNode* nodep) VL_MT_DISABLED; +}; + +#endif // guard diff --git a/test_regress/t/t_stack_check.pl b/test_regress/t/t_stack_check.pl new file mode 100755 index 000000000..8c196698f --- /dev/null +++ b/test_regress/t/t_stack_check.pl @@ -0,0 +1,24 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003-2024 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 => ['--binary --debug-stack-check'], + verilator_make_cmake => 0, + verilator_make_gmake => 0, + make_main => 0, + ); + +execute(); + +file_grep($Self->{run_log_filename}, qr/.*%Warning: System has stack size/); +ok(1); +1; diff --git a/test_regress/t/t_stack_check.v b/test_regress/t/t_stack_check.v new file mode 100644 index 000000000..e95f4535f --- /dev/null +++ b/test_regress/t/t_stack_check.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, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule From 68e4eeb53e61ad3cbc7b00bb1ca70004e64c042b Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 Jan 2024 16:16:14 -0500 Subject: [PATCH 018/116] Add predicted stack overflow warning (#4799). --- include/verilated.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index 1a32e2b1d..c6c5c7321 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -3015,7 +3015,7 @@ void Verilated::stackCheck(QData needSize) VL_MT_UNSAFE { // if the user follows the suggestions if (VL_UNLIKELY(haveSize && needSize && haveSize < (needSize + needSize / 2))) { VL_PRINTF_MT("%%Warning: System has stack size %" PRIu64 " kb" - " which may be too small; suggest at least 'ulimit -c %" PRIu64 "'\n", + " which may be too small; suggest 'ulimit -c %" PRIu64 "' or larger\n", haveSize / 1024, (needSize * 2) / 1024); } #else From 69043549d6c4e7db30effcc9896ed650d61c9c81 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 Jan 2024 17:26:07 -0500 Subject: [PATCH 019/116] Fix const anon union (#4800) --- include/verilated_trace.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/include/verilated_trace.h b/include/verilated_trace.h index b4b053b42..cdf42adf1 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -209,11 +209,11 @@ private: // (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the // assignment operator on inserting into collections, so they don't work // with const fields... - const union { // The callback - initCb_t m_initCb; - dumpCb_t m_dumpCb; - dumpOffloadCb_t m_dumpOffloadCb; - cleanupCb_t m_cleanupCb; + union { // The callback + const initCb_t m_initCb; + const dumpCb_t m_dumpCb; + const dumpOffloadCb_t m_dumpOffloadCb; + const cleanupCb_t m_cleanupCb; }; const uint32_t m_fidx; // The index of the tracing function void* const m_userp; // The user pointer to pass to the callback (the symbol table) From eec41fd039b809ac67fe4b0a872d03f1b8490773 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 6 Jan 2024 18:49:19 -0500 Subject: [PATCH 020/116] Fix lint_off disables on preprocessor warnings (#4703). --- Changes | 1 + src/V3PreLex.h | 4 ++ src/V3PreLex.l | 51 +++++++++++++++++++---- test_regress/t/t_pp_dupdef_pragma_bad.out | 13 ++++++ test_regress/t/t_pp_dupdef_pragma_bad.pl | 19 +++++++++ test_regress/t/t_pp_dupdef_pragma_bad.v | 32 ++++++++++++++ 6 files changed, 111 insertions(+), 9 deletions(-) create mode 100644 test_regress/t/t_pp_dupdef_pragma_bad.out create mode 100755 test_regress/t/t_pp_dupdef_pragma_bad.pl create mode 100644 test_regress/t/t_pp_dupdef_pragma_bad.v diff --git a/Changes b/Changes index c06d4479f..e5f0e02b2 100644 --- a/Changes +++ b/Changes @@ -16,6 +16,7 @@ Verilator 5.021 devel * Add predicted stack overflow warning (#4799). * Remove deprecated 32-bit pointer mode (`gcc -m32`). * Fix delays using wrong timeunits when modules inlined (#4806). [Paul Wright] +* Fix lint_off disables on preprocessor warnings (#4703). [Srinivasan Venkataramanan] Verilator 5.020 2024-01-01 diff --git a/src/V3PreLex.h b/src/V3PreLex.h index 95ae573f0..64e49ffcc 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -162,6 +162,7 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp int m_streamDepth = 0; // Depth of stream processing YY_BUFFER_STATE m_bufferState; // Flex state FileLine* m_tokFilelinep; // Starting position of current token + std::deque m_lexLintState; // Current lint state for save/restore // State to lexer static V3PreLex* s_currentLexp; ///< Current lexing point @@ -209,6 +210,9 @@ public: // Used only by V3PreLex.cpp and V3PreProc.cpp } } void warnBackslashSpace(); + void verilatorCmtLint(const char* textp, bool warnOff); + void verilatorCmtLintRestore(); + void verilatorCmtLintSave(); // Called by V3PreProc.cpp to inform lexer void pushStateDefArg(int level); void pushStateDefForm(); diff --git a/src/V3PreLex.l b/src/V3PreLex.l index e8d882da4..429d1c3cc 100644 --- a/src/V3PreLex.l +++ b/src/V3PreLex.l @@ -66,7 +66,6 @@ static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t, l) %} %x ARGMODE -%x CMTBEGM %x CMTMODE %x CMTONEM %x DEFCMT @@ -420,6 +419,16 @@ bom [\357\273\277] [^\/\*\n\r\\(,){}\[\]\"`]+ | . { FL_FWDC; appendDefValue(yytext, yyleng); FL_BRK; } + /* Pragma comments. */ +"//"{ws}*"verilator lint_off"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, true); return VP_COMMENT; } +"//"{ws}*"verilator lint_on"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, false); return VP_COMMENT; } +"//"{ws}*"verilator lint_restore"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLintRestore(); return VP_COMMENT; } +"//"{ws}*"verilator lint_save"[^\n\r]* { FL_FWDC; LEXP->verilatorCmtLintSave(); return VP_COMMENT; } +"/*"{ws}*"verilator lint_off"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, true); return VP_COMMENT; } +"/*"{ws}*"verilator lint_on"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLint(yytext + 2, false); return VP_COMMENT; } +"/*"{ws}*"verilator lint_restore"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLintRestore(); return VP_COMMENT; } +"/*"{ws}*"verilator lint_save"[^*]*"*/" { FL_FWDC; LEXP->verilatorCmtLintSave(); return VP_COMMENT; } + /* One line comments. */ "//"{ws}*{crnl} { FL_FWDC; linenoInc(); yytext=(char*)"\n"; yyleng=1; return VP_WHITE; } "//" { yy_push_state(CMTONEM); yymore(); } @@ -427,16 +436,13 @@ bom [\357\273\277] /* C-style comments. */ /**** See also DEFCMT */ - /* We distinguish between the start of a comment, and later, to look for prefix comments (deprecated) */ "/*" { yy_push_state(CMTMODE); yymore(); } -{ws}+ { yymore(); } -"*/" { FL_FWDC; yy_pop_state(); return VP_COMMENT; } -{crnl} { linenoInc(); yymore(); } -<> { FL_FWDC; yyerrorf("EOF in '/* ... */' block comment\n"); +"*/" { FL_FWDC; yy_pop_state(); return VP_COMMENT; } +{crnl} { linenoInc(); yymore(); } +<> { FL_FWDC; yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; return VP_EOF_ERROR; } -{word} { yymore(); } -. { yymore(); BEGIN CMTMODE; } /* beginning in comment */ -. { yymore(); } +{word} { yymore(); } +. { yymore(); } /* Define calls */ /* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */ @@ -735,6 +741,33 @@ void V3PreLex::unused() { } // LCOV_EXCL_STOP } +void V3PreLex::verilatorCmtLintSave() { + m_lexLintState.push_back(*curFilelinep()); +} +void V3PreLex::verilatorCmtLintRestore() { + // No error here on restore without save - the verilog.y parse will report as appropriate + if (m_lexLintState.empty()) return; + curFilelinep()->warnStateFrom(m_lexLintState.back()); + m_lexLintState.pop_back(); +} +void V3PreLex::verilatorCmtLint(const char* textp, bool warnOff) { + const char* sp = textp; + while (*sp && std::isspace(*sp)) ++sp; + while (*sp && !std::isspace(*sp)) ++sp; // "verilator" + while (*sp && std::isspace(*sp)) ++sp; + while (*sp && !std::isspace(*sp)) ++sp; // "lint_on/lint_off" + while (*sp && std::isspace(*sp)) ++sp; + string msg = sp; + for (auto pos = msg.begin(); pos != msg.end(); ++pos) { + if (std::isspace(*pos) || *pos == '*') { + msg.erase(pos, msg.end()); + break; + } + } + // No warnings on bad warning codes - the verilog.y parse will report as appropriate + curFilelinep()->warnOff(msg, warnOff); +} + /*################################################################### * Local Variables: * mode: C++ diff --git a/test_regress/t/t_pp_dupdef_pragma_bad.out b/test_regress/t/t_pp_dupdef_pragma_bad.out new file mode 100644 index 000000000..f9df6cc95 --- /dev/null +++ b/test_regress/t/t_pp_dupdef_pragma_bad.out @@ -0,0 +1,13 @@ +%Warning-REDEFMACRO: t/t_pp_dupdef_pragma_bad.v:11:19: Redefining existing define: 'DUP', with different value: 'b_bad' + t/t_pp_dupdef_pragma_bad.v:11:19: ... Location of previous definition, with value: 'a' + ... For warning description see https://verilator.org/warn/REDEFMACRO?v=latest + ... Use "/* verilator lint_off REDEFMACRO */" and lint_on around source to disable this message. +%Warning-REDEFMACRO: t/t_pp_dupdef_pragma_bad.v:16:19: Redefining existing define: 'DUP', with different value: 'd_bad' + t/t_pp_dupdef_pragma_bad.v:16:19: ... Location of previous definition, with value: 'c_nowarn' +%Warning-REDEFMACRO: t/t_pp_dupdef_pragma_bad.v:21:19: Redefining existing define: 'DUP', with different value: 'f_bad' + t/t_pp_dupdef_pragma_bad.v:21:19: ... Location of previous definition, with value: 'e_nowarn' +%Warning-REDEFMACRO: t/t_pp_dupdef_pragma_bad.v:26:19: Redefining existing define: 'DUP', with different value: 'k_bad' + t/t_pp_dupdef_pragma_bad.v:26:19: ... Location of previous definition, with value: 'j_nowarn' +%Warning-REDEFMACRO: t/t_pp_dupdef_pragma_bad.v:31:19: Redefining existing define: 'DUP', with different value: 'm_bad' + t/t_pp_dupdef_pragma_bad.v:31:19: ... Location of previous definition, with value: 'l_nowarn' +%Error: Exiting due to diff --git a/test_regress/t/t_pp_dupdef_pragma_bad.pl b/test_regress/t/t_pp_dupdef_pragma_bad.pl new file mode 100755 index 000000000..b5861b2ab --- /dev/null +++ b/test_regress/t/t_pp_dupdef_pragma_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 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); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_pp_dupdef_pragma_bad.v b/test_regress/t/t_pp_dupdef_pragma_bad.v new file mode 100644 index 000000000..3541805eb --- /dev/null +++ b/test_regress/t/t_pp_dupdef_pragma_bad.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, 2008 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; + +`define DUP a +`define DUP b_bad + +// verilator lint_off REDEFMACRO +`define DUP c_nowarn +// verilator lint_on REDEFMACRO +`define DUP d_bad +// verilator lint_save +// verilator lint_off REDEFMACRO +`define DUP e_nowarn +// verilator lint_restore +`define DUP f_bad + +/* verilator lint_off REDEFMACRO */ +`define DUP j_nowarn +/* verilator lint_on REDEFMACRO */ +`define DUP k_bad +/* verilator lint_save */ +/* verilator lint_off REDEFMACRO */ +`define DUP l_nowarn +/* verilator lint_restore */ +`define DUP m_bad + +endmodule From 55d1b87b347938673ef48c4c8fc9d6b8ecd96421 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Sun, 7 Jan 2024 23:59:56 +0800 Subject: [PATCH 021/116] Support parsing anonymous primitive instantiations (#4809) --- src/V3LinkParse.cpp | 16 ++++++++++++++++ src/verilog.y | 6 ++---- test_regress/t/t_inst_noname_bad.out | 7 +++++++ test_regress/t/t_inst_noname_bad.pl | 19 +++++++++++++++++++ test_regress/t/t_inst_noname_bad.v | 13 +++++++++++++ test_regress/t/t_preproc_inc_bad.out | 2 +- test_regress/t/t_udp_noname.out | 4 ---- test_regress/t/t_udp_noname.pl | 8 +++----- test_regress/t/t_udp_noname.v | 13 ++++++++----- test_regress/t/t_vams_kwd_bad.out | 2 +- 10 files changed, 70 insertions(+), 20 deletions(-) create mode 100644 test_regress/t/t_inst_noname_bad.out create mode 100755 test_regress/t/t_inst_noname_bad.pl create mode 100644 test_regress/t/t_inst_noname_bad.v delete mode 100644 test_regress/t/t_udp_noname.out diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 5d3e36da8..7980a7336 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -56,6 +56,7 @@ class LinkParseVisitor final : public VNVisitor { AstNodeDType* m_dtypep = nullptr; // Current data type AstNodeExpr* m_defaultInSkewp = nullptr; // Current default input skew AstNodeExpr* m_defaultOutSkewp = nullptr; // Current default output skew + int m_anonUdpId = 0; // Counter for anonymous UDP instances int m_genblkAbove = 0; // Begin block number of if/case/for above int m_genblkNum = 0; // Begin block number, 0=none seen int m_beginDepth = 0; // How many begin blocks above current node within current AstNodeModule @@ -621,6 +622,7 @@ class LinkParseVisitor final : public VNVisitor { V3Config::applyModule(nodep); VL_RESTORER(m_modp); + VL_RESTORER(m_anonUdpId); VL_RESTORER(m_genblkAbove); VL_RESTORER(m_genblkNum); VL_RESTORER(m_beginDepth); @@ -631,6 +633,7 @@ class LinkParseVisitor final : public VNVisitor { // Classes inherit from upper package if (m_modp && nodep->timeunit().isNone()) nodep->timeunit(m_modp->timeunit()); m_modp = nodep; + m_anonUdpId = 0; m_genblkAbove = 0; m_genblkNum = 0; m_beginDepth = 0; @@ -700,6 +703,19 @@ class LinkParseVisitor final : public VNVisitor { iterateChildren(nodep); } } + void visit(AstCell* nodep) override { + if (nodep->origName().empty()) { + if (!VN_IS(nodep->modp(), Primitive)) { // Module/Program/Iface + nodep->modNameFileline()->v3error("Instance of " << nodep->modp()->verilogKwd() + << " must be named"); + } + // UDPs can have empty instance names. Assigning unique names for them to prevent any + // conflicts + const string newName = "$unnamedudp" + cvtToStr(++m_anonUdpId); + nodep->name(newName); + nodep->origName(newName); + } + } void visit(AstGenCase* nodep) override { ++m_genblkNum; cleanFileline(nodep); diff --git a/src/verilog.y b/src/verilog.y index b83b953bc..ad0b9bc61 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3203,10 +3203,8 @@ instnameParen: { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, $4, $2, true); } | id instRangeListE { $$ = GRAMMARP->createCellOrIfaceRef($1, *$1, nullptr, $2, false); } - //UNSUP instRangeListE '(' cellpinListE ')' { UNSUP } // UDP - // // Adding above and switching to the Verilog-Perl syntax - // // causes a shift conflict due to use of idClassSel inside exprScope. - // // It also breaks allowing "id foo;" instantiation syntax. + | '(' cellpinListE ')' // When UDP has empty name, unpacked dimensions must not be used + { $$ = GRAMMARP->createCellOrIfaceRef($1, "", $2, nullptr, true); } ; instRangeListE: diff --git a/test_regress/t/t_inst_noname_bad.out b/test_regress/t/t_inst_noname_bad.out new file mode 100644 index 000000000..8f555c3aa --- /dev/null +++ b/test_regress/t/t_inst_noname_bad.out @@ -0,0 +1,7 @@ +%Error: t/t_inst_noname_bad.v:8:5: Instance of module must be named + 8 | m (); + | ^ +%Error: t/t_inst_noname_bad.v:9:5: Instance of module must be named + 9 | m (); + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_inst_noname_bad.pl b/test_regress/t/t_inst_noname_bad.pl new file mode 100755 index 000000000..a60503a1f --- /dev/null +++ b/test_regress/t/t_inst_noname_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_inst_noname_bad.v b/test_regress/t/t_inst_noname_bad.v new file mode 100644 index 000000000..ca179b788 --- /dev/null +++ b/test_regress/t/t_inst_noname_bad.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2023 by Anthony Donlon. +// SPDX-License-Identifier: CC0-1.0 + +module t; + m (); + m (); +endmodule + +module m; +endmodule diff --git a/test_regress/t/t_preproc_inc_bad.out b/test_regress/t/t_preproc_inc_bad.out index 006f0ec09..2f46dacbd 100644 --- a/test_regress/t/t_preproc_inc_bad.out +++ b/test_regress/t/t_preproc_inc_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER or randomize +%Error: t/t_preproc_inc_inc_bad.vh:11:1: syntax error, unexpected endmodule, expecting IDENTIFIER or '(' or randomize 11 | endmodule | ^~~~~~~~~ t/t_preproc_inc_bad.v:10:1: ... note: In file included from 't_preproc_inc_bad.v' diff --git a/test_regress/t/t_udp_noname.out b/test_regress/t/t_udp_noname.out deleted file mode 100644 index 14eb3efdb..000000000 --- a/test_regress/t/t_udp_noname.out +++ /dev/null @@ -1,4 +0,0 @@ -%Error: t/t_udp_noname.v:15:8: syntax error, unexpected '(', expecting IDENTIFIER or randomize - 15 | udp (o, a); - | ^ -%Error: Exiting due to diff --git a/test_regress/t/t_udp_noname.pl b/test_regress/t/t_udp_noname.pl index b4e56a7d2..b46d46042 100755 --- a/test_regress/t/t_udp_noname.pl +++ b/test_regress/t/t_udp_noname.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - expect_filename => $Self->{golden_filename}, - fails => $Self->{vlt_all}, # Verilator unsupported, bug468" ); -#execute( -# check_finished => 1, -# ); +execute( + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_udp_noname.v b/test_regress/t/t_udp_noname.v index 1ce45f043..862a57e86 100644 --- a/test_regress/t/t_udp_noname.v +++ b/test_regress/t/t_udp_noname.v @@ -10,20 +10,23 @@ module t (/*AUTOARG*/ ); input clk; - reg a; - wire o; - udp (o, a); + reg a1; + wire a2 = ~a1; + wire o1, o2; + udp (o1, a1); + udp (o2, a2); integer cyc; initial cyc = 0; // Test loop always @ (posedge clk) begin cyc <= cyc + 1; - a <= cyc[0]; + a1 <= cyc[0]; if (cyc==0) begin end else if (cyc<90) begin - if (a != !cyc[0]) $stop; + if (o1 != cyc[0]) $stop; + if (o2 != !cyc[0]) $stop; end else if (cyc==99) begin $write("*-* All Finished *-*\n"); diff --git a/test_regress/t/t_vams_kwd_bad.out b/test_regress/t/t_vams_kwd_bad.out index 0d6fac32e..9e3a97617 100644 --- a/test_regress/t/t_vams_kwd_bad.out +++ b/test_regress/t/t_vams_kwd_bad.out @@ -2,7 +2,7 @@ 12 | int above; | ^~~~~ ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest -%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting IDENTIFIER or randomize +%Error: t/t_vams_kwd_bad.v:12:13: syntax error, unexpected ';', expecting IDENTIFIER or '(' or randomize 12 | int above; | ^ %Error-UNSUPPORTED: t/t_vams_kwd_bad.v:13:8: Unsupported: AMS reserved word not implemented: 'abs' From 19cb366e5d1539f06c248767ff905d3f497711f3 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 8 Jan 2024 07:35:34 -0500 Subject: [PATCH 022/116] Update ifdef (#4805) (#4807). No functional change. --- include/verilated_sc_trace.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_sc_trace.h b/include/verilated_sc_trace.h index 8ce5ae7e1..a5d775ee4 100644 --- a/include/verilated_sc_trace.h +++ b/include/verilated_sc_trace.h @@ -97,7 +97,7 @@ protected: }; ~VerilatedScTraceBase() override { using namespace sc_core; -#if SYSTEMC_VERSION >= 20140417 && SYSTEMC_VERSION < 20231124 +#ifdef _VL_HAVE_SYSTEMC_PHASE_CALLBACK // remove_trace_file added in 2.3.1 and removed in 3.0.0 // Phase callback is automatically unregistered in ~sc_object(). Only the trace file is // needed to be removed here From 5f52c066e5a1f8b78c81193d37607a01d0947f19 Mon Sep 17 00:00:00 2001 From: Szymon Gizler <151655464+sgizler@users.noreply.github.com> Date: Tue, 9 Jan 2024 16:35:13 +0100 Subject: [PATCH 023/116] Internals: Add serializeOnly() and dumpTreeEitherLevel() (#4815) (#4715). No functional change intended. --- docs/CONTRIBUTORS | 1 + src/V3Active.cpp | 2 +- src/V3ActiveTop.cpp | 2 +- src/V3Assert.cpp | 2 +- src/V3AssertPre.cpp | 2 +- src/V3Begin.cpp | 2 +- src/V3CCtors.cpp | 2 +- src/V3CUse.cpp | 2 +- src/V3Case.cpp | 2 +- src/V3Cast.cpp | 2 +- src/V3Class.cpp | 2 +- src/V3Clean.cpp | 2 +- src/V3Clock.cpp | 2 +- src/V3Combine.cpp | 2 +- src/V3Common.cpp | 2 +- src/V3Const.cpp | 8 +++--- src/V3Coverage.cpp | 2 +- src/V3CoverageJoin.cpp | 2 +- src/V3Dead.cpp | 10 +++---- src/V3Delayed.cpp | 2 +- src/V3Depth.cpp | 2 +- src/V3DepthBlock.cpp | 2 +- src/V3Descope.cpp | 2 +- src/V3DfgOptimizer.cpp | 4 +-- src/V3Error.h | 1 + src/V3Expand.cpp | 2 +- src/V3Force.cpp | 2 +- src/V3Fork.cpp | 4 +-- src/V3Gate.cpp | 2 +- src/V3Inline.cpp | 2 +- src/V3Inst.cpp | 4 +-- src/V3Interface.cpp | 2 +- src/V3Life.cpp | 2 +- src/V3LifePost.cpp | 2 +- src/V3LinkDot.cpp | 24 +++++++++++------ src/V3LinkInc.cpp | 2 +- src/V3LinkJump.cpp | 2 +- src/V3LinkLValue.cpp | 2 +- src/V3LinkLevel.cpp | 4 +-- src/V3LinkParse.cpp | 2 +- src/V3LinkResolve.cpp | 2 +- src/V3Localize.cpp | 2 +- src/V3MergeCond.cpp | 2 +- src/V3Name.cpp | 2 +- src/V3Options.cpp | 6 ++--- src/V3Options.h | 1 + src/V3Param.cpp | 2 +- src/V3Premit.cpp | 2 +- src/V3Randomize.cpp | 2 +- src/V3Reloop.cpp | 2 +- src/V3Sched.cpp | 2 +- src/V3SchedTiming.cpp | 2 +- src/V3SchedVirtIface.cpp | 2 +- src/V3Scope.cpp | 2 +- src/V3Slice.cpp | 2 +- src/V3Split.cpp | 4 +-- src/V3SplitAs.cpp | 2 +- src/V3SplitVar.cpp | 4 +-- src/V3Subst.cpp | 2 +- src/V3Table.cpp | 2 +- src/V3Task.cpp | 2 +- src/V3Timing.cpp | 2 +- src/V3Trace.cpp | 2 +- src/V3TraceDecl.cpp | 2 +- src/V3Tristate.cpp | 2 +- src/V3Unknown.cpp | 2 +- src/V3Unroll.cpp | 2 +- src/V3VariableOrder.cpp | 2 +- src/V3Width.cpp | 2 +- src/V3WidthCommit.cpp | 2 +- src/Verilator.cpp | 56 +++++++++++++++++++++------------------- 71 files changed, 130 insertions(+), 115 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index b5efe1199..f68ce43d5 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -161,6 +161,7 @@ Srinivasan Venkataramanan Stefan Wallentowitz Stephen Henry Steven Hugg +Szymon Gizler Sören Tempel Teng Huang Tim Hutt diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 800205664..18c9fea8c 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -648,5 +648,5 @@ public: void V3Active::activeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("active", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("active", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index fb59ecc0b..2f4e63bd6 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -142,5 +142,5 @@ public: void V3ActiveTop::activeTopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ActiveTopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("activetop", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 508e33e5f..897fe5906 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -540,5 +540,5 @@ public: void V3Assert::assertAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("assert", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 34104eab2..83f8b9e5f 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -495,5 +495,5 @@ public: void V3AssertPre::assertPreAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { AssertPreVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("assertpre", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index 370c3b794..088d3f7ed 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -366,5 +366,5 @@ void V3Begin::debeginAll(AstNetlist* nodep) { { BeginVisitor{nodep, &state}; } if (state.anyFuncInBegin()) { BeginRelinkVisitor{nodep, &state}; } } // Destruct before checking - V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("begin", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 5f50f4128..7aa3130dc 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -252,5 +252,5 @@ void V3CCtors::cctorsAll() { UINFO(2, __FUNCTION__ << ": " << endl); evalAsserts(); { CCtorsVisitor{v3Global.rootp()}; } - V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("cctors", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 5ad565677..d40abd5b5 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -117,5 +117,5 @@ void V3CUse::cUseAll() { // for each output file and put under that CUseVisitor{modp}; } - V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("cuse", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Case.cpp b/src/V3Case.cpp index fcaa828a5..403f0ac00 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -602,7 +602,7 @@ public: void V3Case::caseAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CaseVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("case", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("case", 0, dumpTreeEitherLevel() >= 3); } void V3Case::caseLint(AstNodeCase* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index c6720efd3..be6a0839f 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -236,5 +236,5 @@ public: void V3Cast::castAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CastVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("cast", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 545e76419..54ac0677b 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -240,5 +240,5 @@ public: void V3Class::classAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClassVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("class", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("class", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 50dd4c576..fa118f4da 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -320,5 +320,5 @@ public: void V3Clean::cleanAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { CleanVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("clean", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index d58d8c138..e3315b35b 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -217,5 +217,5 @@ public: void V3Clock::clockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ClockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("clock", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 0fc717789..40dbbe7f6 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -235,5 +235,5 @@ public: void V3Combine::combineAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); CombineVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("combine", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Common.cpp b/src/V3Common.cpp index 891ca15cf..47a5451ec 100644 --- a/src/V3Common.cpp +++ b/src/V3Common.cpp @@ -172,5 +172,5 @@ void V3Common::commonAll() { if (!dtypep->packed()) makeVlToString(dtypep); } } - V3Global::dumpCheckGlobalTree("common", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("common", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 8353833e2..397324ed1 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -3881,7 +3881,7 @@ void V3Const::constifyAllLint(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_WARN, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3); } void V3Const::constifyCpp(AstNetlist* nodep) { @@ -3890,7 +3890,7 @@ void V3Const::constifyCpp(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_CPP, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("const_cpp", 0, dumpTreeEitherLevel() >= 3); } AstNode* V3Const::constifyEdit(AstNode* nodep) { @@ -3914,7 +3914,7 @@ void V3Const::constifyAllLive(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_LIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3); } void V3Const::constifyAll(AstNetlist* nodep) { @@ -3924,7 +3924,7 @@ void V3Const::constifyAll(AstNetlist* nodep) { ConstVisitor visitor{ConstVisitor::PROC_V_EXPENSIVE, /* globalPass: */ true}; (void)visitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("const", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("const", 0, dumpTreeEitherLevel() >= 3); } AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) { diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index e1d188621..dcddd0c99 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -556,5 +556,5 @@ public: void V3Coverage::coverage(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("coverage", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 7f6603f7d..b7cc10392 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -114,5 +114,5 @@ public: void V3CoverageJoin::coverageJoin(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { CoverageJoinVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("coveragejoin", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 66a3ced92..db5e6ae5c 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -543,29 +543,29 @@ void V3Dead::deadifyModules(AstNetlist* nodep) { { DeadVisitor{nodep, false, false, false, false, !v3Global.opt.topIfacesSupported()}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("deadModules", 0, dumpTreeEitherLevel() >= 6); } void V3Dead::deadifyDTypes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, false, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("deadDtypes", 0, dumpTreeEitherLevel() >= 3); } void V3Dead::deadifyDTypesScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, false, true, true, false, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("deadDtypesScoped", 0, dumpTreeEitherLevel() >= 3); } void V3Dead::deadifyAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, false, true, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("deadAll", 0, dumpTreeEitherLevel() >= 3); } void V3Dead::deadifyAllScoped(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DeadVisitor{nodep, true, true, true, true, false}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("deadAllScoped", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index 79205f615..cb31f131e 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -649,5 +649,5 @@ public: void V3Delayed::delayedAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DelayedVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("delayed", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index 51785fc8a..25a294268 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -160,5 +160,5 @@ public: void V3Depth::depthAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("depth", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index d9fe7dd79..54fa3f2b6 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -121,5 +121,5 @@ public: void V3DepthBlock::depthBlockAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DepthBlockVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("deepblock", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 6f224ab85..56078471f 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -300,5 +300,5 @@ public: void V3Descope::descopeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DescopeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("descope", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3DfgOptimizer.cpp b/src/V3DfgOptimizer.cpp index 98a4fc5e0..f209351a9 100644 --- a/src/V3DfgOptimizer.cpp +++ b/src/V3DfgOptimizer.cpp @@ -233,7 +233,7 @@ void V3DfgOptimizer::extract(AstNetlist* netlistp) { UINFO(2, __FUNCTION__ << ": " << endl); // Extract more optimization candidates DataflowExtractVisitor::apply(netlistp); - V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("dfg-extract", 0, dumpTreeEitherLevel() >= 3); } void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { @@ -300,5 +300,5 @@ void V3DfgOptimizer::optimize(AstNetlist* netlistp, const string& label) { AstModule* const resultModp = V3DfgPasses::dfgToAst(*dfg, ctx); UASSERT_OBJ(resultModp == modp, modp, "Should be the same module"); } - V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("dfg-optimize", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Error.h b/src/V3Error.h index e1032a0dd..4873bd193 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -680,6 +680,7 @@ void v3errorEndFatal(std::ostringstream& sstr) VL_DEFINE_DUMP(DfgLevel, "dfg"); /* Define 'int dumpDfgLevel()' for --dumpi-level */ \ VL_DEFINE_DUMP(GraphLevel, "graph"); /* Define 'int dumpGraphLevel()' for dumpi-graph */ \ VL_DEFINE_DUMP(TreeLevel, "tree"); /* Define 'int dumpTreeLevel()' for dumpi-tree */ \ + VL_ATTR_UNUSED static int dumpTreeEitherLevel() { return dumpTreeLevel(); } \ static_assert(true, "") //---------------------------------------------------------------------- diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index db2b53208..21447053f 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -963,5 +963,5 @@ void V3Expand::expandAll(AstNetlist* nodep) { ExpandOkVisitor okVisitor{nodep}; ExpandVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("expand", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Force.cpp b/src/V3Force.cpp index a7217f811..0141efcbf 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -328,5 +328,5 @@ void V3Force::forceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); if (!v3Global.hasForceableSignals()) return; ForceConvertVisitor::apply(nodep); - V3Global::dumpCheckGlobalTree("force", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("force", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Fork.cpp b/src/V3Fork.cpp index 2d024ea59..7d0900061 100644 --- a/src/V3Fork.cpp +++ b/src/V3Fork.cpp @@ -659,11 +659,11 @@ public: void V3Fork::makeDynamicScopes(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { DynScopeVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("fork_dynscope", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("fork_dynscope", 0, dumpTreeEitherLevel() >= 3); } void V3Fork::makeTasks(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ForkVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("fork", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("fork", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 61ba85be7..2e2976ff9 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -1381,5 +1381,5 @@ void V3Gate::gateAll(AstNetlist* netlistp) { if (dumpGraphLevel() >= 3) graphp->dumpDotFilePrefixed("gate_final"); } - V3Global::dumpCheckGlobalTree("gate", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("gate", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 90d6bd304..638393cd7 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -640,5 +640,5 @@ void V3Inline::inlineAll(AstNetlist* nodep) { } } - V3Global::dumpCheckGlobalTree("inline", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("inline", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index 16a6461df..748a11158 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -610,11 +610,11 @@ void V3Inst::checkOutputShort(AstPin* nodep) { void V3Inst::instAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("inst", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("inst", 0, dumpTreeEitherLevel() >= 3); } void V3Inst::dearrayAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { InstDeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("dearray", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("dearray", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Interface.cpp b/src/V3Interface.cpp index 4f5cfcc9c..146739525 100644 --- a/src/V3Interface.cpp +++ b/src/V3Interface.cpp @@ -113,5 +113,5 @@ void V3Interface::interfaceAll(AstNetlist* nodep) { { InlineIntfRefVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("interface", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("interface", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Life.cpp b/src/V3Life.cpp index 0d057d373..d5292bdb8 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -503,5 +503,5 @@ void V3Life::lifeAll(AstNetlist* nodep) { LifeTopVisitor{nodep, &state}; } // Destruct before checking VIsCached::clearCacheTree(); // Removing assignments may affect isPure - V3Global::dumpCheckGlobalTree("life", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("life", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 07f6d0eeb..4855f800d 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -362,5 +362,5 @@ void V3LifePost::lifepostAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); // Mark redundant AssignPost { LifePostDlyVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("life_post", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("life_post", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index ce262adc9..06bd30b9c 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -3791,18 +3791,24 @@ public: void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { VIsCached::clearCacheTree(); // Avoid using any stale isPure - if (debug() >= 5 || dumpTreeLevel() >= 9) { + if (dumpTreeEitherLevel() >= 9) { + V3Global::dumpCheckGlobalTree("prelinkdot"); + } else if (debug() >= 5) { // on high dbg level, dump even if not explicitly told to v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot.tree")); } LinkDotState state{rootp, step}; const LinkDotFindVisitor visitor{rootp, &state}; - if (debug() >= 5 || dumpTreeLevel() >= 9) { + if (dumpTreeEitherLevel() >= 9) { + V3Global::dumpCheckGlobalTree("prelinkdot-find"); + } else if (debug() >= 5) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-find.tree")); } if (step == LDS_PRIMARY || step == LDS_PARAMED) { // Initial link stage, resolve parameters const LinkDotParamVisitor visitors{rootp, &state}; - if (debug() >= 5 || dumpTreeLevel() >= 9) { + if (dumpTreeEitherLevel() >= 9) { + V3Global::dumpCheckGlobalTree("prelinkdot-param"); + } else if (debug() >= 5) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree")); } } else if (step == LDS_ARRAYED) { @@ -3811,7 +3817,9 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { // process AstScope's. This needs to be separate pass after whole hierarchy graph created. const LinkDotScopeVisitor visitors{rootp, &state}; v3Global.assertScoped(true); - if (debug() >= 5 || dumpTreeLevel() >= 9) { + if (dumpTreeEitherLevel() >= 9) { + V3Global::dumpCheckGlobalTree("prelinkdot-scoped"); + } else if (debug() >= 5) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); } } else { @@ -3829,23 +3837,23 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { void V3LinkDot::linkDotPrimary(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_PRIMARY); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeEitherLevel() >= 6); } void V3LinkDot::linkDotParamed(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_PARAMED); - V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("linkdotparam", 0, dumpTreeEitherLevel() >= 3); } void V3LinkDot::linkDotArrayed(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_ARRAYED); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeEitherLevel() >= 6); } void V3LinkDot::linkDotScope(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); linkDotGuts(nodep, LDS_SCOPED); - V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("linkdot", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index 6f87710ca..92ee6d4ed 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -305,5 +305,5 @@ public: void V3LinkInc::linkIncrements(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkIncVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkinc", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("linkinc", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 267439768..2adf3f1e2 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -348,5 +348,5 @@ public: void V3LinkJump::linkJump(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LinkJumpVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("linkjump", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index 88b34da37..c92aa9956 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -317,7 +317,7 @@ public: void V3LinkLValue::linkLValue(AstNetlist* nodep) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkLValueVisitor{nodep, VAccess::NOCHANGE}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linklvalue", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("linklvalue", 0, dumpTreeEitherLevel() >= 6); } void V3LinkLValue::linkLValueSet(AstNode* nodep) { // Called by later link functions when it is known a node needs diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index f6d19543a..4fbdc657f 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -82,7 +82,7 @@ void V3LinkLevel::modSortByLevel() { UASSERT_OBJ(!v3Global.rootp()->modulesp(), v3Global.rootp(), "Unlink didn't work"); for (AstNodeModule* nodep : mods) v3Global.rootp()->addModulesp(nodep); UINFO(9, "modSortByLevel() done\n"); // Comment required for gcc4.6.3 / bug666 - V3Global::dumpCheckGlobalTree("cells", false, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("cells", false, dumpTreeEitherLevel() >= 3); } void V3LinkLevel::timescaling(const ModVec& mods) { @@ -178,7 +178,7 @@ void V3LinkLevel::wrapTop(AstNetlist* rootp) { } } - V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("wraptop", 0, dumpTreeEitherLevel() >= 6); } void V3LinkLevel::wrapTopCell(AstNetlist* rootp) { diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 7980a7336..275608f98 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -919,5 +919,5 @@ public: void V3LinkParse::linkParse(AstNetlist* rootp) { UINFO(4, __FUNCTION__ << ": " << endl); { LinkParseVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkparse", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("linkparse", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 0507decdf..03a655aa3 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -515,5 +515,5 @@ void V3LinkResolve::linkResolve(AstNetlist* rootp) { const LinkResolveVisitor visitor{rootp}; LinkBotupVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("linkresolve", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("linkresolve", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index b92751c89..7a16c5352 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -219,5 +219,5 @@ public: void V3Localize::localizeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { LocalizeVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("localize", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("localize", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 55e674808..82add8465 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -884,5 +884,5 @@ public: void V3MergeCond::mergeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { MergeCondVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("merge_cond", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("merge_cond", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 481539e64..4631c145e 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -141,5 +141,5 @@ public: void V3Name::nameAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { NameVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("name", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("name", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 340f4c48f..9afd8452e 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -777,7 +777,7 @@ void V3Options::notify() VL_MT_DISABLED { FileLine* const cmdfl = new FileLine{FileLine::commandLineFilename()}; if (!outFormatOk() && v3Global.opt.main()) ccSet(); // --main implies --cc if not provided - if (!outFormatOk() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !xmlOnly()) { + if (!outFormatOk() && !dpiHdrOnly() && !lintOnly() && !preprocOnly() && !serializeOnly()) { v3fatal("verilator: Need --binary, --cc, --sc, --dpi-hdr-only, --lint-only, " "--xml-only or --E option"); } @@ -847,14 +847,14 @@ void V3Options::notify() VL_MT_DISABLED { !v3Global.opt.dpiHdrOnly() // && !v3Global.opt.lintOnly() // && !v3Global.opt.preprocOnly() // - && !v3Global.opt.xmlOnly()); + && !v3Global.opt.serializeOnly()); } if (v3Global.opt.makeDepend().isDefault()) { v3Global.opt.m_makeDepend.setTrueOrFalse( // !v3Global.opt.dpiHdrOnly() // && !v3Global.opt.lintOnly() // && !v3Global.opt.preprocOnly() // - && !v3Global.opt.xmlOnly()); + && !v3Global.opt.serializeOnly()); } if (trace()) { diff --git a/src/V3Options.h b/src/V3Options.h index 5db70ffe6..c80e92875 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -516,6 +516,7 @@ public: bool vpi() const { return m_vpi; } bool xInitialEdge() const { return m_xInitialEdge; } bool xmlOnly() const { return m_xmlOnly; } + bool serializeOnly() const { return m_xmlOnly; } bool topIfacesSupported() const { return lintOnly() && !hierarchical(); } int buildJobs() const VL_MT_SAFE { return m_buildJobs; } diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 028be731b..806dedf9a 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -1479,5 +1479,5 @@ public: void V3Param::param(AstNetlist* rootp) { UINFO(2, __FUNCTION__ << ": " << endl); { ParamVisitor{rootp}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("param", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("param", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 08ab03e69..b313df5c9 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -345,5 +345,5 @@ public: void V3Premit::premitAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { PremitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("premit", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("premit", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Randomize.cpp b/src/V3Randomize.cpp index ecdd7824e..492f42129 100644 --- a/src/V3Randomize.cpp +++ b/src/V3Randomize.cpp @@ -435,7 +435,7 @@ void V3Randomize::randomizeNetlist(AstNetlist* nodep) { const RandomizeMarkVisitor markVisitor{nodep}; RandomizeVisitor{nodep}; } - V3Global::dumpCheckGlobalTree("randomize", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("randomize", 0, dumpTreeEitherLevel() >= 3); } AstFunc* V3Randomize::newRandomizeFunc(AstClass* nodep) { diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 3149ac55d..c7329c8ad 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -268,5 +268,5 @@ public: void V3Reloop::reloopAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReloopVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reloop", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("reloop", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 59014e149..331301a88 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -1383,7 +1383,7 @@ void schedule(AstNetlist* netlistp) { netlistp->dpiExportTriggerp(nullptr); - V3Global::dumpCheckGlobalTree("sched", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("sched", 0, dumpTreeEitherLevel() >= 3); } } // namespace V3Sched diff --git a/src/V3SchedTiming.cpp b/src/V3SchedTiming.cpp index d83d82e61..eda28aa16 100644 --- a/src/V3SchedTiming.cpp +++ b/src/V3SchedTiming.cpp @@ -429,7 +429,7 @@ void transformForks(AstNetlist* const netlistp) { ~ForkVisitor() override = default; }; ForkVisitor{netlistp}; - V3Global::dumpCheckGlobalTree("sched_forks", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("sched_forks", 0, dumpTreeEitherLevel() >= 6); } } // namespace V3Sched diff --git a/src/V3SchedVirtIface.cpp b/src/V3SchedVirtIface.cpp index 270c62aae..5093991c7 100644 --- a/src/V3SchedVirtIface.cpp +++ b/src/V3SchedVirtIface.cpp @@ -225,7 +225,7 @@ VirtIfaceTriggers makeVirtIfaceTriggers(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); if (v3Global.hasVirtIfaces()) { VirtIfaceVisitor visitor{nodep}; - V3Global::dumpCheckGlobalTree("sched_vif", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("sched_vif", 0, dumpTreeEitherLevel() >= 6); return visitor.take_triggers(); } return {}; diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index c8eb247d2..6436b9932 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -416,5 +416,5 @@ void V3Scope::scopeAll(AstNetlist* nodep) { const ScopeVisitor visitor{nodep}; ScopeCleanupVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("scope", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("scope", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index 69ecca56f..f2fe8cb7e 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -335,5 +335,5 @@ public: void V3Slice::sliceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SliceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("slice", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("slice", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Split.cpp b/src/V3Split.cpp index b2e7e8d22..e2eb6c757 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -1005,10 +1005,10 @@ private: void V3Split::splitReorderAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { ReorderVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("reorder", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("reorder", 0, dumpTreeEitherLevel() >= 3); } void V3Split::splitAlwaysAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("split", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("split", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index e63f0d8e8..029144d52 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -192,5 +192,5 @@ public: void V3SplitAs::splitAsAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SplitAsVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("splitas", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("splitas", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 9bb0b1ea5..1247581db 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -1242,9 +1242,9 @@ void V3SplitVar::splitVariable(AstNetlist* nodep) { const SplitUnpackedVarVisitor visitor{nodep}; refs = visitor.getPackedVarRefs(); } - V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeLevel() >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeEitherLevel() >= 9); { SplitPackedVarVisitor{nodep, refs}; } - V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeLevel() >= 9); + V3Global::dumpCheckGlobalTree("split_var", 0, dumpTreeEitherLevel() >= 9); } bool V3SplitVar::canSplitVar(const AstVar* varp) { diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index 643a051f1..5b68583a9 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -384,5 +384,5 @@ public: void V3Subst::substituteAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { SubstVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("subst", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("subst", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Table.cpp b/src/V3Table.cpp index 06ffe06b8..c958c87e8 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -427,5 +427,5 @@ void TableSimulateVisitor::varRefCb(AstVarRef* nodep) { void V3Table::tableAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TableVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("table", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("table", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 021da7f20..62d0f8c05 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1981,5 +1981,5 @@ void V3Task::taskAll(AstNetlist* nodep) { TaskStateVisitor visitors{nodep}; const TaskVisitor visitor{nodep, &visitors}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("task", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("task", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Timing.cpp b/src/V3Timing.cpp index b9993687a..48aa5c017 100644 --- a/src/V3Timing.cpp +++ b/src/V3Timing.cpp @@ -1237,5 +1237,5 @@ void V3Timing::timingAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); TimingSuspendableVisitor susVisitor{nodep}; if (v3Global.usesTiming()) TimingControlVisitor{nodep}; - V3Global::dumpCheckGlobalTree("timing", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("timing", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 6be90173a..ef3795b7c 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -918,5 +918,5 @@ public: void V3Trace::traceAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("trace", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("trace", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 47986dbd6..cceee8a5c 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -691,5 +691,5 @@ public: void V3TraceDecl::traceDeclAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TraceDeclVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tracedecl", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("tracedecl", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 48f1e8d46..56cf939f8 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -1814,5 +1814,5 @@ public: void V3Tristate::tristateAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { TristateVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("tristate", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("tristate", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index cb34c7ed3..69fca0873 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -525,5 +525,5 @@ public: void V3Unknown::unknownAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { UnknownVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("unknown", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("unknown", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index ae92a5230..076b0518a 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -512,5 +512,5 @@ void V3Unroll::unrollAll(AstNetlist* nodep) { UnrollStateful unroller; unroller.unrollAll(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("unroll", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index 7bddc69a6..cc02a8a6c 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -202,5 +202,5 @@ void V3VariableOrder::orderAll() { modp = VN_AS(modp->nextp(), NodeModule)) { VariableOrder::processModule(modp); } - V3Global::dumpCheckGlobalTree("variableorder", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("variableorder", 0, dumpTreeEitherLevel() >= 3); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 13afe74f3..d6cfaae8f 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -7620,7 +7620,7 @@ void V3Width::width(AstNetlist* nodep) { WidthRemoveVisitor rvisitor; (void)rvisitor.mainAcceptEdit(nodep); } // Destruct before checking - V3Global::dumpCheckGlobalTree("width", 0, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("width", 0, dumpTreeEitherLevel() >= 3); } //! Single node parameter propagation //! Smaller step... Only do a single node for parameter propagation diff --git a/src/V3WidthCommit.cpp b/src/V3WidthCommit.cpp index c3ac9bc95..174d25605 100644 --- a/src/V3WidthCommit.cpp +++ b/src/V3WidthCommit.cpp @@ -232,5 +232,5 @@ public: void V3WidthCommit::widthCommit(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); { WidthCommitVisitor{nodep}; } // Destruct before checking - V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeLevel() >= 6); + V3Global::dumpCheckGlobalTree("widthcommit", 0, dumpTreeEitherLevel() >= 6); } diff --git a/src/Verilator.cpp b/src/Verilator.cpp index cee743a50..3c4cea294 100644 --- a/src/Verilator.cpp +++ b/src/Verilator.cpp @@ -151,7 +151,7 @@ static void process() { if (v3Global.opt.stats()) V3Stats::statsStageAll(v3Global.rootp(), "Link"); if (v3Global.opt.debugExitUvm23()) { V3Error::abortIfErrors(); - if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + if (v3Global.opt.serializeOnly()) V3EmitXml::emitxml(); cout << "--debug-exit-uvm23: Exiting after UVM-supported pass\n"; std::exit(0); } @@ -168,7 +168,8 @@ static void process() { v3Global.checkTree(); // Create a hierarchical Verilation plan - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.hierarchical()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() + && v3Global.opt.hierarchical()) { V3HierBlockPlan::createPlan(v3Global.rootp()); // If a plan is created, further analysis is not necessary. // The actual Verilation will be done based on this plan. @@ -179,7 +180,7 @@ static void process() { } if (v3Global.opt.debugExitUvm()) { V3Error::abortIfErrors(); - if (v3Global.opt.xmlOnly()) V3EmitXml::emitxml(); + if (v3Global.opt.serializeOnly()) V3EmitXml::emitxml(); cout << "--debug-exit-uvm: Exiting after UVM-supported pass\n"; std::exit(0); } @@ -215,7 +216,7 @@ static void process() { // V3Assert::assertAll(v3Global.rootp()); - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Add top level wrapper with instance pointing to old top // Move packages to under new top // Must do this after we know parameters and dtypes (as don't clone dtype decls) @@ -225,7 +226,7 @@ static void process() { // Propagate constants into expressions if (v3Global.opt.fConstBeforeDfg()) V3Const::constifyAllLint(v3Global.rootp()); - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Split packed variables into multiple pieces to resolve UNOPTFLAT. // should be after constifyAllLint() which flattens to 1D bit vector V3SplitVar::splitVariable(v3Global.rootp()); @@ -250,7 +251,7 @@ static void process() { V3Tristate::tristateAll(v3Global.rootp()); } - if (!v3Global.opt.xmlOnly()) { + if (!v3Global.opt.serializeOnly()) { // Move assignments from X into MODULE temps. // (Before flattening, so each new X variable is shared between all scopes of that // module.) @@ -268,7 +269,7 @@ static void process() { V3DfgOptimizer::optimize(v3Global.rootp(), " pre inline"); } - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Module inlining // Cannot remove dead variables after this, as alias information for final // V3Scope's V3LinkDot is in the AstVar. @@ -298,7 +299,7 @@ static void process() { // --FLATTENING--------------- - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // We're going to flatten the hierarchy, so as many optimizations that // can be done as possible should be before this.... @@ -318,25 +319,25 @@ static void process() { // --SCOPE BASED OPTIMIZATIONS-------------- - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Cleanup V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyDTypesScoped(v3Global.rootp()); v3Global.checkTree(); } - if (!v3Global.opt.xmlOnly()) { + if (!v3Global.opt.serializeOnly()) { // Convert case statements to if() blocks. Must be after V3Unknown // Must be before V3Task so don't need to deal with task in case value compares V3Case::caseAll(v3Global.rootp()); } - if (!(v3Global.opt.xmlOnly() && !v3Global.opt.flatten())) { + if (!(v3Global.opt.serializeOnly() && !v3Global.opt.flatten())) { // Inline all tasks V3Task::taskAll(v3Global.rootp()); } - if (!v3Global.opt.xmlOnly()) { + if (!v3Global.opt.serializeOnly()) { // Add __PVT's // After V3Task so task internal variables will get renamed V3Name::nameAll(v3Global.rootp()); @@ -449,7 +450,7 @@ static void process() { // --MODULE OPTIMIZATIONS-------------- - if (!v3Global.opt.xmlOnly()) { + if (!v3Global.opt.serializeOnly()) { // Split deep blocks to appease MSVC++. Must be before Localize. if (!v3Global.opt.lintOnly() && v3Global.opt.compLimitBlocks()) { V3DepthBlock::depthBlockAll(v3Global.rootp()); @@ -472,7 +473,7 @@ static void process() { // --GENERATION------------------ - if (!v3Global.opt.xmlOnly()) { + if (!v3Global.opt.serializeOnly()) { // Remove unused vars V3Const::constifyAll(v3Global.rootp()); V3Dead::deadifyAll(v3Global.rootp()); @@ -489,24 +490,24 @@ static void process() { } // Expand macros and wide operators into C++ primitives - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && v3Global.opt.fExpand()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() && v3Global.opt.fExpand()) { V3Expand::expandAll(v3Global.rootp()); } // Propagate constants across WORDSEL arrayed temporaries - if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubst()) { + if (!v3Global.opt.serializeOnly() && v3Global.opt.fSubst()) { // Constant folding of expanded stuff V3Const::constifyCpp(v3Global.rootp()); V3Subst::substituteAll(v3Global.rootp()); } - if (!v3Global.opt.xmlOnly() && v3Global.opt.fSubstConst()) { + if (!v3Global.opt.serializeOnly() && v3Global.opt.fSubstConst()) { // Constant folding of substitutions V3Const::constifyCpp(v3Global.rootp()); V3Dead::deadifyAll(v3Global.rootp()); } - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()) { if (v3Global.opt.fMergeCond()) { // Merge conditionals V3MergeCond::mergeAll(v3Global.rootp()); @@ -531,11 +532,11 @@ static void process() { } V3Error::abortIfErrors(); - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly()) { // + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly()) { // V3CCtors::cctorsAll(); } - if (!v3Global.opt.xmlOnly() && v3Global.opt.mtasks()) { + if (!v3Global.opt.serializeOnly() && v3Global.opt.mtasks()) { // Finalize our MTask cost estimates and pack the mtasks into // threads. Must happen pre-EmitC which relies on the packing // order. Must happen post-V3LifePost which changes the relative @@ -543,7 +544,8 @@ static void process() { V3Partition::finalize(v3Global.rootp()); } - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() + && !v3Global.opt.dpiHdrOnly()) { // Add common methods/etc to modules V3Common::commonAll(); @@ -555,7 +557,8 @@ static void process() { } // Output the text - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() + && !v3Global.opt.dpiHdrOnly()) { // emitcInlines is first, as it may set needHInlines which other emitters read V3EmitC::emitcInlines(); V3EmitC::emitcSyms(); @@ -567,13 +570,13 @@ static void process() { V3EmitC::emitcSyms(true); } } - if (!v3Global.opt.xmlOnly() + if (!v3Global.opt.serializeOnly() && !v3Global.opt.dpiHdrOnly()) { // Unfortunately we have some lint checks in emitcImp. V3EmitC::emitcImp(); } { const V3MtDisabledLockGuard mtDisabler{v3MtDisabledLock()}; - if (v3Global.opt.xmlOnly() + if (v3Global.opt.serializeOnly() // Check XML when debugging to make sure no missing node types || (v3Global.opt.debugCheck() && !v3Global.opt.lintOnly() && !v3Global.opt.dpiHdrOnly())) { @@ -590,7 +593,8 @@ static void process() { V3EmitC::emitcFiles(); } - if (!v3Global.opt.lintOnly() && !v3Global.opt.xmlOnly() && !v3Global.opt.dpiHdrOnly()) { + if (!v3Global.opt.lintOnly() && !v3Global.opt.serializeOnly() + && !v3Global.opt.dpiHdrOnly()) { if (v3Global.opt.main()) V3EmitCMain::emit(); // V3EmitMk/V3EmitCMake must be after all other emitters, @@ -679,7 +683,7 @@ static void verilate(const string& argString) { } // Final steps - V3Global::dumpCheckGlobalTree("final", 990, dumpTreeLevel() >= 3); + V3Global::dumpCheckGlobalTree("final", 990, dumpTreeEitherLevel() >= 3); V3Error::abortIfErrors(); From ab47fc66564022dce4f125c2010772f08b8dae49 Mon Sep 17 00:00:00 2001 From: Andrew Nolte Date: Thu, 11 Jan 2024 07:49:07 -0500 Subject: [PATCH 024/116] Fix localparam elaboration (#3858) (#4794) --- src/V3Param.cpp | 12 ++-- ...m_unsup.out => t_interface_localparam.out} | 4 +- ...ram_unsup.pl => t_interface_localparam.pl} | 2 - test_regress/t/t_interface_localparam.v | 60 +++++++++++++++++++ test_regress/t/t_interface_localparam_unsup.v | 51 ---------------- 5 files changed, 67 insertions(+), 62 deletions(-) rename test_regress/t/{t_interface_localparam_unsup.out => t_interface_localparam.out} (63%) rename test_regress/t/{t_interface_localparam_unsup.pl => t_interface_localparam.pl} (87%) create mode 100644 test_regress/t/t_interface_localparam.v delete mode 100644 test_regress/t/t_interface_localparam_unsup.v diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 806dedf9a..5169ae83b 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -825,7 +825,7 @@ class ParamProcessor final { } } - void storeOriginalParams(AstClass* const classp) { + void storeOriginalParams(AstNodeModule* const classp) { for (AstNode* stmtp = classp->stmtsp(); stmtp; stmtp = stmtp->nextp()) { AstNode* originalParamp = nullptr; if (AstVar* const varp = VN_CAST(stmtp, Var)) { @@ -870,13 +870,13 @@ class ParamProcessor final { UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); // If it's the first use of the default instance, create a copy and store it in user3p. // user3p will also be used to check if the default instance is used. - if (!srcModpr->user3p() && VN_IS(srcModpr, Class)) { - AstClass* classCopyp = VN_AS(srcModpr, Class)->cloneTree(false); + if (!srcModpr->user3p() && (VN_IS(srcModpr, Class) || VN_IS(srcModpr, Iface))) { + AstNodeModule* nodeCopyp = srcModpr->cloneTree(false); // It is a temporary copy of the original class node, stored in order to create // another instances. It is needed only during class instantiation. - m_deleter.pushDeletep(classCopyp); - srcModpr->user3p(classCopyp); - storeOriginalParams(classCopyp); + m_deleter.pushDeletep(nodeCopyp); + srcModpr->user3p(nodeCopyp); + storeOriginalParams(nodeCopyp); } } else { const string newname diff --git a/test_regress/t/t_interface_localparam_unsup.out b/test_regress/t/t_interface_localparam.out similarity index 63% rename from test_regress/t/t_interface_localparam_unsup.out rename to test_regress/t/t_interface_localparam.out index 1ac204e0e..21c7ae04c 100644 --- a/test_regress/t/t_interface_localparam_unsup.out +++ b/test_regress/t/t_interface_localparam.out @@ -1,5 +1,3 @@ *-* All Finished *-* top.t.intf: symbolsPerBeat 16, symbolsPerBeatDivBy2 8, mismatch 0 -top.t.theCore.core_intf: symbolsPerBeat 64, symbolsPerBeatDivBy2 8, mismatch 1 -%Error: t/t_interface_localparam_unsup.v:23: Verilog $stop -Aborting... +top.t.theCore.core_intf: symbolsPerBeat 64, symbolsPerBeatDivBy2 32, mismatch 0 diff --git a/test_regress/t/t_interface_localparam_unsup.pl b/test_regress/t/t_interface_localparam.pl similarity index 87% rename from test_regress/t/t_interface_localparam_unsup.pl rename to test_regress/t/t_interface_localparam.pl index fa08b1e33..762975c8b 100755 --- a/test_regress/t/t_interface_localparam_unsup.pl +++ b/test_regress/t/t_interface_localparam.pl @@ -15,8 +15,6 @@ compile( execute( check_finished => 1, - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); ok(1); diff --git a/test_regress/t/t_interface_localparam.v b/test_regress/t/t_interface_localparam.v new file mode 100644 index 000000000..1adc2565b --- /dev/null +++ b/test_regress/t/t_interface_localparam.v @@ -0,0 +1,60 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2023 by Justin Thiel. +// SPDX-License-Identifier: CC0-1.0 + +interface SimpleIntf +#( + parameter int val = 28 +) +(); + + // This value is calculated incorrectly for other instances of + // this interface when it is accessed via the HDL for any other + // instance of this interface + localparam int valDiv2 = val/2; + localparam int valDiv4 = valDiv2/2; + + localparam bit mismatch2 = (val != (2*valDiv2) ); + localparam bit mismatch4 = (val != (4*valDiv4) ); + + initial begin + $write("%m: val %0d, valDiv2 %0d, mismatch2 %0d\n", + val, valDiv2, mismatch2); + $write("%m: val %0d, valDiv4 %0d, mismatch4 %0d\n", + val, valDiv4, mismatch2); + if (mismatch2) $stop; + if (mismatch4) $stop; + end + +endinterface + +module Core( + SimpleIntf intf +); + + // this will constify and valDiv2 will have the default value + localparam valDiv4Upper = intf.valDiv2; + + SimpleIntf #(.val(68)) core_intf (); + + initial begin + if (intf.valDiv2 != valDiv4Upper) begin + $display("%%Error: param = %0d", intf.valDiv2); + end + end +endmodule + +module t(); + + SimpleIntf intf(); + + Core theCore (.intf); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_interface_localparam_unsup.v b/test_regress/t/t_interface_localparam_unsup.v deleted file mode 100644 index 6deb411ae..000000000 --- a/test_regress/t/t_interface_localparam_unsup.v +++ /dev/null @@ -1,51 +0,0 @@ -// DESCRIPTION: Verilator: Verilog Test module -// -// This file ONLY is placed into the Public Domain, for any use, -// without warranty, 2023 by Justin Thiel. -// SPDX-License-Identifier: CC0-1.0 - -interface SimpleIntf -#( - parameter int symbolsPerBeat = 16 -) -(); - - // This value is calculated incorrectly for other instances of - // this interface when it is accessed via the HDL for any other - // instance of this interface - localparam int symbolsPerBeatDivBy2 = symbolsPerBeat/2; - - localparam bit mismatch = (symbolsPerBeat != (2*symbolsPerBeatDivBy2) ); - - initial begin - $write("%m: symbolsPerBeat %0d, symbolsPerBeatDivBy2 %0d, mismatch %0d\n", - symbolsPerBeat, symbolsPerBeatDivBy2, mismatch); - if (mismatch) $stop; - end - -endinterface - -module Core( - SimpleIntf intf -); - - // NOTE: When this line is commented out the test will pass - localparam intf_symbolsPerBeatDivBy2 = intf.symbolsPerBeatDivBy2; - - localparam int core_intf_symbolsPerBeat = 64; - SimpleIntf #(.symbolsPerBeat(core_intf_symbolsPerBeat)) core_intf (); - -endmodule - -module t(); - - SimpleIntf intf(); - - Core theCore (.intf); - - initial begin - $write("*-* All Finished *-*\n"); - $finish; - end - -endmodule From fcdd8e5da6f91ee794b1a270e688deaa1921d8ac Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Thu, 11 Jan 2024 20:19:48 -0500 Subject: [PATCH 025/116] Fix missing includes with multiple inheritance (#3819 partial) --- src/V3EmitCHeaders.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 4a9bfdb06..795193e5a 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -296,9 +296,9 @@ class EmitCHeader final : public EmitCConstInit { void emitAll(const AstNodeModule* modp) { // Include files required by this AstNodeModule if (const AstClass* const classp = VN_CAST(modp, Class)) { - if (classp->extendsp()) { - puts("#include \"" - + prefixNameProtect(classp->extendsp()->classp()->classOrPackagep()) + for (const AstClassExtends* extp = classp->extendsp(); extp; + extp = VN_AS(extp->nextp(), ClassExtends)) { + puts("#include \"" + prefixNameProtect(extp->classp()->classOrPackagep()) + ".h\"\n"); } } From 21bf2d62d2ae6ff7380afbbfd89cc954913cdd0d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 12 Jan 2024 08:19:30 -0500 Subject: [PATCH 026/116] Fix mis-splitting of dump control functions (#4821). --- Changes | 1 + src/V3AstNodeExpr.h | 2 ++ src/V3AstNodeOther.h | 3 ++- 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index e5f0e02b2..af190d398 100644 --- a/Changes +++ b/Changes @@ -17,6 +17,7 @@ Verilator 5.021 devel * Remove deprecated 32-bit pointer mode (`gcc -m32`). * Fix delays using wrong timeunits when modules inlined (#4806). [Paul Wright] * Fix lint_off disables on preprocessor warnings (#4703). [Srinivasan Venkataramanan] +* Fix mis-splitting of dump control functions (#4821). [Fan Shupei] Verilator 5.020 2024-01-01 diff --git a/src/V3AstNodeExpr.h b/src/V3AstNodeExpr.h index 89caeed1e..a7b1a6775 100644 --- a/src/V3AstNodeExpr.h +++ b/src/V3AstNodeExpr.h @@ -2072,6 +2072,7 @@ public: string emitC() override { return "VL_VALUEPLUSARGS_%nq(%lw, %P, nullptr)"; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } + // but isPure() true bool cleanOut() const override { return true; } bool same(const AstNode* /*samep*/) const override { return true; } }; @@ -3479,6 +3480,7 @@ public: bool sizeMattersRhs() const override { return false; } bool isGateOptimizable() const override { return false; } bool isPredictOptimizable() const override { return false; } + bool isPure() override { return false; } int instrCount() const override { return INSTR_COUNT_PLI; } }; diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index ee2b52808..2ca075540 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -2840,8 +2840,9 @@ public: ASTGEN_MEMBERS_AstDumpCtl; string verilogKwd() const override { return ctlType().ascii(); } bool isGateOptimizable() const override { return false; } - bool isPredictOptimizable() const override { return false; } bool isOutputter() override { return true; } + bool isPredictOptimizable() const override { return false; } + bool isPure() override { return false; } virtual bool cleanOut() const { return true; } bool same(const AstNode* /*samep*/) const override { return true; } VDumpCtlType ctlType() const { return m_ctlType; } From 27d906a6b34c6ee7033ace790b7f4f3234ba10e6 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Fri, 12 Jan 2024 08:20:53 -0500 Subject: [PATCH 027/116] Commentary: Changes update --- Changes | 10 +++++++++- docs/spelling.txt | 2 ++ 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/Changes b/Changes index af190d398..293b244f2 100644 --- a/Changes +++ b/Changes @@ -15,8 +15,16 @@ Verilator 5.021 devel * Add predicted stack overflow warning (#4799). * Remove deprecated 32-bit pointer mode (`gcc -m32`). -* Fix delays using wrong timeunits when modules inlined (#4806). [Paul Wright] +* Change zero replication width error to ZEROREPL warning (#4753) (#4762). [Pengcheng Xu] +* Support `vpiConstType` in `vpi_get_str()` (#4797). [Marlon James] +* Support SystemC 3.0.0 public review version (#4805) (#4807). [Anthony Donlon] +* Support parsing anonymous primitive instantiations (#4809). [Anthony Donlon] +* Fix localparam elaboration (#3858) (#4794). [Andrew Nolte] * Fix lint_off disables on preprocessor warnings (#4703). [Srinivasan Venkataramanan] +* Fix $time not rounding up (#4790) (#4792). [Paul Wright] +* Fix `vpi_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795). [Marlon James] +* Fix VPI parameter iteration (#4798). [Marlon James] +* Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright] * Fix mis-splitting of dump control functions (#4821). [Fan Shupei] diff --git a/docs/spelling.txt b/docs/spelling.txt index dfa90efdf..602f3b397 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -940,6 +940,7 @@ stdin stdout stime stmts +str strcasecmp stringification stringified @@ -1047,6 +1048,7 @@ vpiSize vpiSuppressVal vpiTimeUnit vpiType +vpiUndefined vpm vpp warmup From c9d7486d16223e414b89e2545354245d3bec4788 Mon Sep 17 00:00:00 2001 From: Larry Doolittle Date: Fri, 12 Jan 2024 10:09:34 -0800 Subject: [PATCH 028/116] Fix maybe-uninitialized compiler warning (#4820) (#4822) --- include/verilated_fst_c.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index 79c5c9ee9..ffc78ec99 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -174,7 +174,7 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, if (dtypenum > 0) fstWriterEmitEnumTableRef(m_fst, m_local2fstdtype[dtypenum]); - fstVarDir varDir; + fstVarDir varDir = FST_VD_IMPLICIT; switch (direction) { case VerilatedTraceSigDirection::INOUT: varDir = FST_VD_INOUT; break; case VerilatedTraceSigDirection::OUTPUT: varDir = FST_VD_OUTPUT; break; From 5073f208af0868d2888f1603bb9ec7cd61b34866 Mon Sep 17 00:00:00 2001 From: Tim Hutt Date: Sat, 13 Jan 2024 20:34:59 +0000 Subject: [PATCH 029/116] Internals: Use more standard syntax for avoiding unused variable warnings (#4826) --- include/verilated.cpp | 9 ++++++--- src/V3CCtors.cpp | 4 ++-- src/V3EmitCFunc.h | 2 +- src/V3EmitCImp.cpp | 2 +- src/V3EmitCModel.cpp | 2 +- src/V3Trace.cpp | 2 +- 6 files changed, 12 insertions(+), 9 deletions(-) diff --git a/include/verilated.cpp b/include/verilated.cpp index c6c5c7321..3ce0fe4da 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -112,7 +112,8 @@ thread_local Verilated::ThreadLocal Verilated::t_s; #ifndef VL_USER_FINISH ///< Define this to override the vl_finish function void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { - if (false && hier) {} // Unused argument + // hier is unused in the default implementation. + (void)hier; VL_PRINTF( // Not VL_PRINTF_MT, already on main thread "- %s:%d: Verilog $finish\n", filename, linenum); Verilated::threadContextp()->gotFinish(true); @@ -140,7 +141,8 @@ void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE { #ifndef VL_USER_FATAL ///< Define this to override the vl_fatal function void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { - if (false && hier) {} + // hier is unused in the default implementation. + (void)hier; Verilated::threadContextp()->gotError(true); Verilated::threadContextp()->gotFinish(true); if (filename && filename[0]) { @@ -178,7 +180,8 @@ void vl_stop_maybe(const char* filename, int linenum, const char* hier, bool may #ifndef VL_USER_WARN ///< Define this to override the vl_warn function void vl_warn(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_UNSAFE { - if (false && hier) {} + // hier is unused in the default implementation. + (void)hier; if (filename && filename[0]) { // Not VL_PRINTF_MT, already on main thread VL_PRINTF("%%Warning: %s:%d: %s\n", filename, linenum, msg); diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 7aa3130dc..afffc75c4 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -67,10 +67,10 @@ class V3CCtorsBuilder final { string preventUnusedStmt; if (m_type.isClass()) { funcp->argTypes(EmitCBase::symClassVar()); - preventUnusedStmt = "if (false && vlSymsp) {} // Prevent unused\n"; + preventUnusedStmt = "(void)vlSymsp; // Prevent unused variable warning\n"; } else if (m_type.isCoverage()) { funcp->argTypes("bool first"); - preventUnusedStmt = "if (false && first) {} // Prevent unused\n"; + preventUnusedStmt = "(void)first; // Prevent unused variable warning\n"; } if (!preventUnusedStmt.empty()) { funcp->addStmtsp(new AstCStmt{m_modp->fileline(), preventUnusedStmt}); diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 8c75f0462..0ae6f53ec 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -286,7 +286,7 @@ public: m_lazyDecls.declared(nodep); // Defined here, so no longer needs declaration if (!nodep->isStatic()) { // Standard prologue m_useSelfForThis = true; - puts("if (false && vlSelf) {} // Prevent unused\n"); + puts("(void)vlSelf; // Prevent unused variable warning\n"); if (!VN_IS(m_modp, Class)) puts(symClassAssign()); } } diff --git a/src/V3EmitCImp.cpp b/src/V3EmitCImp.cpp index bf46f0f3c..d33c172e2 100644 --- a/src/V3EmitCImp.cpp +++ b/src/V3EmitCImp.cpp @@ -293,7 +293,7 @@ class EmitCImp final : EmitCFunc { } puts("\nvoid " + modName + "::" + protect("__Vconfigure") + "(bool first) {\n"); - puts("if (false && first) {} // Prevent unused\n"); + puts("(void)first; // Prevent unused variable warning\n"); if (v3Global.opt.coverage()) { puts(modName + "__" + protect("_configure_coverage") + "(this, first);\n"); } diff --git a/src/V3EmitCModel.cpp b/src/V3EmitCModel.cpp index 1ecbab127..90ccd80fc 100644 --- a/src/V3EmitCModel.cpp +++ b/src/V3EmitCModel.cpp @@ -548,7 +548,7 @@ class EmitCModel final : public EmitCFunc { + +"::trace()' shall not be called after '" + v3Global.opt.traceClassBase() + "C::open()'.\");\n"); puts(/**/ "}\n"); - puts(/**/ "if (false && levels && options) {} // Prevent unused\n"); + puts(/**/ "(void)levels; (void)options; // Prevent unused variable warning\n"); puts(/**/ "tfp->spTrace()->addModel(this);\n"); puts(/**/ "tfp->spTrace()->addInitCb(&" + protect("trace_init") + ", &(vlSymsp->TOP));\n"); puts(/**/ topModNameProtected + "__" + protect("trace_register") diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index ef3795b7c..44d7e807d 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -533,7 +533,7 @@ class TraceVisitor final : public VNVisitor { addInitStr("const uint32_t base VL_ATTR_UNUSED = " "vlSymsp->__Vm_baseCode + " + cvtToStr(baseCode) + ";\n"); - addInitStr("if (false && bufp) {} // Prevent unused\n"); + addInitStr("(void)bufp; // Prevent unused variable warning\n"); } else { addInitStr("uint32_t* const oldp VL_ATTR_UNUSED = " "bufp->oldp(vlSymsp->__Vm_baseCode + " From 2e999a544159243c8442db3f0c4e65e6b0b7de1d Mon Sep 17 00:00:00 2001 From: Adrian Sampson Date: Sat, 13 Jan 2024 19:52:50 -0500 Subject: [PATCH 030/116] Fix too null pointer dereference (#4810) (#4825) --- docs/CONTRIBUTORS | 1 + src/V3TraceDecl.cpp | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index f68ce43d5..3ca519cd0 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -4,6 +4,7 @@ under the Developer Certificate of Origin (https://developercertificate.org/). Please see the Verilator manual for 200+ additional contributors. Thanks to all. Adam Bagley +Adrian Sampson Adrien Le Masle Ahmed El-Mahmoudy Aleksander Kiryk diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index cceee8a5c..0735e6dce 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -259,10 +259,12 @@ class TraceDeclVisitor final : public VNVisitor { const std::string name = path.substr(pos == string::npos ? 0 : pos + 1); // Compute the type of the scope being fixed up - AstNodeModule* const modp = scopep->aboveCellp()->modp(); - const VTracePrefixType scopeType = VN_IS(modp, Iface) - ? VTracePrefixType::SCOPE_INTERFACE - : VTracePrefixType::SCOPE_MODULE; + const AstCell* const cellp = scopep->aboveCellp(); + const VTracePrefixType scopeType = cellp ? ( + VN_IS((cellp->modp()), Iface) + ? VTracePrefixType::SCOPE_INTERFACE + : VTracePrefixType::SCOPE_MODULE + ) : VTracePrefixType::SCOPE_MODULE; // Push the scope prefix AstNodeStmt* const pushp = new AstTracePushPrefix{flp, name, scopeType}; From 54922c036a4e3d28efd0b3502b1b699af1c77828 Mon Sep 17 00:00:00 2001 From: github action Date: Sun, 14 Jan 2024 00:53:31 +0000 Subject: [PATCH 031/116] Apply 'make format' --- src/V3TraceDecl.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 0735e6dce..63302b5c2 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -260,11 +260,10 @@ class TraceDeclVisitor final : public VNVisitor { // Compute the type of the scope being fixed up const AstCell* const cellp = scopep->aboveCellp(); - const VTracePrefixType scopeType = cellp ? ( - VN_IS((cellp->modp()), Iface) - ? VTracePrefixType::SCOPE_INTERFACE - : VTracePrefixType::SCOPE_MODULE - ) : VTracePrefixType::SCOPE_MODULE; + const VTracePrefixType scopeType + = cellp ? (VN_IS((cellp->modp()), Iface) ? VTracePrefixType::SCOPE_INTERFACE + : VTracePrefixType::SCOPE_MODULE) + : VTracePrefixType::SCOPE_MODULE; // Push the scope prefix AstNodeStmt* const pushp = new AstTracePushPrefix{flp, name, scopeType}; From 372cdf1fc860c5b7945fc8cfe857dd4d2e4fb862 Mon Sep 17 00:00:00 2001 From: Szymon Gizler <151655464+sgizler@users.noreply.github.com> Date: Tue, 16 Jan 2024 17:18:20 +0100 Subject: [PATCH 032/116] Tests: Let debugger handle signals instead of test driver (#4817) --- test_regress/driver.pl | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 526ced720..692d6fd89 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -26,6 +26,7 @@ use POSIX qw(strftime); use lib "."; use Time::HiRes qw(usleep); use Digest::MD5 qw(md5); +use POSIX; $::Driver = 1; $::Have_Forker = 0; @@ -133,6 +134,11 @@ if (! GetOptions( $opt_jobs = calc_jobs() if defined $opt_jobs && $opt_jobs == 0; $Fork->max_proc($opt_jobs); +my $interactive_debugger = $opt_gdb || $opt_gdbsim || $opt_rr || $opt_rrsim; +if ($opt_jobs > 1 && $interactive_debugger) { + die "%Error: Unable to use -j > 1 with --gdb* and --rr* options" +} + if ((scalar keys %opt_scenarios) < 1) { $opt_scenarios{dist} = 1; $opt_scenarios{vlt} = 1; @@ -451,7 +457,7 @@ sub wait_and_report { while ($::Fork->is_any_left) { $::Fork->poll; if ((time() - ($self->{_last_summary_time} || 0) >= 30) - && (!$opt_gdb && !$opt_gdbsim)) { # Don't show for interactive gdb etc + && !$interactive_debugger) { # Don't show for interactive gdb etc $self->print_summary(force => 1, show_running => 1); } Time::HiRes::usleep 100 * 1000; @@ -492,7 +498,7 @@ sub print_summary { @_); # All legal arguments shown immediately above if (!$self->{quiet} || $params{force} || ($self->{left_cnt} < 5) - || (time() - ($self->{_last_summary_time} || 0) >= 15)) { # Don't show for interactive gdb etc + || (time() - ($self->{_last_summary_time} || 0) >= 15)) { $self->{_last_summary_time} = time(); print STDERR ("==SUMMARY: " . $self->sprint_summary . "\n"); if ($params{show_running}) { @@ -1645,8 +1651,14 @@ sub _run { if ($param{logfile}) { $logfh = IO::File->new(">$param{logfile}") or die "%Error: Can't open $param{logfile}"; } + my $backup_fg_group = POSIX::tcgetpgrp(0); my $pid = fork(); if ($pid) { # Parent + if ($interactive_debugger) { + # Let gdb take care of signals send from keyboard + POSIX::setpgid($pid, 0); # Put child in separate process group + POSIX::tcsetpgrp(0, $pid); # Make this group a foreground one + } close CHILDWR; print "driver: Entering directory '", File::Spec->rel2abs($param{entering}), "'\n" if $param{entering}; @@ -1687,6 +1699,11 @@ sub _run { exit($? ? 10 : 0); # $?>>8 misses coredumps } waitpid($pid, 0); + if ($interactive_debugger) { + # Restore old foreground group + local $SIG{TTOU} = 'IGNORE'; # Ignore SIGTTOU from modyfing terminal settings in bg proccess + POSIX::tcsetpgrp(0, $backup_fg_group); + } $status = $? || 0; } flush STDOUT; From 6f96c6763d7e135c57c2fa092bf938679909dfa5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 17 Jan 2024 08:25:54 -0500 Subject: [PATCH 033/116] Commentary --- docs/guide/simulating.rst | 31 ++++++++++++++++--------------- 1 file changed, 16 insertions(+), 15 deletions(-) diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index 3890fc75a..c4af6115a 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -505,21 +505,12 @@ documentation. Runtime Debugging ================= -To debug a Verilated executable, use the standard GNU debugger ``gdb`` or a -similar tool, e.g.: - - .. code-block:: bash - - gdb obj_dir/Vmodel - run {Vmodel_command_arguments} - {segmentation faults} - bt - -Typically you will want to have debugger symbols inserted by the compiler, -assertions enabled in the C library, assertions enabled in the Verilated -library, and the sanitizer enabled to look for bad memory or undefined -operations. (These options slow down the executable, so do this only when -debugging.) To enable these, Verilate with: +To debug a Verilated executable, typically you will want to have debugger +symbols inserted by the compiler, assertions enabled in the C library, +assertions enabled in the Verilated library, and the sanitizer enabled to +look for bad memory or undefined operations. (These options slow down the +executable, so do this only when debugging.) To enable these, Verilate +with: .. code-block:: bash @@ -532,3 +523,13 @@ The :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options used here pass the following argument into the generated Makefile for use as compiler or linker options respectively. If you are using your own Makefiles, adapt appropriately to pass the suggested flags to the compiler and linker. + +Once you have a debugging-enabled executable, run it using the the standard +GNU debugger ``gdb`` or a similar tool, and create a backtrace; e.g.: + + .. code-block:: bash + + gdb obj_dir/Vmodel + run {Vmodel_command_arguments} + {segmentation faults} + bt From db3ce29b36807c5b5278913399e14b1ec00f0f77 Mon Sep 17 00:00:00 2001 From: Szymon Gizler <151655464+sgizler@users.noreply.github.com> Date: Wed, 17 Jan 2024 14:32:44 +0100 Subject: [PATCH 034/116] Fix wrong utimes() param (#4829) --- src/V3Os.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/V3Os.cpp b/src/V3Os.cpp index b6d2be2a0..9286a00d1 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -318,9 +318,7 @@ void V3Os::filesystemFlushBuildDir(const string& dirname) { // Attempt to force out written directory, for NFS like file systems. #if !defined(_MSC_VER) && !defined(__MINGW32__) // Linux kernel may not reread from NFS unless timestamp modified - struct timeval tv; - gettimeofday(&tv, NULL); - const int err = utimes(dirname.c_str(), &tv); + const int err = utimes(dirname.c_str(), nullptr); // Not an error if (err != 0) UINFO(1, "-Info: File not utimed: " << dirname << endl); #endif From f80c167d65b284ea03835d3a5a0e3584b7c95377 Mon Sep 17 00:00:00 2001 From: Anthony Donlon <4056887+donlon@users.noreply.github.com> Date: Thu, 18 Jan 2024 08:30:42 +0800 Subject: [PATCH 035/116] Fix warnings in verilated_sc_trace.h for Clang. No functional change. (#4807) (#4827) --- configure.ac | 1 - include/verilated_sc_trace.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/configure.ac b/configure.ac index 7679d98e6..1aa353ed7 100644 --- a/configure.ac +++ b/configure.ac @@ -424,7 +424,6 @@ m4_foreach([cflag],[ [-Wno-c++11-narrowing], [-Wno-constant-logical-operand], [-Wno-non-pod-varargs], - [-Wno-overloaded-virtual], [-Wno-parentheses-equality], [-Wno-shadow], [-Wno-sign-compare], diff --git a/include/verilated_sc_trace.h b/include/verilated_sc_trace.h index a5d775ee4..f9a25a75c 100644 --- a/include/verilated_sc_trace.h +++ b/include/verilated_sc_trace.h @@ -102,6 +102,8 @@ protected: // Phase callback is automatically unregistered in ~sc_object(). Only the trace file is // needed to be removed here if (m_traceFileAdded) simcontext()->remove_trace_file(this); +#else + (void)m_traceFileAdded; #endif #ifdef _VL_HAVE_SYSTEMC_STAGE_CALLBACK sc_unregister_stage_callback(*this, SC_PRE_TIMESTEP | SC_POST_UPDATE); @@ -184,6 +186,7 @@ private: // SystemC 2.1.v1 void write_comment(const std::string&) override {} + void trace(sc_core::sc_trace_file*) const override {} void trace(const unsigned int&, const std::string&, const char**) override {} #define DECL_TRACE_METHOD_A(tp) \ From 8b03f2d47b0737d4071d07d6494905e603941d5d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 17 Jan 2024 08:28:40 -0500 Subject: [PATCH 036/116] Commentary --- docs/guide/conf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/guide/conf.py b/docs/guide/conf.py index 0bb6097a7..12fd0db39 100644 --- a/docs/guide/conf.py +++ b/docs/guide/conf.py @@ -45,7 +45,7 @@ def setup(app): # -- Project information project = 'Verilator' -copyright = '2022 by Wilson Snyder, under LGPL-3.0 or Artistic-2.0' +copyright = '2024 by Wilson Snyder, under LGPL-3.0 or Artistic-2.0' author = 'Wilson Snyder' # The master toctree document. From 89cfa0737fafb81e91a000a3d328b8f02f2a103e Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 17 Jan 2024 19:48:07 -0500 Subject: [PATCH 037/116] Internals: Fix cppcheck warnings --- Makefile.in | 2 +- include/verilated.cpp | 2 +- include/verilated_vpi.cpp | 16 ++++++++-------- src/V3Ast.cpp | 4 +++- src/V3Ast.h | 1 + src/V3Const.cpp | 3 +-- src/V3EmitCSyms.cpp | 2 ++ src/V3Gate.cpp | 9 +++++---- src/V3Simulate.h | 8 ++++---- src/V3StackCount.cpp | 2 +- src/V3TraceDecl.cpp | 5 ++--- src/V3Width.cpp | 4 +--- 12 files changed, 30 insertions(+), 28 deletions(-) diff --git a/Makefile.in b/Makefile.in index 205c912d9..312eccb6a 100644 --- a/Makefile.in +++ b/Makefile.in @@ -340,7 +340,7 @@ CPPCHECK_FLAGS = --enable=all --inline-suppr \ --suppress=useStlAlgorithm CPPCHECK_FLAGS += --xml CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CHECK_CPP)) -CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src +CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/include/gtkwave -I$(srcdir)/include/vltstd -I$(srcdir)/src/obj_dbg -I$(srcdir)/src cppcheck: cppcheck-1 cppcheck-2 cppcheck-3 cppcheck-4 cppcheck-5 cppcheck-6 cppcheck-7 cppcheck-8 cppcheck-1: diff --git a/include/verilated.cpp b/include/verilated.cpp index 3ce0fe4da..73d3cee4f 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2693,7 +2693,7 @@ std::pair VerilatedContextImp::argc_argv() VL_MT_SAFE_EXCLUDES(m_ar int in = 0; for (const auto& i : m_args.m_argVec) { s_argvp[in] = new char[i.length() + 1]; - std::strcpy(s_argvp[in], i.c_str()); + std::memcpy(s_argvp[in], i.c_str(), i.length() + 1); ++in; } s_argvp[s_argc] = nullptr; diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 03ad2abe9..151393cf9 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -507,9 +507,9 @@ public: delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle return nullptr; } - const VerilatedScope::Type type = (*m_it)->type(); + const VerilatedScope::Type itype = (*m_it)->type(); const VerilatedScope* const modp = *m_it++; - if (type == VerilatedScope::SCOPE_MODULE) { + if (itype == VerilatedScope::SCOPE_MODULE) { return (new VerilatedVpioModule{modp})->castVpiHandle(); } } @@ -523,9 +523,9 @@ class VerilatedVpioPackage final : public VerilatedVpioScope { public: explicit VerilatedVpioPackage(const VerilatedScope* modulep) : VerilatedVpioScope{modulep} { - const char* fullname = m_scopep->name(); - if (std::strncmp(fullname, "TOP.", 4) == 0) fullname += 4; - m_fullname = std::string{fullname} + "::"; + const char* sfullname = m_scopep->name(); + if (std::strncmp(sfullname, "TOP.", 4) == 0) sfullname += 4; + m_fullname = std::string{sfullname} + "::"; if (m_fullname == "\\$unit ::") m_fullname = "$unit::"; m_name = std::string(m_scopep->identifier()); if (m_name == "\\$unit ") m_name = "$unit"; @@ -558,12 +558,12 @@ public: delete this; // IEEE 37.2.2 vpi_scan at end does a vpi_release_handle return nullptr; } - const VerilatedScope::Type type = (*m_it)->type(); + const VerilatedScope::Type itype = (*m_it)->type(); const VerilatedScope* const modp = *m_it++; - if (type == VerilatedScope::SCOPE_MODULE) { + if (itype == VerilatedScope::SCOPE_MODULE) { return (new VerilatedVpioModule{modp})->castVpiHandle(); } - if (type == VerilatedScope::SCOPE_PACKAGE) { + if (itype == VerilatedScope::SCOPE_PACKAGE) { return (new VerilatedVpioPackage{modp})->castVpiHandle(); } } diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index 1948e60ff..8dc5b7565 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -1116,6 +1116,7 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { // private: Check a tree and children UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent"); + // cppcheck-suppress danglingTempReference const VNTypeInfo& typeInfo = *type().typeInfo(); for (int i = 1; i <= 4; i++) { AstNode* nodep = nullptr; @@ -1126,6 +1127,7 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { case 4: nodep = op4p(); break; default: this->v3fatalSrc("Bad case"); break; } + // cppcheck-suppress danglingTempReference const char* opName = typeInfo.m_opNamep[i - 1]; switch (typeInfo.m_opType[i - 1]) { case VNTypeInfo::OP_UNUSED: @@ -1142,7 +1144,7 @@ void AstNode::checkTreeIter(const AstNode* prevBackp) const VL_MT_STABLE { case VNTypeInfo::OP_LIST: if (const AstNode* const headp = nodep) { const AstNode* backp = this; - const AstNode* tailp = headp; + const AstNode* tailp; const AstNode* opp = headp; do { opp->checkTreeIter(backp); diff --git a/src/V3Ast.h b/src/V3Ast.h index 71ec84aa0..af40b6ad9 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -125,6 +125,7 @@ public: constexpr VNType(en _e) VL_MT_SAFE : m_e{_e} {} explicit VNType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning + // cppcheck-suppress danglingTempReference const VNTypeInfo* typeInfo() const VL_MT_SAFE { return &typeInfoTable[m_e]; } constexpr operator en() const VL_MT_SAFE { return m_e; } }; diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 397324ed1..0b12137e1 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -542,9 +542,8 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { restorer.disableRestore(); // Now all checks passed } else if (nodep->type() == m_rootp->type()) { // And, Or, Xor incrOps(nodep, __LINE__); - VL_RESTORER(m_leafp); - for (const bool right : {false, true}) { + VL_RESTORER(m_leafp); Restorer restorer{*this}; LeafInfo leafInfo{m_lsb}; m_leafp = &leafInfo; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index 217645f73..a2c253150 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -237,6 +237,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { // << scpSym << endl); if (v3Global.opt.vpi()) varHierarchyScopes(scpName); if (m_scopeNames.find(scpSym) == m_scopeNames.end()) { + // cppcheck-suppress stlFindInsert m_scopeNames.emplace(scpSym, ScopeData{scpSym, scpPretty, 0, "SCOPE_OTHER"}); } @@ -341,6 +342,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { ScopeFuncData(nodep, m_cfuncp, m_modp)); } else { if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) { + // cppcheck-suppress stlFindInsert m_scopeNames.emplace(nodep->scopeDpiName(), ScopeData{nodep->scopeDpiName(), nodep->scopePrettyDpiName(), timeunit, "SCOPE_OTHER"}); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 2e2976ff9..a25d7feea 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -48,7 +48,7 @@ class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex { bool m_dedupable = true; // True if this node should be able to be deduped bool m_consumed = false; // Output goes to something meaningful public: - GateEitherVertex(V3Graph* graphp) + explicit GateEitherVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} ~GateEitherVertex() override = default; @@ -811,8 +811,9 @@ class GateInline final { // If the consumer logic writes one of the variables that the substitution // is reading, then we would get a cycles, so we cannot do that. bool canInline = true; - for (V3GraphEdge* edgep = dstVtxp->outBeginp(); edgep; edgep = edgep->outNextp()) { - const GateVarVertex* const consVVertexp = edgep->top()->as(); + for (V3GraphEdge* dedgep = dstVtxp->outBeginp(); dedgep; + dedgep = dedgep->outNextp()) { + const GateVarVertex* const consVVertexp = dedgep->top()->as(); if (readVscps.count(consVVertexp->varScp())) { canInline = false; break; @@ -1327,7 +1328,7 @@ class GateUnused final { } } - GateUnused(GateGraph& graph) + explicit GateUnused(GateGraph& graph) : m_graph{graph} { mark(); // Mark all used vertices remove(); // Remove unused vertices diff --git a/src/V3Simulate.h b/src/V3Simulate.h index b9c4c80ab..42f1b4009 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -456,12 +456,12 @@ private: clearOptimizable(nodep, "Var write & read"); } m_varAux(vscp).usage |= VU_RV; - const bool isConst = (nodep->varp()->isConst() || nodep->varp()->isParam()) - && nodep->varp()->valuep(); + const bool varIsConst = (nodep->varp()->isConst() || nodep->varp()->isParam()) + && nodep->varp()->valuep(); AstNodeExpr* const valuep - = isConst ? fetchValueNull(nodep->varp()->valuep()) : nullptr; + = varIsConst ? fetchValueNull(nodep->varp()->valuep()) : nullptr; // Propagate PARAM constants for constant function analysis - if (isConst && valuep) { + if (varIsConst && valuep) { if (!m_checkOnly && optimizable()) newValue(vscp, valuep); } else { if (m_checkOnly) varRefCb(nodep); diff --git a/src/V3StackCount.cpp b/src/V3StackCount.cpp index f500b8602..19850cd27 100644 --- a/src/V3StackCount.cpp +++ b/src/V3StackCount.cpp @@ -58,7 +58,7 @@ class StackCountVisitor final : public VNVisitorConst { public: // CONSTRUCTORS - StackCountVisitor(AstNode* nodep) { iterateConstNull(nodep); } + explicit StackCountVisitor(AstNode* nodep) { iterateConstNull(nodep); } ~StackCountVisitor() override = default; // METHODS diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index 63302b5c2..088573c84 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -391,9 +391,8 @@ class TraceDeclVisitor final : public VNVisitor { } else { // This is a subscope: insert a placeholder to be fixed up later AstCell* const cellp = entry.cellp(); - FileLine* const flp = cellp->fileline(); - AstNodeStmt* const stmtp - = new AstComment{flp, "Cell init for: " + cellp->prettyName()}; + AstNodeStmt* const stmtp = new AstComment{ + cellp->fileline(), "Cell init for: " + cellp->prettyName()}; addToSubFunc(stmtp); m_cellInitPlaceholders.emplace_back(nodep, cellp, stmtp); } diff --git a/src/V3Width.cpp b/src/V3Width.cpp index d6cfaae8f..373233981 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -4411,10 +4411,8 @@ class WidthVisitor final : public VNVisitor { static bool usesDynamicScheduler(AstNode* nodep) { UASSERT_OBJ(nodep->dtypep()->isEvent(), nodep, "Node does not have an event dtype"); - - AstVarRef* vrefp; while (true) { - vrefp = VN_CAST(nodep, VarRef); + AstVarRef* const vrefp = VN_CAST(nodep, VarRef); if (vrefp) return usesDynamicScheduler(vrefp); if (VN_IS(nodep, MemberSel)) { return true; From c30b9d04a85a634f4dcab959749825156e8d5369 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 08:57:22 -0500 Subject: [PATCH 038/116] Change unused vars to standard void syntax. No functional change intended. --- examples/make_tracing_c/sim_main.cpp | 3 --- examples/make_tracing_sc/sc_main.cpp | 3 --- src/V3File.cpp | 5 +++-- src/VlcTop.cpp | 5 ++--- test_regress/driver.pl | 2 +- 5 files changed, 6 insertions(+), 12 deletions(-) diff --git a/examples/make_tracing_c/sim_main.cpp b/examples/make_tracing_c/sim_main.cpp index a49225cdc..69f99cae2 100644 --- a/examples/make_tracing_c/sim_main.cpp +++ b/examples/make_tracing_c/sim_main.cpp @@ -20,9 +20,6 @@ double sc_time_stamp() { return 0; } int main(int argc, char** argv) { // This is a more complicated example, please also see the simpler examples/make_hello_c. - // Prevent unused variable warnings - if (false && argc && argv) {} - // Create logs/ directory in case we have traces to put under it Verilated::mkdir("logs"); diff --git a/examples/make_tracing_sc/sc_main.cpp b/examples/make_tracing_sc/sc_main.cpp index 59f1a55a4..208d4e43d 100644 --- a/examples/make_tracing_sc/sc_main.cpp +++ b/examples/make_tracing_sc/sc_main.cpp @@ -29,9 +29,6 @@ using namespace sc_dt; int sc_main(int argc, char* argv[]) { // This is a more complicated example, please also see the simpler examples/make_hello_c. - // Prevent unused variable warnings - if (false && argc && argv) {} - // Create logs/ directory in case we have traces to put under it Verilated::mkdir("logs"); diff --git a/src/V3File.cpp b/src/V3File.cpp index 4db49c97a..07486c3fb 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -361,7 +361,8 @@ private: return true; } bool readContentsFilter(const string& filename, StrList& outl) { - if (filename != "" || outl.empty()) {} // Prevent unused + (void)filename; // Prevent unused variable warning + (void)outl; // Prevent unused variable warning #ifdef INFILTER_PIPE writeFilter("read \"" + filename + "\"\n"); const string line = readFilterLine(); @@ -484,7 +485,7 @@ private: } } void startFilter(const string& command) { - if (command == "") {} // Prevent Unused + (void)command; // Prevent Unused variable warning #ifdef INFILTER_PIPE int fd_stdin[2]; // Can't use std::array int fd_stdout[2]; // Can't use std::array diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index 60ea127ac..7d9c83659 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -51,11 +51,10 @@ void VlcTop::readCoverage(const string& filename, bool nonfatal) { if (line[secspace] == '\'' && line[secspace + 1] == ' ') break; } const string point = line.substr(3, secspace - 3); - uint64_t hits = std::atoll(line.c_str() + secspace + 1); + const uint64_t hits = std::atoll(line.c_str() + secspace + 1); // UINFO(9," point '"<= VlcBuckets::sufficient()) { points().pointNumber(pointnum).testsCoveringInc(); diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 692d6fd89..6bc4172de 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1883,7 +1883,7 @@ sub _make_main { print $fh " srand48(5);\n"; # Ensure determinism print $fh " contextp->randReset(" . $self->{verilated_randReset} . ");\n" if defined $self->{verilated_randReset}; - print $fh " topp.reset(new ${vm_prefix}(\"top\"));\n"; + print $fh " topp.reset(new ${vm_prefix}{\"top\"});\n"; print $fh " contextp->internalsDump()\n;" if $self->{verilated_debug}; my $set; From fef0502d50b950137c4b4db8445adc130a223eeb Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 10:17:35 -0500 Subject: [PATCH 039/116] Tests: Imply make_main=>0 on --main tests --- test_regress/driver.pl | 37 ++++++++++++------- test_regress/t/t_assigndly_dynamic.pl | 2 - test_regress/t/t_clocking_empty_block.pl | 1 - test_regress/t/t_clocking_timing1.pl | 1 - test_regress/t/t_clocking_timing2.pl | 1 - test_regress/t/t_cxx_equal_to.pl | 1 - test_regress/t/t_delay_var.pl | 1 - test_regress/t/t_disable_fork1.pl | 1 - test_regress/t/t_disable_fork2.pl | 1 - test_regress/t/t_disable_fork3.pl | 1 - test_regress/t/t_display_impure.pl | 1 - test_regress/t/t_event_control_pass.pl | 1 - test_regress/t/t_flag_binary.pl | 1 - test_regress/t/t_flag_main.pl | 1 - test_regress/t/t_flag_main_sc_bad.pl | 1 - test_regress/t/t_flag_prefix.pl | 1 - .../t/t_fork_block_item_declaration.pl | 1 - test_regress/t/t_fork_dynscope.pl | 1 - test_regress/t/t_fork_initial.pl | 1 - test_regress/t/t_fork_join_none_class_cap.pl | 1 - test_regress/t/t_fork_jumpblock.pl | 1 - test_regress/t/t_fork_none_var.pl | 1 - test_regress/t/t_fork_output_arg.pl | 1 - test_regress/t/t_interface_virtual_timing.pl | 1 - .../t/t_jumps_uninit_destructor_call.pl | 1 - test_regress/t/t_lint_infinite.pl | 1 - test_regress/t/t_mailbox.pl | 1 - test_regress/t/t_mailbox_notiming.pl | 1 - test_regress/t/t_mailbox_std.pl | 1 - test_regress/t/t_mailbox_unbounded.pl | 1 - test_regress/t/t_process_propagation.pl | 1 - test_regress/t/t_process_task.pl | 1 - test_regress/t/t_semaphore.pl | 1 - test_regress/t/t_semaphore_std.pl | 1 - test_regress/t/t_stack_check.pl | 1 - test_regress/t/t_std_process_self.pl | 2 - test_regress/t/t_stream5.pl | 1 - test_regress/t/t_time.pl | 1 - test_regress/t/t_timing_always.pl | 1 - test_regress/t/t_timing_class.pl | 1 - test_regress/t/t_timing_class_static_delay.pl | 1 - test_regress/t/t_timing_clkgen1.pl | 1 - test_regress/t/t_timing_clkgen2.pl | 1 - test_regress/t/t_timing_clkgen3.pl | 1 - test_regress/t/t_timing_debug1.pl | 1 - test_regress/t/t_timing_debug2.pl | 1 - test_regress/t/t_timing_delay_callstack.pl | 1 - test_regress/t/t_timing_dlyassign.pl | 1 - test_regress/t/t_timing_dynscope.pl | 1 - test_regress/t/t_timing_events.pl | 1 - test_regress/t/t_timing_fork_comb.pl | 1 - test_regress/t/t_timing_fork_join.pl | 1 - test_regress/t/t_timing_fork_join_forkproc.pl | 1 - test_regress/t/t_timing_fork_many.pl | 1 - .../t/t_timing_fork_no_timing_ctrl.pl | 1 - test_regress/t/t_timing_fork_rec_method.pl | 1 - test_regress/t/t_timing_fork_taskcall.pl | 1 - test_regress/t/t_timing_intra_assign.pl | 2 - test_regress/t/t_timing_long.pl | 2 - test_regress/t/t_timing_nba.pl | 1 - test_regress/t/t_timing_off.pl | 1 - test_regress/t/t_timing_pong.pl | 1 - test_regress/t/t_timing_protect.pl | 1 - test_regress/t/t_timing_reentry.pl | 1 - test_regress/t/t_timing_sched.pl | 1 - test_regress/t/t_timing_sched_if.pl | 1 - test_regress/t/t_timing_sched_nba.pl | 1 - test_regress/t/t_timing_strobe.pl | 1 - test_regress/t/t_timing_timescale.pl | 1 - test_regress/t/t_timing_trace.pl | 1 - test_regress/t/t_timing_trace_fst.pl | 1 - test_regress/t/t_timing_wait1.pl | 1 - test_regress/t/t_timing_wait2.pl | 1 - test_regress/t/t_timing_wait3.pl | 1 - test_regress/t/t_timing_wait_long.pl | 1 - test_regress/t/t_timing_zerodly.pl | 1 - test_regress/t/t_timing_zerodly_unsup.pl | 1 - test_regress/t/t_trace_binary.pl | 1 - test_regress/t/t_trace_binary_flag_off.pl | 1 - test_regress/t/t_trace_param_override.pl | 1 - .../t/t_trace_ub_misaligned_address.pl | 1 - .../t/t_var_extern_method_lifetime.pl | 1 - test_regress/t/t_virtual_interface_method.pl | 1 - test_regress/t/t_vlt_timing.pl | 1 - test_regress/t/t_wait_fork.pl | 1 - 85 files changed, 23 insertions(+), 102 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 6bc4172de..7c7e5692d 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -910,6 +910,19 @@ sub clean_objs { system("rm", "-rf", glob("$self->{obj_dir}/*")); } +sub _checkflags { + my $self = shift; + my %param = (@_); + my $checkflags = (' '.join(' ', + @{$param{v_flags}}, + @{$param{v_flags2}}, + @{$param{verilator_flags}}, + @{$param{verilator_flags2}}, + @{$param{verilator_flags3}}) + .' '); + return $checkflags; +} + sub compile_vlt_cmd { my $self = (ref $_[0] ? shift : $Self); my %param = (%{$self}, # Default arguments are from $self @@ -918,7 +931,7 @@ sub compile_vlt_cmd { my @vlt_cmd = ( "perl", "$ENV{VERILATOR_ROOT}/bin/verilator", - $self->compile_vlt_flags(%param), + $self->_compile_vlt_flags(%param), $param{top_filename}, @{$param{v_other_filenames}}, $param{stdout_filename} ? "> " . $param{stdout_filename} : "" @@ -926,19 +939,12 @@ sub compile_vlt_cmd { return @vlt_cmd; } -sub compile_vlt_flags { - my $self = (ref $_[0] ? shift : $Self); - my %param = (%{$self}, # Default arguments are from $self - @_); # Supports arbitrary arguments +sub _compile_vlt_flags { + my $self = shift; + my %param = (@_); # Supports arbitrary arguments from compile_vlt_cmd return 1 if $self->errors || $self->skips; - my $checkflags = (' '.join(' ', - @{$param{v_flags}}, - @{$param{v_flags2}}, - @{$param{verilator_flags}}, - @{$param{verilator_flags2}}, - @{$param{verilator_flags3}}) - .' '); + my $checkflags = $self->_checkflags(%param); die "%Error: specify threads via 'threads =>' argument, not as a command line option" unless ($checkflags !~ /(^|\s)-?-threads\s/); $self->{coverage} = 1 if ($checkflags =~ /-coverage\b/); $self->{savable} = 1 if ($checkflags =~ /-savable\b/); @@ -1013,12 +1019,15 @@ sub compile { die "%Error: 'threads =>' argument must be <= 1 for vlt scenario" if $param{vlt} && $param{threads} > 1; # Compute automatic parameter values + my $checkflags = $self->_checkflags(%param); $param{threads} = ::calc_threads($Vltmt_threads) if $param{threads} < 0 && $param{vltmt}; $param{context_threads} = $param{threads} >= 1 ? $param{threads} : 1 if !$param{context_threads}; + $param{make_main} = 0 if ($checkflags =~ / -?-main\b/ || $checkflags =~ / -?-binary\b/); + $self->{threads} = $param{threads}; $self->{context_threads} = $param{context_threads}; - compile_vlt_cmd(%param); + $self->compile_vlt_cmd(%param); my $define_opt = defineOpt($self->{xsim}); if (join(' ', @{$self->{v_flags}}) !~ /TEST_DUMPFILE/) { @@ -1188,7 +1197,7 @@ sub compile { } if ($param{verilator_make_cmake}) { - my @vlt_args = $self->compile_vlt_flags(%param); + my @vlt_args = $self->_compile_vlt_flags(%param); $self->oprint("Running cmake\n") if $self->{verbose}; mkdir $self->{obj_dir}; my @csources = (); diff --git a/test_regress/t/t_assigndly_dynamic.pl b/test_regress/t/t_assigndly_dynamic.pl index 3576e3ffb..270c8b710 100755 --- a/test_regress/t/t_assigndly_dynamic.pl +++ b/test_regress/t/t_assigndly_dynamic.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( @@ -21,7 +20,6 @@ execute( compile( verilator_flags2 => ["--exe --main --timing +define+WITH_DELAY"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_clocking_empty_block.pl b/test_regress/t/t_clocking_empty_block.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_clocking_empty_block.pl +++ b/test_regress/t/t_clocking_empty_block.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_clocking_timing1.pl b/test_regress/t/t_clocking_timing1.pl index 671334c7d..fbcaf794f 100755 --- a/test_regress/t/t_clocking_timing1.pl +++ b/test_regress/t/t_clocking_timing1.pl @@ -14,7 +14,6 @@ top_filename("t/t_clocking_timing.v"); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_clocking_timing2.pl b/test_regress/t/t_clocking_timing2.pl index ad6f5308f..d5e2d9864 100755 --- a/test_regress/t/t_clocking_timing2.pl +++ b/test_regress/t/t_clocking_timing2.pl @@ -14,7 +14,6 @@ top_filename("t/t_clocking_timing.v"); compile( verilator_flags2 => ["--exe --main --timing -DTEST_INPUT_SKEW=12 -DTEST_OUTPUT_SKEW=16"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_cxx_equal_to.pl b/test_regress/t/t_cxx_equal_to.pl index efd6274f5..d0f124208 100755 --- a/test_regress/t/t_cxx_equal_to.pl +++ b/test_regress/t/t_cxx_equal_to.pl @@ -16,7 +16,6 @@ compile( verilator_flags2 => ['--binary --timing --trace'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_delay_var.pl b/test_regress/t/t_delay_var.pl index 0b10f155d..c8f2eacfe 100755 --- a/test_regress/t/t_delay_var.pl +++ b/test_regress/t/t_delay_var.pl @@ -12,7 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_disable_fork1.pl b/test_regress/t/t_disable_fork1.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_disable_fork1.pl +++ b/test_regress/t/t_disable_fork1.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_disable_fork2.pl b/test_regress/t/t_disable_fork2.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_disable_fork2.pl +++ b/test_regress/t/t_disable_fork2.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_disable_fork3.pl b/test_regress/t/t_disable_fork3.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_disable_fork3.pl +++ b/test_regress/t/t_disable_fork3.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_display_impure.pl b/test_regress/t/t_display_impure.pl index 61f6d3396..576ac0d3d 100755 --- a/test_regress/t/t_display_impure.pl +++ b/test_regress/t/t_display_impure.pl @@ -12,7 +12,6 @@ scenarios(linter => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_event_control_pass.pl b/test_regress/t/t_event_control_pass.pl index 2f8329791..0cb201e30 100755 --- a/test_regress/t/t_event_control_pass.pl +++ b/test_regress/t/t_event_control_pass.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, threads => 1, ); diff --git a/test_regress/t/t_flag_binary.pl b/test_regress/t/t_flag_binary.pl index e810b1eb6..bf2dc801d 100755 --- a/test_regress/t/t_flag_binary.pl +++ b/test_regress/t/t_flag_binary.pl @@ -19,7 +19,6 @@ compile( verilator_flags2 => ['--binary'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index 57041562f..f279e8a2e 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -17,7 +17,6 @@ compile( verilator_flags2 => ['--exe --build --main'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, # Check that code --main produces uses only most modern API features make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY', ); diff --git a/test_regress/t/t_flag_main_sc_bad.pl b/test_regress/t/t_flag_main_sc_bad.pl index 8c8eb97ca..94fd1dce7 100755 --- a/test_regress/t/t_flag_main_sc_bad.pl +++ b/test_regress/t/t_flag_main_sc_bad.pl @@ -14,7 +14,6 @@ compile( verilator_flags2 => ['--exe --build --main --sc'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_flag_prefix.pl b/test_regress/t/t_flag_prefix.pl index adcce742d..940ddc16b 100755 --- a/test_regress/t/t_flag_prefix.pl +++ b/test_regress/t/t_flag_prefix.pl @@ -16,7 +16,6 @@ compile( "--exe", "--main", "--stats", "--build"], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_block_item_declaration.pl b/test_regress/t/t_fork_block_item_declaration.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_fork_block_item_declaration.pl +++ b/test_regress/t/t_fork_block_item_declaration.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_dynscope.pl b/test_regress/t/t_fork_dynscope.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_fork_dynscope.pl +++ b/test_regress/t/t_fork_dynscope.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_initial.pl b/test_regress/t/t_fork_initial.pl index c78ec8a58..7751e4fe8 100755 --- a/test_regress/t/t_fork_initial.pl +++ b/test_regress/t/t_fork_initial.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, # issue #4471 - remove this verilator_make_gmake => 0, ); diff --git a/test_regress/t/t_fork_join_none_class_cap.pl b/test_regress/t/t_fork_join_none_class_cap.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_fork_join_none_class_cap.pl +++ b/test_regress/t/t_fork_join_none_class_cap.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_jumpblock.pl b/test_regress/t/t_fork_jumpblock.pl index bc632ee01..a1cdcff37 100755 --- a/test_regress/t/t_fork_jumpblock.pl +++ b/test_regress/t/t_fork_jumpblock.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_none_var.pl b/test_regress/t/t_fork_none_var.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_fork_none_var.pl +++ b/test_regress/t/t_fork_none_var.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_fork_output_arg.pl b/test_regress/t/t_fork_output_arg.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_fork_output_arg.pl +++ b/test_regress/t/t_fork_output_arg.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_interface_virtual_timing.pl b/test_regress/t/t_interface_virtual_timing.pl index 0da9620d1..30ef08a9e 100755 --- a/test_regress/t/t_interface_virtual_timing.pl +++ b/test_regress/t/t_interface_virtual_timing.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_jumps_uninit_destructor_call.pl b/test_regress/t/t_jumps_uninit_destructor_call.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_jumps_uninit_destructor_call.pl +++ b/test_regress/t/t_jumps_uninit_destructor_call.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_lint_infinite.pl b/test_regress/t/t_lint_infinite.pl index 3364f1ed7..7964ebe90 100755 --- a/test_regress/t/t_lint_infinite.pl +++ b/test_regress/t/t_lint_infinite.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_mailbox.pl b/test_regress/t/t_mailbox.pl index 30306c8ce..41f6e2a53 100755 --- a/test_regress/t/t_mailbox.pl +++ b/test_regress/t/t_mailbox.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wall"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_mailbox_notiming.pl b/test_regress/t/t_mailbox_notiming.pl index fb7f3e881..70368f851 100755 --- a/test_regress/t/t_mailbox_notiming.pl +++ b/test_regress/t/t_mailbox_notiming.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --no-timing -Wall"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_mailbox_std.pl b/test_regress/t/t_mailbox_std.pl index 31b9a5203..8f575f2f2 100755 --- a/test_regress/t/t_mailbox_std.pl +++ b/test_regress/t/t_mailbox_std.pl @@ -14,7 +14,6 @@ top_filename("t/t_mailbox.v"); compile( verilator_flags2 => ["--exe --main --timing -Wall --Wpedantic -DMAILBOX_T=std::mailbox"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_mailbox_unbounded.pl b/test_regress/t/t_mailbox_unbounded.pl index 30306c8ce..41f6e2a53 100755 --- a/test_regress/t/t_mailbox_unbounded.pl +++ b/test_regress/t/t_mailbox_unbounded.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wall"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_process_propagation.pl b/test_regress/t/t_process_propagation.pl index 3364f1ed7..7964ebe90 100755 --- a/test_regress/t/t_process_propagation.pl +++ b/test_regress/t/t_process_propagation.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_process_task.pl b/test_regress/t/t_process_task.pl index 123e2f4fd..ef9cff8c5 100755 --- a/test_regress/t/t_process_task.pl +++ b/test_regress/t/t_process_task.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( v_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_semaphore.pl b/test_regress/t/t_semaphore.pl index 30306c8ce..41f6e2a53 100755 --- a/test_regress/t/t_semaphore.pl +++ b/test_regress/t/t_semaphore.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wall"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_semaphore_std.pl b/test_regress/t/t_semaphore_std.pl index 47041497b..39236c3d4 100755 --- a/test_regress/t/t_semaphore_std.pl +++ b/test_regress/t/t_semaphore_std.pl @@ -14,7 +14,6 @@ top_filename("t/t_semaphore.v"); compile( verilator_flags2 => ["--exe --main --timing -Wall -DSEMAPHORE_T=std::semaphore"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_stack_check.pl b/test_regress/t/t_stack_check.pl index 8c196698f..0c61fa4eb 100755 --- a/test_regress/t/t_stack_check.pl +++ b/test_regress/t/t_stack_check.pl @@ -14,7 +14,6 @@ compile( verilator_flags2 => ['--binary --debug-stack-check'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute(); diff --git a/test_regress/t/t_std_process_self.pl b/test_regress/t/t_std_process_self.pl index 5b73c5ff4..80841859b 100755 --- a/test_regress/t/t_std_process_self.pl +++ b/test_regress/t/t_std_process_self.pl @@ -12,12 +12,10 @@ scenarios(simulator => 1); lint( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); lint( verilator_flags2 => ["--exe --main --timing --DUSE_STD_PREFIX"], - make_main => 0, ); ok(1); diff --git a/test_regress/t/t_stream5.pl b/test_regress/t/t_stream5.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_stream5.pl +++ b/test_regress/t/t_stream5.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_time.pl b/test_regress/t/t_time.pl index 0db50fc52..47728df81 100755 --- a/test_regress/t/t_time.pl +++ b/test_regress/t/t_time.pl @@ -12,7 +12,6 @@ scenarios(linter => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_always.pl b/test_regress/t/t_timing_always.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_always.pl +++ b/test_regress/t/t_timing_always.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_class.pl b/test_regress/t/t_timing_class.pl index 002312d88..ed3bac458 100755 --- a/test_regress/t/t_timing_class.pl +++ b/test_regress/t/t_timing_class.pl @@ -12,7 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_class_static_delay.pl b/test_regress/t/t_timing_class_static_delay.pl index 002312d88..ed3bac458 100755 --- a/test_regress/t/t_timing_class_static_delay.pl +++ b/test_regress/t/t_timing_class_static_delay.pl @@ -12,7 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_clkgen1.pl b/test_regress/t/t_timing_clkgen1.pl index edbe747b4..a4a48a187 100755 --- a/test_regress/t/t_timing_clkgen1.pl +++ b/test_regress/t/t_timing_clkgen1.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wno-MINTYPMAXDLY"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_clkgen2.pl b/test_regress/t/t_timing_clkgen2.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_clkgen2.pl +++ b/test_regress/t/t_timing_clkgen2.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_clkgen3.pl b/test_regress/t/t_timing_clkgen3.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_clkgen3.pl +++ b/test_regress/t/t_timing_clkgen3.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_debug1.pl b/test_regress/t/t_timing_debug1.pl index 06be36082..61ae92cc7 100755 --- a/test_regress/t/t_timing_debug1.pl +++ b/test_regress/t/t_timing_debug1.pl @@ -14,7 +14,6 @@ top_filename("t/t_timing_sched.v"); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_debug2.pl b/test_regress/t/t_timing_debug2.pl index 4ff0b44ea..aa8ec9485 100755 --- a/test_regress/t/t_timing_debug2.pl +++ b/test_regress/t/t_timing_debug2.pl @@ -14,7 +14,6 @@ top_filename("t/t_timing_class.v"); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_delay_callstack.pl b/test_regress/t/t_timing_delay_callstack.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_delay_callstack.pl +++ b/test_regress/t/t_timing_delay_callstack.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_dlyassign.pl b/test_regress/t/t_timing_dlyassign.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_dlyassign.pl +++ b/test_regress/t/t_timing_dlyassign.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_dynscope.pl b/test_regress/t/t_timing_dynscope.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_dynscope.pl +++ b/test_regress/t/t_timing_dynscope.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_events.pl b/test_regress/t/t_timing_events.pl index 002312d88..ed3bac458 100755 --- a/test_regress/t/t_timing_events.pl +++ b/test_regress/t/t_timing_events.pl @@ -12,7 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_comb.pl b/test_regress/t/t_timing_fork_comb.pl index ac0e116ba..c9e9158e8 100755 --- a/test_regress/t/t_timing_fork_comb.pl +++ b/test_regress/t/t_timing_fork_comb.pl @@ -20,7 +20,6 @@ compile( compile( verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_join.pl b/test_regress/t/t_timing_fork_join.pl index 3feb337e3..f686c3eec 100755 --- a/test_regress/t/t_timing_fork_join.pl +++ b/test_regress/t/t_timing_fork_join.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_join_forkproc.pl b/test_regress/t/t_timing_fork_join_forkproc.pl index 61664fabe..e6d59ea75 100755 --- a/test_regress/t/t_timing_fork_join_forkproc.pl +++ b/test_regress/t/t_timing_fork_join_forkproc.pl @@ -14,7 +14,6 @@ top_filename("t/t_timing_fork_join.v"); compile( verilator_flags2 => ["--exe --main --timing --ftaskify-all-forked"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_many.pl b/test_regress/t/t_timing_fork_many.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_fork_many.pl +++ b/test_regress/t/t_timing_fork_many.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_no_timing_ctrl.pl b/test_regress/t/t_timing_fork_no_timing_ctrl.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_fork_no_timing_ctrl.pl +++ b/test_regress/t/t_timing_fork_no_timing_ctrl.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_rec_method.pl b/test_regress/t/t_timing_fork_rec_method.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_fork_rec_method.pl +++ b/test_regress/t/t_timing_fork_rec_method.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_fork_taskcall.pl b/test_regress/t/t_timing_fork_taskcall.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_fork_taskcall.pl +++ b/test_regress/t/t_timing_fork_taskcall.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_intra_assign.pl b/test_regress/t/t_timing_intra_assign.pl index fabe5ebc4..f625618ab 100755 --- a/test_regress/t/t_timing_intra_assign.pl +++ b/test_regress/t/t_timing_intra_assign.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT"], - make_main => 0, ); execute( @@ -22,7 +21,6 @@ execute( compile( verilator_flags2 => ["--exe --main --timing -Wno-UNOPTFLAT -fno-localize"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_long.pl b/test_regress/t/t_timing_long.pl index 834a8c4f5..2c5c9595e 100755 --- a/test_regress/t/t_timing_long.pl +++ b/test_regress/t/t_timing_long.pl @@ -59,7 +59,6 @@ if ($Self->have_coroutines) { verilator_flags2 => ["--exe --build --main --tim" . "ing"], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, make_top => 1, ); @@ -72,7 +71,6 @@ compile( verilator_flags2 => ["--exe --build --main --no-timing -Wno-STMTDLY"], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, make_top => 1, ); diff --git a/test_regress/t/t_timing_nba.pl b/test_regress/t/t_timing_nba.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_nba.pl +++ b/test_regress/t/t_timing_nba.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_off.pl b/test_regress/t/t_timing_off.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_off.pl +++ b/test_regress/t/t_timing_off.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_pong.pl b/test_regress/t/t_timing_pong.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_pong.pl +++ b/test_regress/t/t_timing_pong.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_protect.pl b/test_regress/t/t_timing_protect.pl index bd2ed322d..84a4c7ce0 100755 --- a/test_regress/t/t_timing_protect.pl +++ b/test_regress/t/t_timing_protect.pl @@ -19,7 +19,6 @@ else { compile( verilator_flags2 => ["--exe --main --timing --protect-ids", "--protect-key SECRET_KEY"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_reentry.pl b/test_regress/t/t_timing_reentry.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_reentry.pl +++ b/test_regress/t/t_timing_reentry.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_sched.pl b/test_regress/t/t_timing_sched.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_sched.pl +++ b/test_regress/t/t_timing_sched.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_sched_if.pl b/test_regress/t/t_timing_sched_if.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_sched_if.pl +++ b/test_regress/t/t_timing_sched_if.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_sched_nba.pl b/test_regress/t/t_timing_sched_nba.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_sched_nba.pl +++ b/test_regress/t/t_timing_sched_nba.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_strobe.pl b/test_regress/t/t_timing_strobe.pl index 3feb337e3..f686c3eec 100755 --- a/test_regress/t/t_timing_strobe.pl +++ b/test_regress/t/t_timing_strobe.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_timescale.pl b/test_regress/t/t_timing_timescale.pl index 3feb337e3..f686c3eec 100755 --- a/test_regress/t/t_timing_timescale.pl +++ b/test_regress/t/t_timing_timescale.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_trace.pl b/test_regress/t/t_timing_trace.pl index 73c643cee..e968634de 100755 --- a/test_regress/t/t_timing_trace.pl +++ b/test_regress/t/t_timing_trace.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing --trace -Wno-MINTYPMAXDLY"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_trace_fst.pl b/test_regress/t/t_timing_trace_fst.pl index 261ee5e84..2e8d5f1f5 100755 --- a/test_regress/t/t_timing_trace_fst.pl +++ b/test_regress/t/t_timing_trace_fst.pl @@ -14,7 +14,6 @@ top_filename("t/t_timing_trace.v"); compile( verilator_flags2 => ["--exe --main --timing --trace-fst -Wno-MINTYPMAXDLY"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_wait1.pl b/test_regress/t/t_timing_wait1.pl index 3508f0a14..3f4a19511 100755 --- a/test_regress/t/t_timing_wait1.pl +++ b/test_regress/t/t_timing_wait1.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing -Wno-WAITCONST"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_wait2.pl b/test_regress/t/t_timing_wait2.pl index 3feb337e3..f686c3eec 100755 --- a/test_regress/t/t_timing_wait2.pl +++ b/test_regress/t/t_timing_wait2.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_wait3.pl b/test_regress/t/t_timing_wait3.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_timing_wait3.pl +++ b/test_regress/t/t_timing_wait3.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_wait_long.pl b/test_regress/t/t_timing_wait_long.pl index 3feb337e3..f686c3eec 100755 --- a/test_regress/t/t_timing_wait_long.pl +++ b/test_regress/t/t_timing_wait_long.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_zerodly.pl b/test_regress/t/t_timing_zerodly.pl index bbc99cfb6..9d615c1c3 100755 --- a/test_regress/t/t_timing_zerodly.pl +++ b/test_regress/t/t_timing_zerodly.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_timing_zerodly_unsup.pl b/test_regress/t/t_timing_zerodly_unsup.pl index 2d852adb1..5439c7838 100755 --- a/test_regress/t/t_timing_zerodly_unsup.pl +++ b/test_regress/t/t_timing_zerodly_unsup.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_trace_binary.pl b/test_regress/t/t_trace_binary.pl index 8304613d5..321b41ed5 100755 --- a/test_regress/t/t_trace_binary.pl +++ b/test_regress/t/t_trace_binary.pl @@ -17,7 +17,6 @@ compile( verilator_flags2 => ['--binary --trace'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_trace_binary_flag_off.pl b/test_regress/t/t_trace_binary_flag_off.pl index 6de81c2ca..4a099bdc7 100755 --- a/test_regress/t/t_trace_binary_flag_off.pl +++ b/test_regress/t/t_trace_binary_flag_off.pl @@ -19,7 +19,6 @@ compile( verilator_flags2 => ['--binary'], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_trace_param_override.pl b/test_regress/t/t_trace_param_override.pl index 4e2cf6e81..51a8874fe 100755 --- a/test_regress/t/t_trace_param_override.pl +++ b/test_regress/t/t_trace_param_override.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --trace -GPOVERRODE=31"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_trace_ub_misaligned_address.pl b/test_regress/t/t_trace_ub_misaligned_address.pl index 83dcf0fb4..bc08c02fe 100755 --- a/test_regress/t/t_trace_ub_misaligned_address.pl +++ b/test_regress/t/t_trace_ub_misaligned_address.pl @@ -18,7 +18,6 @@ compile( "-LDFLAGS -fsanitize=address,undefined"], verilator_make_cmake => 0, verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_var_extern_method_lifetime.pl b/test_regress/t/t_var_extern_method_lifetime.pl index b8493bd06..929ae897c 100755 --- a/test_regress/t/t_var_extern_method_lifetime.pl +++ b/test_regress/t/t_var_extern_method_lifetime.pl @@ -12,7 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_virtual_interface_method.pl b/test_regress/t/t_virtual_interface_method.pl index 2d5085be1..9a53332e0 100755 --- a/test_regress/t/t_virtual_interface_method.pl +++ b/test_regress/t/t_virtual_interface_method.pl @@ -13,7 +13,6 @@ scenarios(simulator => 1); compile( v_flags2 => ["--binary"], verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_vlt_timing.pl b/test_regress/t/t_vlt_timing.pl index d816239d3..78679cf79 100755 --- a/test_regress/t/t_vlt_timing.pl +++ b/test_regress/t/t_vlt_timing.pl @@ -14,7 +14,6 @@ top_filename("t/t_timing_off.v"); compile( verilator_flags2 => ["--exe --main --timing t/t_vlt_timing.vlt"], - make_main => 0, ); execute( diff --git a/test_regress/t/t_wait_fork.pl b/test_regress/t/t_wait_fork.pl index 0db50fc52..47728df81 100755 --- a/test_regress/t/t_wait_fork.pl +++ b/test_regress/t/t_wait_fork.pl @@ -12,7 +12,6 @@ scenarios(linter => 1); compile( verilator_flags2 => ["--exe --main --timing"], - make_main => 0, ); execute( From 375a121377e2e23eb8695ed3599b065a2bbeb04a Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 10:24:54 -0500 Subject: [PATCH 040/116] Tests: Use lint() where able instead of compile(). No functional change intended. --- test_regress/t/t_array_method_bad.pl | 2 +- test_regress/t/t_assert_clock_event_unsup.pl | 2 +- test_regress/t/t_assert_disable_bad.pl | 2 +- test_regress/t/t_assert_imm_nz_bad.pl | 2 +- test_regress/t/t_assert_procedural_clk_bad.pl | 2 +- test_regress/t/t_assert_property_untyped_unsup.pl | 2 +- test_regress/t/t_assert_property_var_unsup.pl | 2 +- test_regress/t/t_assert_recursive_property_unsup.pl | 2 +- test_regress/t/t_assigndly_dynamic_notiming_bad.pl | 2 +- test_regress/t/t_class_assign_bad.pl | 2 +- test_regress/t/t_class_assign_cond_bad.pl | 2 +- test_regress/t/t_class_param_enum_bad.pl | 2 +- test_regress/t/t_class_super_bad.pl | 2 +- test_regress/t/t_class_super_bad2.pl | 2 +- test_regress/t/t_class_super_new_bad_nfirst.pl | 2 +- test_regress/t/t_class_uses_this_bad.pl | 2 +- test_regress/t/t_clocking_notiming.pl | 2 +- test_regress/t/t_const_slicesel_bad.pl | 2 +- test_regress/t/t_continue_do_while_bad.pl | 2 +- test_regress/t/t_covergroup_unsup.pl | 2 +- test_regress/t/t_dfg_multidriver_dfg_bad.pl | 4 ++-- test_regress/t/t_disable_fork_notiming.pl | 2 +- test_regress/t/t_dpi_unpack_bad.pl | 2 +- test_regress/t/t_event_control_expr_unsup.pl | 2 +- test_regress/t/t_event_control_star.pl | 2 +- test_regress/t/t_expect.pl | 2 +- test_regress/t/t_flag_instr_count_dpi_bad.pl | 2 +- test_regress/t/t_flag_main_sc_bad.pl | 2 +- test_regress/t/t_flag_only_bad.pl | 2 +- test_regress/t/t_flag_only_bad2.pl | 2 +- test_regress/t/t_flag_only_bad3.pl | 2 +- test_regress/t/t_force_bad_rw.pl | 2 +- test_regress/t/t_inside_assoc_unsup.pl | 2 +- test_regress/t/t_interconnect_bad.pl | 4 ++-- test_regress/t/t_let_arg_bad.pl | 2 +- test_regress/t/t_let_recurse_bad.pl | 2 +- test_regress/t/t_let_unsup.pl | 2 +- test_regress/t/t_lint_implicit_def_bad.pl | 2 +- test_regress/t/t_lint_stmtdly_bad.pl | 2 +- test_regress/t/t_mod_interface_array3.pl | 2 +- test_regress/t/t_notiming.pl | 2 +- test_regress/t/t_notiming_off.pl | 2 +- test_regress/t/t_param_type_bad2.pl | 2 +- test_regress/t/t_process_notiming.pl | 2 +- test_regress/t/t_sampled_expr_unsup.pl | 2 +- test_regress/t/t_sequence_sexpr_unsup.pl | 2 +- test_regress/t/t_source_sync.pl | 2 +- test_regress/t/t_split_var_1_bad.pl | 2 +- test_regress/t/t_structu_dataType_assignment_bad.pl | 4 +--- 49 files changed, 51 insertions(+), 53 deletions(-) diff --git a/test_regress/t/t_array_method_bad.pl b/test_regress/t/t_array_method_bad.pl index 1d770f716..c65314f7b 100755 --- a/test_regress/t/t_array_method_bad.pl +++ b/test_regress/t/t_array_method_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_assert_clock_event_unsup.pl b/test_regress/t/t_assert_clock_event_unsup.pl index d188a4276..1e3627720 100755 --- a/test_regress/t/t_assert_clock_event_unsup.pl +++ b/test_regress/t/t_assert_clock_event_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert'], fails => 1, diff --git a/test_regress/t/t_assert_disable_bad.pl b/test_regress/t/t_assert_disable_bad.pl index efe818bd1..1f68597d8 100755 --- a/test_regress/t/t_assert_disable_bad.pl +++ b/test_regress/t/t_assert_disable_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert'], fails => 1, diff --git a/test_regress/t/t_assert_imm_nz_bad.pl b/test_regress/t/t_assert_imm_nz_bad.pl index eebb17b11..9841a8c0f 100755 --- a/test_regress/t/t_assert_imm_nz_bad.pl +++ b/test_regress/t/t_assert_imm_nz_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert'], fails => 1, diff --git a/test_regress/t/t_assert_procedural_clk_bad.pl b/test_regress/t/t_assert_procedural_clk_bad.pl index d188a4276..1e3627720 100755 --- a/test_regress/t/t_assert_procedural_clk_bad.pl +++ b/test_regress/t/t_assert_procedural_clk_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert'], fails => 1, diff --git a/test_regress/t/t_assert_property_untyped_unsup.pl b/test_regress/t/t_assert_property_untyped_unsup.pl index d188a4276..1e3627720 100755 --- a/test_regress/t/t_assert_property_untyped_unsup.pl +++ b/test_regress/t/t_assert_property_untyped_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert'], fails => 1, diff --git a/test_regress/t/t_assert_property_var_unsup.pl b/test_regress/t/t_assert_property_var_unsup.pl index c9ca914d8..7284ec30e 100755 --- a/test_regress/t/t_assert_property_var_unsup.pl +++ b/test_regress/t/t_assert_property_var_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert --error-limit 1000'], fails => 1, diff --git a/test_regress/t/t_assert_recursive_property_unsup.pl b/test_regress/t/t_assert_recursive_property_unsup.pl index 15b4f4a73..8e28a9204 100755 --- a/test_regress/t/t_assert_recursive_property_unsup.pl +++ b/test_regress/t/t_assert_recursive_property_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename=>$Self->{golden_filename}, verilator_flags2=> ['--assert'], fails => 1, diff --git a/test_regress/t/t_assigndly_dynamic_notiming_bad.pl b/test_regress/t/t_assigndly_dynamic_notiming_bad.pl index 1e658d937..bf0b971e2 100755 --- a/test_regress/t/t_assigndly_dynamic_notiming_bad.pl +++ b/test_regress/t/t_assigndly_dynamic_notiming_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_class_assign_bad.pl b/test_regress/t/t_class_assign_bad.pl index 430290c0a..c35c8bc93 100755 --- a/test_regress/t/t_class_assign_bad.pl +++ b/test_regress/t/t_class_assign_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_assign_cond_bad.pl b/test_regress/t/t_class_assign_cond_bad.pl index 430290c0a..c35c8bc93 100755 --- a/test_regress/t/t_class_assign_cond_bad.pl +++ b/test_regress/t/t_class_assign_cond_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_param_enum_bad.pl b/test_regress/t/t_class_param_enum_bad.pl index 430290c0a..c35c8bc93 100755 --- a/test_regress/t/t_class_param_enum_bad.pl +++ b/test_regress/t/t_class_param_enum_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_super_bad.pl b/test_regress/t/t_class_super_bad.pl index 45af9e7a6..7be596e0f 100755 --- a/test_regress/t/t_class_super_bad.pl +++ b/test_regress/t/t_class_super_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_super_bad2.pl b/test_regress/t/t_class_super_bad2.pl index 45af9e7a6..7be596e0f 100755 --- a/test_regress/t/t_class_super_bad2.pl +++ b/test_regress/t/t_class_super_bad2.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_super_new_bad_nfirst.pl b/test_regress/t/t_class_super_new_bad_nfirst.pl index 8b81d9f75..44783b1f6 100755 --- a/test_regress/t/t_class_super_new_bad_nfirst.pl +++ b/test_regress/t/t_class_super_new_bad_nfirst.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_class_uses_this_bad.pl b/test_regress/t/t_class_uses_this_bad.pl index 45af9e7a6..7be596e0f 100755 --- a/test_regress/t/t_class_uses_this_bad.pl +++ b/test_regress/t/t_class_uses_this_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_clocking_notiming.pl b/test_regress/t/t_clocking_notiming.pl index 5a683788e..bf475c910 100755 --- a/test_regress/t/t_clocking_notiming.pl +++ b/test_regress/t/t_clocking_notiming.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_const_slicesel_bad.pl b/test_regress/t/t_const_slicesel_bad.pl index 9d8b88724..5d84a06aa 100755 --- a/test_regress/t/t_const_slicesel_bad.pl +++ b/test_regress/t/t_const_slicesel_bad.pl @@ -14,7 +14,7 @@ scenarios(linter => 1); lint( fails => 1 -); + ); ok(1); 1; diff --git a/test_regress/t/t_continue_do_while_bad.pl b/test_regress/t/t_continue_do_while_bad.pl index 15b4f4a73..8e28a9204 100755 --- a/test_regress/t/t_continue_do_while_bad.pl +++ b/test_regress/t/t_continue_do_while_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename=>$Self->{golden_filename}, verilator_flags2=> ['--assert'], fails => 1, diff --git a/test_regress/t/t_covergroup_unsup.pl b/test_regress/t/t_covergroup_unsup.pl index c9ca914d8..7284ec30e 100755 --- a/test_regress/t/t_covergroup_unsup.pl +++ b/test_regress/t/t_covergroup_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert --error-limit 1000'], fails => 1, diff --git a/test_regress/t/t_dfg_multidriver_dfg_bad.pl b/test_regress/t/t_dfg_multidriver_dfg_bad.pl index eae347a52..9325bb095 100755 --- a/test_regress/t/t_dfg_multidriver_dfg_bad.pl +++ b/test_regress/t/t_dfg_multidriver_dfg_bad.pl @@ -10,10 +10,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, -); + ); ok(1); 1; diff --git a/test_regress/t/t_disable_fork_notiming.pl b/test_regress/t/t_disable_fork_notiming.pl index 1a013a057..4994b95cb 100755 --- a/test_regress/t/t_disable_fork_notiming.pl +++ b/test_regress/t/t_disable_fork_notiming.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, v_flags2 => ["--no-timing"], fails => 1, diff --git a/test_regress/t/t_dpi_unpack_bad.pl b/test_regress/t/t_dpi_unpack_bad.pl index 1720150ad..a60503a1f 100755 --- a/test_regress/t/t_dpi_unpack_bad.pl +++ b/test_regress/t/t_dpi_unpack_bad.pl @@ -13,7 +13,7 @@ scenarios(linter => 1); lint( fails => 1, expect_filename => $Self->{golden_filename}, -); + ); ok(1); 1; diff --git a/test_regress/t/t_event_control_expr_unsup.pl b/test_regress/t/t_event_control_expr_unsup.pl index 1bf0030aa..2f43f3687 100755 --- a/test_regress/t/t_event_control_expr_unsup.pl +++ b/test_regress/t/t_event_control_expr_unsup.pl @@ -12,7 +12,7 @@ scenarios(vlt => 1); # no vltmt, as AstMemberSel is unhandled in V3InstrCount top_filename("t_event_control_expr.v"); -compile( +lint( verilator_flags2 => ['-DUNSUP'], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_event_control_star.pl b/test_regress/t/t_event_control_star.pl index c5e251fe7..68471ddd3 100755 --- a/test_regress/t/t_event_control_star.pl +++ b/test_regress/t/t_event_control_star.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( verilator_flags2 => ["--timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_expect.pl b/test_regress/t/t_expect.pl index 1e49d46fd..7da2a2cb5 100755 --- a/test_regress/t/t_expect.pl +++ b/test_regress/t/t_expect.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert --timing'], fails => 1, diff --git a/test_regress/t/t_flag_instr_count_dpi_bad.pl b/test_regress/t/t_flag_instr_count_dpi_bad.pl index 33b76e374..ebc71f887 100755 --- a/test_regress/t/t_flag_instr_count_dpi_bad.pl +++ b/test_regress/t/t_flag_instr_count_dpi_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( verilator_flags2 => ["--instr-count-dpi -1"], fails => 1, expect => "%Error: --instr-count-dpi must be non-negative: -1" diff --git a/test_regress/t/t_flag_main_sc_bad.pl b/test_regress/t/t_flag_main_sc_bad.pl index 94fd1dce7..6d6075e78 100755 --- a/test_regress/t/t_flag_main_sc_bad.pl +++ b/test_regress/t/t_flag_main_sc_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( verilator_flags2 => ['--exe --build --main --sc'], verilator_make_cmake => 0, verilator_make_gmake => 0, diff --git a/test_regress/t/t_flag_only_bad.pl b/test_regress/t/t_flag_only_bad.pl index 6fb0c0314..b01845221 100755 --- a/test_regress/t/t_flag_only_bad.pl +++ b/test_regress/t/t_flag_only_bad.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_flag_main.v"); -compile( +lint( verilator_make_cmake => 0, verilator_make_gmake => 0, verilator_flags2 => ["--binary -E --dpi-hdr-only --lint-only --xml-only -Wall"], diff --git a/test_regress/t/t_flag_only_bad2.pl b/test_regress/t/t_flag_only_bad2.pl index 34c252411..d2f4e5124 100755 --- a/test_regress/t/t_flag_only_bad2.pl +++ b/test_regress/t/t_flag_only_bad2.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_flag_main.v"); -compile( +lint( verilator_make_cmake => 0, verilator_make_gmake => 0, verilator_flags2 => ["--build -E -Wno-fatal --dpi-hdr-only --lint-only --xml-only"], diff --git a/test_regress/t/t_flag_only_bad3.pl b/test_regress/t/t_flag_only_bad3.pl index f21368eec..68e326b8d 100755 --- a/test_regress/t/t_flag_only_bad3.pl +++ b/test_regress/t/t_flag_only_bad3.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); top_filename("t/t_flag_main.v"); -compile( +lint( verilator_make_cmake => 0, verilator_make_gmake => 0, verilator_flags2 => ["-Wall --lint-only -Wno-fatal --dpi-hdr-only --xml-only"], diff --git a/test_regress/t/t_force_bad_rw.pl b/test_regress/t/t_force_bad_rw.pl index b9057722c..a5846c699 100755 --- a/test_regress/t/t_force_bad_rw.pl +++ b/test_regress/t/t_force_bad_rw.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_inside_assoc_unsup.pl b/test_regress/t/t_inside_assoc_unsup.pl index ffb804e48..27159da5b 100755 --- a/test_regress/t/t_inside_assoc_unsup.pl +++ b/test_regress/t/t_inside_assoc_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_interconnect_bad.pl b/test_regress/t/t_interconnect_bad.pl index 1362bf74f..a60503a1f 100755 --- a/test_regress/t/t_interconnect_bad.pl +++ b/test_regress/t/t_interconnect_bad.pl @@ -8,9 +8,9 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 -scenarios(simulator => 1); +scenarios(linter => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_let_arg_bad.pl b/test_regress/t/t_let_arg_bad.pl index 882bc2418..d85145f99 100755 --- a/test_regress/t/t_let_arg_bad.pl +++ b/test_regress/t/t_let_arg_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, fails => 1, ); diff --git a/test_regress/t/t_let_recurse_bad.pl b/test_regress/t/t_let_recurse_bad.pl index 882bc2418..d85145f99 100755 --- a/test_regress/t/t_let_recurse_bad.pl +++ b/test_regress/t/t_let_recurse_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, fails => 1, ); diff --git a/test_regress/t/t_let_unsup.pl b/test_regress/t/t_let_unsup.pl index 882bc2418..d85145f99 100755 --- a/test_regress/t/t_let_unsup.pl +++ b/test_regress/t/t_let_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(linter => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, fails => 1, ); diff --git a/test_regress/t/t_lint_implicit_def_bad.pl b/test_regress/t/t_lint_implicit_def_bad.pl index 24c0e4c87..7539b1bd9 100755 --- a/test_regress/t/t_lint_implicit_def_bad.pl +++ b/test_regress/t/t_lint_implicit_def_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( verilator_flags2 => ["--lint-only -Wall -Wno-DECLFILENAME"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_lint_stmtdly_bad.pl b/test_regress/t/t_lint_stmtdly_bad.pl index bcb7303da..280ae5a3c 100755 --- a/test_regress/t/t_lint_stmtdly_bad.pl +++ b/test_regress/t/t_lint_stmtdly_bad.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_mod_interface_array3.pl b/test_regress/t/t_mod_interface_array3.pl index 1362bf74f..a29ead0ed 100755 --- a/test_regress/t/t_mod_interface_array3.pl +++ b/test_regress/t/t_mod_interface_array3.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_notiming.pl b/test_regress/t/t_notiming.pl index 5a683788e..bf475c910 100755 --- a/test_regress/t/t_notiming.pl +++ b/test_regress/t/t_notiming.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -compile( +lint( verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_notiming_off.pl b/test_regress/t/t_notiming_off.pl index cca2c7651..955b160b1 100755 --- a/test_regress/t/t_notiming_off.pl +++ b/test_regress/t/t_notiming_off.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); top_filename("t/t_timing_off.v"); -compile( +lint( verilator_flags2 => ["--no-timing"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_param_type_bad2.pl b/test_regress/t/t_param_type_bad2.pl index b12ecf9cf..9151f32e0 100755 --- a/test_regress/t/t_param_type_bad2.pl +++ b/test_regress/t/t_param_type_bad2.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( # Bug1575 required trace to crash verilator_flags2 => ["--trace --cc"], fails => 1, diff --git a/test_regress/t/t_process_notiming.pl b/test_regress/t/t_process_notiming.pl index 9a1abce98..f7118bd7d 100755 --- a/test_regress/t/t_process_notiming.pl +++ b/test_regress/t/t_process_notiming.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); top_filename("t/t_process.v"); -compile( +lint( expect_filename => $Self->{golden_filename}, v_flags2 => ["+define+T_PROCESS+std::process", "--no-timing"], fails => 1, diff --git a/test_regress/t/t_sampled_expr_unsup.pl b/test_regress/t/t_sampled_expr_unsup.pl index 24a95330a..244d49cbd 100755 --- a/test_regress/t/t_sampled_expr_unsup.pl +++ b/test_regress/t/t_sampled_expr_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename=>$Self->{golden_filename}, verilator_flags2=> ['--assert -Wno-UNSIGNED'], fails => 1, diff --git a/test_regress/t/t_sequence_sexpr_unsup.pl b/test_regress/t/t_sequence_sexpr_unsup.pl index c9ca914d8..7284ec30e 100755 --- a/test_regress/t/t_sequence_sexpr_unsup.pl +++ b/test_regress/t/t_sequence_sexpr_unsup.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( expect_filename => $Self->{golden_filename}, verilator_flags2 => ['--assert --error-limit 1000'], fails => 1, diff --git a/test_regress/t/t_source_sync.pl b/test_regress/t/t_source_sync.pl index f34ef865a..63947fd00 100755 --- a/test_regress/t/t_source_sync.pl +++ b/test_regress/t/t_source_sync.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -compile( +lint( fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_split_var_1_bad.pl b/test_regress/t/t_split_var_1_bad.pl index cb986145a..256bd9bc6 100755 --- a/test_regress/t/t_split_var_1_bad.pl +++ b/test_regress/t/t_split_var_1_bad.pl @@ -14,7 +14,7 @@ lint( fails => 1, verilator_flags2 => ['--stats'], expect_filename => $Self->{golden_filename}, -); + ); ok(1); 1; diff --git a/test_regress/t/t_structu_dataType_assignment_bad.pl b/test_regress/t/t_structu_dataType_assignment_bad.pl index b9230bc2a..d593ee907 100755 --- a/test_regress/t/t_structu_dataType_assignment_bad.pl +++ b/test_regress/t/t_structu_dataType_assignment_bad.pl @@ -10,13 +10,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); - -compile( +lint( verilator_flags2 => ['--structs-packed'], fails => 1, expect_filename => $Self->{golden_filename}, ); - ok(1); 1; From a43fd06f857d4b0413210ec8db0e6e781818fffc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 10:37:35 -0500 Subject: [PATCH 041/116] Tests: Imply no driver.pl make when using --build. No functional change intended --- test_regress/driver.pl | 4 ++++ test_regress/t/t_cxx_equal_to.pl | 2 -- test_regress/t/t_dfg_peephole.pl | 4 ---- test_regress/t/t_flag_binary.pl | 2 -- test_regress/t/t_flag_binary_parallel.pl | 2 -- test_regress/t/t_flag_build.pl | 2 -- test_regress/t/t_flag_build_bad2.pl | 2 -- test_regress/t/t_flag_build_jobs_and_j.pl | 2 -- test_regress/t/t_flag_main.pl | 2 -- test_regress/t/t_flag_main_sc_bad.pl | 2 -- test_regress/t/t_flag_main_top_name.pl | 2 -- test_regress/t/t_flag_main_top_name_empty.pl | 2 -- test_regress/t/t_flag_only_bad.pl | 2 -- test_regress/t/t_flag_only_bad2.pl | 2 -- test_regress/t/t_flag_verilate.pl | 2 -- test_regress/t/t_stack_check.pl | 2 -- test_regress/t/t_timing_long.pl | 4 ---- test_regress/t/t_trace_binary.pl | 2 -- test_regress/t/t_trace_binary_flag_off.pl | 2 -- test_regress/t/t_trace_timing1.pl | 2 -- test_regress/t/t_trace_ub_misaligned_address.pl | 2 -- test_regress/t/t_unroll_delay.pl | 3 --- test_regress/t/t_wait_const.pl | 3 --- 23 files changed, 4 insertions(+), 50 deletions(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index 7c7e5692d..a59442393 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -1023,6 +1023,10 @@ sub compile { $param{threads} = ::calc_threads($Vltmt_threads) if $param{threads} < 0 && $param{vltmt}; $param{context_threads} = $param{threads} >= 1 ? $param{threads} : 1 if !$param{context_threads}; $param{make_main} = 0 if ($checkflags =~ / -?-main\b/ || $checkflags =~ / -?-binary\b/); + if ($checkflags =~ / -?-build\b/ || $checkflags =~ / -?-binary\b/) { + $param{verilator_make_cmake} = 0; + $param{verilator_make_gmake} = 0; + } $self->{threads} = $param{threads}; $self->{context_threads} = $param{context_threads}; diff --git a/test_regress/t/t_cxx_equal_to.pl b/test_regress/t/t_cxx_equal_to.pl index d0f124208..be05b3b5e 100755 --- a/test_regress/t/t_cxx_equal_to.pl +++ b/test_regress/t/t_cxx_equal_to.pl @@ -14,8 +14,6 @@ top_filename("t/t_cxx_equal_to.v"); compile( verilator_flags2 => ['--binary --timing --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute( diff --git a/test_regress/t/t_dfg_peephole.pl b/test_regress/t/t_dfg_peephole.pl index 952898fbb..a58241b50 100755 --- a/test_regress/t/t_dfg_peephole.pl +++ b/test_regress/t/t_dfg_peephole.pl @@ -59,8 +59,6 @@ close $wrFile; compile( verilator_flags2 => ["--stats", "--build", "-fno-dfg", "+incdir+$Self->{obj_dir}", "-Mdir", "$Self->{obj_dir}/obj_ref", "--prefix", "Vref"], - verilator_make_gmake => 0, - verilator_make_cmake => 0 ); # Compile optimized - also builds executable @@ -72,8 +70,6 @@ compile( "-CFLAGS \"-I .. -I ../obj_ref\"", "../obj_ref/Vref__ALL.a", "../../t/$Self->{name}.cpp"], - verilator_make_gmake => 0, - verilator_make_cmake => 0 ); # Execute test to check equivalence diff --git a/test_regress/t/t_flag_binary.pl b/test_regress/t/t_flag_binary.pl index bf2dc801d..ba2c15de6 100755 --- a/test_regress/t/t_flag_binary.pl +++ b/test_regress/t/t_flag_binary.pl @@ -17,8 +17,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--binary'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute( diff --git a/test_regress/t/t_flag_binary_parallel.pl b/test_regress/t/t_flag_binary_parallel.pl index 0305abd74..f97b78cf8 100755 --- a/test_regress/t/t_flag_binary_parallel.pl +++ b/test_regress/t/t_flag_binary_parallel.pl @@ -17,8 +17,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--binary', '--output-split 1'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_main => 0, ); diff --git a/test_regress/t/t_flag_build.pl b/test_regress/t/t_flag_build.pl index c26b6bcb0..985c72304 100755 --- a/test_regress/t/t_flag_build.pl +++ b/test_regress/t/t_flag_build.pl @@ -12,8 +12,6 @@ scenarios(simulator => 1); top_filename("t/t_flag_make_cmake.v"); compile( # Don't call cmake nor gmake from driver.pl - verilator_make_cmake => 0, - verilator_make_gmake => 0, verilator_flags2 => ['--exe --cc --build -j 2', '../' . $Self->{main_filename}, '-MAKEFLAGS -p --trace'], diff --git a/test_regress/t/t_flag_build_bad2.pl b/test_regress/t/t_flag_build_bad2.pl index a28ddb9a1..b61a1b234 100755 --- a/test_regress/t/t_flag_build_bad2.pl +++ b/test_regress/t/t_flag_build_bad2.pl @@ -12,8 +12,6 @@ scenarios(vlt => 1); top_filename("t/t_flag_make_cmake.v"); compile( - verilator_make_cmake => 0, - verilator_make_gmake => 0, # Need --no-print-directory so golden file doesn't compare directory names verilator_flags2 => ["--build --MAKEFLAGS --no-print-directory" ." --MAKEFLAGS illegal-flag-to-fail-make"], diff --git a/test_regress/t/t_flag_build_jobs_and_j.pl b/test_regress/t/t_flag_build_jobs_and_j.pl index 356011fbf..bd8c6da26 100755 --- a/test_regress/t/t_flag_build_jobs_and_j.pl +++ b/test_regress/t/t_flag_build_jobs_and_j.pl @@ -12,8 +12,6 @@ scenarios(simulator => 1); top_filename("t/t_flag_make_cmake.v"); compile( - verilator_make_cmake => 0, - verilator_make_gmake => 0, verilator_flags2 => ['--exe --cc --build -j 10 --build-jobs 2 --stats', '../' . $Self->{main_filename}], ); diff --git a/test_regress/t/t_flag_main.pl b/test_regress/t/t_flag_main.pl index f279e8a2e..2d1040ad8 100755 --- a/test_regress/t/t_flag_main.pl +++ b/test_regress/t/t_flag_main.pl @@ -15,8 +15,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--exe --build --main'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, # Check that code --main produces uses only most modern API features make_flags => 'CPPFLAGS_ADD=-DVL_NO_LEGACY', ); diff --git a/test_regress/t/t_flag_main_sc_bad.pl b/test_regress/t/t_flag_main_sc_bad.pl index 6d6075e78..75c182412 100755 --- a/test_regress/t/t_flag_main_sc_bad.pl +++ b/test_regress/t/t_flag_main_sc_bad.pl @@ -12,8 +12,6 @@ scenarios(vlt => 1); lint( verilator_flags2 => ['--exe --build --main --sc'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, fails => 1, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_flag_main_top_name.pl b/test_regress/t/t_flag_main_top_name.pl index 876acdd1c..027e13395 100755 --- a/test_regress/t/t_flag_main_top_name.pl +++ b/test_regress/t/t_flag_main_top_name.pl @@ -15,8 +15,6 @@ top_filename("t/t_flag_main_top_name.v"); compile( verilator_flags => ["-Mdir $Self->{obj_dir}", "--exe", "--build", "--main"], verilator_flags2 => ["--top-module top", "--main-top-name ALTOP"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_main => 0, ); diff --git a/test_regress/t/t_flag_main_top_name_empty.pl b/test_regress/t/t_flag_main_top_name_empty.pl index bd3cc906f..2f4bc41fb 100755 --- a/test_regress/t/t_flag_main_top_name_empty.pl +++ b/test_regress/t/t_flag_main_top_name_empty.pl @@ -15,8 +15,6 @@ top_filename("t/t_flag_main_top_name.v"); compile( verilator_flags => ["-Mdir $Self->{obj_dir}", "--exe", "--build", "--main"], verilator_flags2 => ["--top-module top", "--main-top-name -", "-DMAIN_TOP_NAME_EMPTY"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_main => 0, ); diff --git a/test_regress/t/t_flag_only_bad.pl b/test_regress/t/t_flag_only_bad.pl index b01845221..c3650bf1e 100755 --- a/test_regress/t/t_flag_only_bad.pl +++ b/test_regress/t/t_flag_only_bad.pl @@ -12,8 +12,6 @@ scenarios(vlt => 1); top_filename("t/t_flag_main.v"); lint( - verilator_make_cmake => 0, - verilator_make_gmake => 0, verilator_flags2 => ["--binary -E --dpi-hdr-only --lint-only --xml-only -Wall"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_flag_only_bad2.pl b/test_regress/t/t_flag_only_bad2.pl index d2f4e5124..54cc461d0 100755 --- a/test_regress/t/t_flag_only_bad2.pl +++ b/test_regress/t/t_flag_only_bad2.pl @@ -12,8 +12,6 @@ scenarios(vlt => 1); top_filename("t/t_flag_main.v"); lint( - verilator_make_cmake => 0, - verilator_make_gmake => 0, verilator_flags2 => ["--build -E -Wno-fatal --dpi-hdr-only --lint-only --xml-only"], fails => 1, expect_filename => $Self->{golden_filename}, diff --git a/test_regress/t/t_flag_verilate.pl b/test_regress/t/t_flag_verilate.pl index bf4061315..aa1ec0ef8 100755 --- a/test_regress/t/t_flag_verilate.pl +++ b/test_regress/t/t_flag_verilate.pl @@ -43,8 +43,6 @@ if ( ! -e $Self->{obj_dir} . '/Vt_flag_verilate.mk' ) { # Just build, no Verilation. .tree must not be saved even with --dump-tree option. compile( # Don't call cmake nor gmake from driver.pl. Just build here - verilator_make_cmake => 0, - verilator_make_gmake => 0, verilator_flags2 => ['--exe --cc --build --no-verilate', '../' . $Self->{main_filename}, '--debugi 1 --dump-tree --dump-tree-addrids'], diff --git a/test_regress/t/t_stack_check.pl b/test_regress/t/t_stack_check.pl index 0c61fa4eb..934833563 100755 --- a/test_regress/t/t_stack_check.pl +++ b/test_regress/t/t_stack_check.pl @@ -12,8 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ['--binary --debug-stack-check'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute(); diff --git a/test_regress/t/t_timing_long.pl b/test_regress/t/t_timing_long.pl index 2c5c9595e..9c7fdc503 100755 --- a/test_regress/t/t_timing_long.pl +++ b/test_regress/t/t_timing_long.pl @@ -57,8 +57,6 @@ gen($Self->{top_filename}); if ($Self->have_coroutines) { compile( verilator_flags2 => ["--exe --build --main --tim" . "ing"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_top => 1, ); @@ -69,8 +67,6 @@ if ($Self->have_coroutines) { compile( verilator_flags2 => ["--exe --build --main --no-timing -Wno-STMTDLY"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_top => 1, ); diff --git a/test_regress/t/t_trace_binary.pl b/test_regress/t/t_trace_binary.pl index 321b41ed5..afc204bcb 100755 --- a/test_regress/t/t_trace_binary.pl +++ b/test_regress/t/t_trace_binary.pl @@ -15,8 +15,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--binary --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute( diff --git a/test_regress/t/t_trace_binary_flag_off.pl b/test_regress/t/t_trace_binary_flag_off.pl index 4a099bdc7..521677772 100755 --- a/test_regress/t/t_trace_binary_flag_off.pl +++ b/test_regress/t/t_trace_binary_flag_off.pl @@ -17,8 +17,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--binary'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute( diff --git a/test_regress/t/t_trace_timing1.pl b/test_regress/t/t_trace_timing1.pl index a0528ef80..4c3233d88 100755 --- a/test_regress/t/t_trace_timing1.pl +++ b/test_regress/t/t_trace_timing1.pl @@ -15,8 +15,6 @@ compile( "-Mdir $Self->{obj_dir}", "--debug-check", ], verilator_flags2 => ['--binary --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, make_main => 0, ); diff --git a/test_regress/t/t_trace_ub_misaligned_address.pl b/test_regress/t/t_trace_ub_misaligned_address.pl index bc08c02fe..9dab0ca4e 100755 --- a/test_regress/t/t_trace_ub_misaligned_address.pl +++ b/test_regress/t/t_trace_ub_misaligned_address.pl @@ -16,8 +16,6 @@ compile( verilator_flags2 => ["--binary --trace", "-CFLAGS -fsanitize=address,undefined", "-LDFLAGS -fsanitize=address,undefined"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, ); execute( diff --git a/test_regress/t/t_unroll_delay.pl b/test_regress/t/t_unroll_delay.pl index 9a4002b2d..a9298001e 100755 --- a/test_regress/t/t_unroll_delay.pl +++ b/test_regress/t/t_unroll_delay.pl @@ -12,9 +12,6 @@ scenarios(simulator => 1); compile( verilator_flags2 => ['--binary --timing --trace'], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, ); execute( diff --git a/test_regress/t/t_wait_const.pl b/test_regress/t/t_wait_const.pl index b2d31c26d..901ee7e8b 100755 --- a/test_regress/t/t_wait_const.pl +++ b/test_regress/t/t_wait_const.pl @@ -12,9 +12,6 @@ scenarios(vlt => 1); compile( verilator_flags2 => ["--binary"], - verilator_make_cmake => 0, - verilator_make_gmake => 0, - make_main => 0, ); execute( From d595d4c7ac581e4dde4b1a1a5b0fb46c97f97c03 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 10:57:00 -0500 Subject: [PATCH 042/116] Tests: Use --binary with some --timing tests --- test_regress/t/t_altera_lpm_counter.pl | 2 +- test_regress/t/t_delay_incr.pl | 2 +- test_regress/t/t_delay_incr_timing.pl | 2 +- test_regress/t/t_fork_join_none_any_nested.pl | 2 +- test_regress/t/t_fork_label.pl | 2 +- test_regress/t/t_fork_timing.pl | 2 +- test_regress/t/t_func_lib_sub_timing.pl | 2 +- test_regress/t/t_interconnect.pl | 2 +- test_regress/t/t_mailbox_class.pl | 2 +- test_regress/t/t_math_signed5.pl | 2 +- test_regress/t/t_math_signed5_timing.pl | 2 +- test_regress/t/t_package_ddecl.pl | 2 +- test_regress/t/t_package_ddecl_timing.pl | 2 +- test_regress/t/t_parse_delay.pl | 2 +- test_regress/t/t_parse_delay_timing.pl | 2 +- test_regress/t/t_process.pl | 2 +- test_regress/t/t_process_fork.pl | 2 +- test_regress/t/t_process_rand.pl | 2 +- test_regress/t/t_process_std.pl | 2 +- test_regress/t/t_queue_persistence_inl_unsup.pl | 2 +- test_regress/t/t_queue_persistence_noinl.pl | 2 +- test_regress/t/t_selextract_in_paramextends.pl | 2 +- test_regress/t/t_semaphore_class.pl | 2 +- test_regress/t/t_suspendable_deep.pl | 2 +- test_regress/t/t_uvm_all.pl | 2 +- test_regress/t/t_var_in_fork.pl | 2 +- test_regress/t/t_wait_order.pl | 2 +- test_regress/t/t_wait_timing.pl | 2 +- test_regress/t/t_while_timing_control.pl | 2 +- 29 files changed, 29 insertions(+), 29 deletions(-) diff --git a/test_regress/t/t_altera_lpm_counter.pl b/test_regress/t/t_altera_lpm_counter.pl index 78ec8c557..3f4aa0eed 100755 --- a/test_regress/t/t_altera_lpm_counter.pl +++ b/test_regress/t/t_altera_lpm_counter.pl @@ -14,7 +14,7 @@ top_filename("t/t_altera_lpm.v"); (my $module = $Self->{name}) =~ s/.*t_altera_//; compile( - verilator_flags2 => ["--top-module ${module}", "--no-timing"] + verilator_flags2 => ["--top-module ${module}", "--binary --no-timing"] ); ok(1); diff --git a/test_regress/t/t_delay_incr.pl b/test_regress/t/t_delay_incr.pl index 3e8a3c919..ff38a8470 100755 --- a/test_regress/t/t_delay_incr.pl +++ b/test_regress/t/t_delay_incr.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['-Wno-STMTDLY -Wno-ASSIGNDLY --no-timing'], + verilator_flags2 => ['--binary --no-timing -Wno-STMTDLY -Wno-ASSIGNDLY'], ); execute( diff --git a/test_regress/t/t_delay_incr_timing.pl b/test_regress/t/t_delay_incr_timing.pl index 7bc99d468..d60b1c8bd 100755 --- a/test_regress/t/t_delay_incr_timing.pl +++ b/test_regress/t/t_delay_incr_timing.pl @@ -16,7 +16,7 @@ top_filename("t/t_delay_incr.v"); compile( timing_loop => 1, - verilator_flags2 => ['--timing -Wno-ZERODLY'], + verilator_flags2 => ['--binary --timing -Wno-ZERODLY'], ); execute( diff --git a/test_regress/t/t_fork_join_none_any_nested.pl b/test_regress/t/t_fork_join_none_any_nested.pl index b267631e9..fec4c2942 100755 --- a/test_regress/t/t_fork_join_none_any_nested.pl +++ b/test_regress/t/t_fork_join_none_any_nested.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_fork_label.pl b/test_regress/t/t_fork_label.pl index 8bb4480e1..dc3cfd898 100755 --- a/test_regress/t/t_fork_label.pl +++ b/test_regress/t/t_fork_label.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['--no-timing'], + verilator_flags2 => ['--binary --no-timing'], ); execute(); diff --git a/test_regress/t/t_fork_timing.pl b/test_regress/t/t_fork_timing.pl index db741a7d5..b62f5837f 100755 --- a/test_regress/t/t_fork_timing.pl +++ b/test_regress/t/t_fork_timing.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); top_filename("t/t_fork.v"); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_func_lib_sub_timing.pl b/test_regress/t/t_func_lib_sub_timing.pl index 7498c6694..6101d0fa0 100755 --- a/test_regress/t/t_func_lib_sub_timing.pl +++ b/test_regress/t/t_func_lib_sub_timing.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); # UNOPTTHREADS in vltmt top_filename("t/t_func_lib_sub.v"); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); # No execute diff --git a/test_regress/t/t_interconnect.pl b/test_regress/t/t_interconnect.pl index 2a516857f..7cb28e364 100755 --- a/test_regress/t/t_interconnect.pl +++ b/test_regress/t/t_interconnect.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], fails => $Self->{vlt_all}, expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_mailbox_class.pl b/test_regress/t/t_mailbox_class.pl index 6e30bd25d..91589388d 100755 --- a/test_regress/t/t_mailbox_class.pl +++ b/test_regress/t/t_mailbox_class.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); ok(1); diff --git a/test_regress/t/t_math_signed5.pl b/test_regress/t/t_math_signed5.pl index f5debdb98..39ae2a784 100755 --- a/test_regress/t/t_math_signed5.pl +++ b/test_regress/t/t_math_signed5.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['--no-timing'], + verilator_flags2 => ['--binary --no-timing'], ); execute( diff --git a/test_regress/t/t_math_signed5_timing.pl b/test_regress/t/t_math_signed5_timing.pl index 34482e187..695a67c98 100755 --- a/test_regress/t/t_math_signed5_timing.pl +++ b/test_regress/t/t_math_signed5_timing.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_math_signed5.v"); compile( - verilator_flags2 => ['--timing'], + verilator_flags2 => ['--binary --timing'], timing_loop => 1, ); diff --git a/test_regress/t/t_package_ddecl.pl b/test_regress/t/t_package_ddecl.pl index f5debdb98..39ae2a784 100755 --- a/test_regress/t/t_package_ddecl.pl +++ b/test_regress/t/t_package_ddecl.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['--no-timing'], + verilator_flags2 => ['--binary --no-timing'], ); execute( diff --git a/test_regress/t/t_package_ddecl_timing.pl b/test_regress/t/t_package_ddecl_timing.pl index f7858dcb8..85bccb16b 100755 --- a/test_regress/t/t_package_ddecl_timing.pl +++ b/test_regress/t/t_package_ddecl_timing.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_package_ddecl.v"); compile( - verilator_flags2 => ['--timing'], + verilator_flags2 => ['--binary --timing'], timing_loop => 1, ); diff --git a/test_regress/t/t_parse_delay.pl b/test_regress/t/t_parse_delay.pl index 40a477a35..d399f16df 100755 --- a/test_regress/t/t_parse_delay.pl +++ b/test_regress/t/t_parse_delay.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ['--no-timing'], + verilator_flags2 => ['--binary --no-timing'], ); ok(1); diff --git a/test_regress/t/t_parse_delay_timing.pl b/test_regress/t/t_parse_delay_timing.pl index d466d38c7..c5543a880 100755 --- a/test_regress/t/t_parse_delay_timing.pl +++ b/test_regress/t/t_parse_delay_timing.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_parse_delay.v"); compile( - verilator_flags2 => ['--timing'], + verilator_flags2 => ['--binary --timing'], ); ok(1); diff --git a/test_regress/t/t_process.pl b/test_regress/t/t_process.pl index 7eac3054e..1ef7ad890 100755 --- a/test_regress/t/t_process.pl +++ b/test_regress/t/t_process.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - v_flags2 => ["--timing"], + v_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_process_fork.pl b/test_regress/t/t_process_fork.pl index 604f632d4..67c7c9e67 100755 --- a/test_regress/t/t_process_fork.pl +++ b/test_regress/t/t_process_fork.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_process_rand.pl b/test_regress/t/t_process_rand.pl index 4152e3d9b..eb241c303 100755 --- a/test_regress/t/t_process_rand.pl +++ b/test_regress/t/t_process_rand.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - v_flags2 => ["--timing"], + v_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_process_std.pl b/test_regress/t/t_process_std.pl index c9318acf2..207d1490a 100755 --- a/test_regress/t/t_process_std.pl +++ b/test_regress/t/t_process_std.pl @@ -13,7 +13,7 @@ scenarios(simulator => 1); top_filename("t/t_process.v"); compile( - v_flags2 => ["+define+T_PROCESS+std::process", "--timing"], + v_flags2 => ["--binary --timing", "+define+T_PROCESS+std::process"], ); execute( diff --git a/test_regress/t/t_queue_persistence_inl_unsup.pl b/test_regress/t/t_queue_persistence_inl_unsup.pl index 8cf7fc5b6..bbbc342e1 100755 --- a/test_regress/t/t_queue_persistence_inl_unsup.pl +++ b/test_regress/t/t_queue_persistence_inl_unsup.pl @@ -18,7 +18,7 @@ if (!$Self->have_coroutines) { else { compile( timing_loop => 1, - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], fails => 1, # bug3385 need to fix "ref" expect_filename => $Self->{golden_filename}, ); diff --git a/test_regress/t/t_queue_persistence_noinl.pl b/test_regress/t/t_queue_persistence_noinl.pl index 187562462..2f2670fa9 100755 --- a/test_regress/t/t_queue_persistence_noinl.pl +++ b/test_regress/t/t_queue_persistence_noinl.pl @@ -18,7 +18,7 @@ if (!$Self->have_coroutines) { else { compile( timing_loop => 1, - verilator_flags2 => ["--timing --fno-inline +define+TEST_NOINLINE"], + verilator_flags2 => ["--binary --timing --fno-inline +define+TEST_NOINLINE"], ); execute( diff --git a/test_regress/t/t_selextract_in_paramextends.pl b/test_regress/t/t_selextract_in_paramextends.pl index b267631e9..fec4c2942 100755 --- a/test_regress/t/t_selextract_in_paramextends.pl +++ b/test_regress/t/t_selextract_in_paramextends.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_semaphore_class.pl b/test_regress/t/t_semaphore_class.pl index 6e30bd25d..91589388d 100755 --- a/test_regress/t/t_semaphore_class.pl +++ b/test_regress/t/t_semaphore_class.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); ok(1); diff --git a/test_regress/t/t_suspendable_deep.pl b/test_regress/t/t_suspendable_deep.pl index e7824bce9..3b4f977f4 100755 --- a/test_regress/t/t_suspendable_deep.pl +++ b/test_regress/t/t_suspendable_deep.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); ok(1); diff --git a/test_regress/t/t_uvm_all.pl b/test_regress/t/t_uvm_all.pl index 2b328c903..77aac6e6b 100755 --- a/test_regress/t/t_uvm_all.pl +++ b/test_regress/t/t_uvm_all.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); compile( - v_flags2 => ["--timing", + v_flags2 => ["--binary --timing", "-Wno-PKGNODECL -Wno-IMPLICITSTATIC -Wno-CONSTRAINTIGN -Wno-MISINDENT", "-Wno-WIDTHEXPAND -Wno-WIDTHTRUNC -Wno-CASTCONST -Wno-REALCVT", "--error-limit 200 --debug-exit-uvm"], diff --git a/test_regress/t/t_var_in_fork.pl b/test_regress/t/t_var_in_fork.pl index b267631e9..fec4c2942 100755 --- a/test_regress/t/t_var_in_fork.pl +++ b/test_regress/t/t_var_in_fork.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--timing"], + verilator_flags2 => ["--binary --timing"], ); execute( diff --git a/test_regress/t/t_wait_order.pl b/test_regress/t/t_wait_order.pl index 2e33e5676..eba12604c 100755 --- a/test_regress/t/t_wait_order.pl +++ b/test_regress/t/t_wait_order.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); compile( expect_filename => $Self->{golden_filename}, - verilator_flags2 => ['--timing'], + verilator_flags2 => ['--binary --timing'], fails => $Self->{vlt_all}, ); diff --git a/test_regress/t/t_wait_timing.pl b/test_regress/t/t_wait_timing.pl index 41fd8a2dd..8791bb4a2 100755 --- a/test_regress/t/t_wait_timing.pl +++ b/test_regress/t/t_wait_timing.pl @@ -14,7 +14,7 @@ top_filename("t/t_wait.v"); compile( timing_loop => 1, - verilator_flags2 => ["--timing -Wno-WAITCONST"], + verilator_flags2 => ["--binary --timing -Wno-WAITCONST"], ); execute( diff --git a/test_regress/t/t_while_timing_control.pl b/test_regress/t/t_while_timing_control.pl index b6091c571..c6aaa67e5 100755 --- a/test_regress/t/t_while_timing_control.pl +++ b/test_regress/t/t_while_timing_control.pl @@ -14,7 +14,7 @@ $Self->{main_time_multiplier} = 10e-7 / 10e-9; compile( timing_loop => 1, - verilator_flags2 => ['--timing -Wno-ZERODLY'], + verilator_flags2 => ['--binary --timing -Wno-ZERODLY'], ); execute( From a38fea1f9eb83fb5ebb7b8c9f10f47957aba6ccc Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 11:19:42 -0500 Subject: [PATCH 043/116] Tests: Use context coverage write --- test_regress/driver.pl | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test_regress/driver.pl b/test_regress/driver.pl index a59442393..dbbd02f69 100755 --- a/test_regress/driver.pl +++ b/test_regress/driver.pl @@ -2031,7 +2031,7 @@ sub _make_main { if ($self->{coverage}) { $fh->print("#if VM_COVERAGE\n"); - $fh->print(" VerilatedCov::write(\"", $self->{coverage_filename}, "\");\n"); + $fh->print(" contextp->coveragep()->write(\"", $self->{coverage_filename}, "\");\n"); $fh->print("#endif // VM_COVERAGE\n"); } if ($self->{trace}) { From 1a9250278825f383efe8d6ef15b55c477e6723e5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 12:28:49 -0500 Subject: [PATCH 044/116] Add --main support for dumping coverage, and +verilator+coverage+file runtime option. --- Changes | 2 ++ docs/guide/exe_sim.rst | 5 +++++ docs/guide/simulating.rst | 18 ++++++++++++------ include/verilated.cpp | 13 ++++++++++++- include/verilated.h | 5 +++++ include/verilated_cov.cpp | 14 ++++++++++---- include/verilated_cov.h | 14 +++++++------- src/V3EmitCMain.cpp | 10 +++++++++- test_regress/t/t_cover_lib_c.cpp | 12 ++++++++---- test_regress/t/t_cover_main.out | 2 ++ test_regress/t/t_cover_main.pl | 25 +++++++++++++++++++++++++ test_regress/t/t_cover_main.v | 13 +++++++++++++ 12 files changed, 110 insertions(+), 23 deletions(-) create mode 100644 test_regress/t/t_cover_main.out create mode 100755 test_regress/t/t_cover_main.pl create mode 100644 test_regress/t/t_cover_main.v diff --git a/Changes b/Changes index 293b244f2..98c816c51 100644 --- a/Changes +++ b/Changes @@ -14,6 +14,8 @@ Verilator 5.021 devel **Minor:** * Add predicted stack overflow warning (#4799). +* Add +verilator+coverage+file runtime option. +* Add --main support for dumping coverage. * Remove deprecated 32-bit pointer mode (`gcc -m32`). * Change zero replication width error to ZEROREPL warning (#4753) (#4762). [Pengcheng Xu] * Support `vpiConstType` in `vpi_get_str()` (#4797). [Marlon James] diff --git a/docs/guide/exe_sim.rst b/docs/guide/exe_sim.rst index 7fbeaff0c..0040e242f 100644 --- a/docs/guide/exe_sim.rst +++ b/docs/guide/exe_sim.rst @@ -19,6 +19,11 @@ Summary: .. include:: ../_build/gen/args_verilated.rst +.. option:: +verilator+coverage+file+ + + When a model was Verilated using :vlopt:`--coverage`, sets the filename + to write coverage data into. Defaults to :file:`coverage.dat`. + .. option:: +verilator+debug Enable simulation runtime debugging. Equivalent to diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index c4af6115a..e196444dd 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -230,14 +230,20 @@ Coverage Collection When any coverage flag is used to Verilate, Verilator will add appropriate coverage point insertions into the model and collect the coverage data. -To get the coverage data from the model, in the user wrapper code, -typically at the end once a test passes, call -:code:`Verilated::threadContextp()->coveragep()->write` with an argument of the filename for -the coverage data file to write coverage data to (typically -"logs/coverage.dat"). +To get the coverage data from the model, write the coverage with either: + +1. Using :vlopt:`--binary` or :vlopt:`--main`, and Verilator will dump + coverage when the test completes to the filename specified with + :vlopt:`+verilator+coverage+file+\`. + +2. In the user wrapper code, typically at the end once a test passes, call + :code:`Verilated::threadContextp()->coveragep()->write` with an argument + of the filename for the coverage data file to write coverage data to + (typically "logs/coverage.dat"). Run each of your tests in different directories, potentially in parallel. -Each test will create a :file:`logs/coverage.dat` file. +Each test will create the file specified above, +e.g. :file:`logs/coverage.dat`. After running all of the tests, execute the :command:`verilator_coverage` command, passing arguments pointing to the filenames of all the diff --git a/include/verilated.cpp b/include/verilated.cpp index 73d3cee4f..20a2d8e91 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -2430,6 +2430,7 @@ VerilatedContext::VerilatedContext() : m_impdatap{new VerilatedContextImpData} { Verilated::lastContextp(this); Verilated::threadContextp(this); + m_ns.m_coverageFilename = "coverage.dat"; m_ns.m_profExecFilename = "profile_exec.dat"; m_ns.m_profVltFilename = "profile.vlt"; m_fdps.resize(31); @@ -2465,6 +2466,14 @@ void VerilatedContext::calcUnusedSigs(bool flag) VL_MT_SAFE { const VerilatedLockGuard lock{m_mutex}; m_s.m_calcUnusedSigs = flag; } +void VerilatedContext::coverageFilename(const std::string& flag) VL_MT_SAFE { + const VerilatedLockGuard lock{m_mutex}; + m_ns.m_coverageFilename = flag; +} +std::string VerilatedContext::coverageFilename() const VL_MT_SAFE { + const VerilatedLockGuard lock{m_mutex}; + return m_ns.m_coverageFilename; +} void VerilatedContext::dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex) { const VerilatedLockGuard lock{m_timeDumpMutex}; m_dumpfile = flag; @@ -2705,7 +2714,9 @@ void VerilatedContextImp::commandArgVl(const std::string& arg) { if (0 == std::strncmp(arg.c_str(), "+verilator+", std::strlen("+verilator+"))) { std::string str; uint64_t u64; - if (arg == "+verilator+debug") { + if (commandArgVlString(arg, "+verilator+coverage+file+", str)) { + coverageFilename(str); + } else if (arg == "+verilator+debug") { Verilated::debug(4); } else if (commandArgVlUint64(arg, "+verilator+debugi+", u64, 0, std::numeric_limits::max())) { diff --git a/include/verilated.h b/include/verilated.h index 89181ace1..d12ac0148 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -385,6 +385,7 @@ protected: uint64_t m_profExecStart = 1; // +prof+exec+start time uint32_t m_profExecWindow = 2; // +prof+exec+window size // Slow path + std::string m_coverageFilename; // +coverage+file filename std::string m_profExecFilename; // +prof+exec+file filename std::string m_profVltFilename; // +prof+vlt filename } m_ns; @@ -576,6 +577,10 @@ public: VerilatedVirtualBase* enableExecutionProfiler(VerilatedVirtualBase* (*construct)(VerilatedContext&)); + // Internal: coverage + void coverageFilename(const std::string& flag) VL_MT_SAFE; + std::string coverageFilename() const VL_MT_SAFE; + // Internal: $dumpfile void dumpfile(const std::string& flag) VL_MT_SAFE_EXCLUDES(m_timeDumpMutex); std::string dumpfile() const VL_MT_SAFE_EXCLUDES(m_timeDumpMutex); diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index ea5d738fd..269597508 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -106,6 +106,7 @@ private: using ItemList = std::deque; // MEMBERS + VerilatedContext* const m_contextp; // Context VerilatedCovImp is pointed-to by mutable VerilatedMutex m_mutex; // Protects all members ValueIndexMap m_valueIndexes VL_GUARDED_BY(m_mutex); // Unique arbitrary value for values IndexValueMap m_indexValues VL_GUARDED_BY(m_mutex); // Unique arbitrary value for keys @@ -120,7 +121,8 @@ private: public: // CONSTRUCTORS - VerilatedCovImp() = default; + VerilatedCovImp(VerilatedContext* contextp) + : m_contextp{contextp} {} VL_UNCOPYABLE(VerilatedCovImp); protected: @@ -253,6 +255,7 @@ private: public: // PUBLIC METHODS + std::string defaultFilename() VL_MT_SAFE { return m_contextp->coverageFilename(); } void forcePerInstance(const bool flag) VL_MT_SAFE_EXCLUDES(m_mutex) { Verilated::quiesce(); const VerilatedLockGuard lock{m_mutex}; @@ -354,7 +357,7 @@ public: m_insertp = nullptr; } - void write(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) { + void write(const std::string& filename) VL_MT_SAFE_EXCLUDES(m_mutex) { Verilated::quiesce(); const VerilatedLockGuard lock{m_mutex}; selftest(); @@ -426,6 +429,7 @@ public: //============================================================================= // VerilatedCovContext +std::string VerilatedCovContext::defaultFilename() VL_MT_SAFE { return impp()->defaultFilename(); } void VerilatedCovContext::forcePerInstance(bool flag) VL_MT_SAFE { impp()->forcePerInstance(flag); } @@ -434,7 +438,9 @@ void VerilatedCovContext::clearNonMatch(const char* matchp) VL_MT_SAFE { impp()->clearNonMatch(matchp); } void VerilatedCovContext::zero() VL_MT_SAFE { impp()->zero(); } -void VerilatedCovContext::write(const char* filenamep) VL_MT_SAFE { impp()->write(filenamep); } +void VerilatedCovContext::write(const std::string& filename) VL_MT_SAFE { + impp()->write(filename); +} void VerilatedCovContext::_inserti(uint32_t* itemp) VL_MT_SAFE { impp()->inserti(new VerilatedCoverItemSpec{itemp}); } @@ -516,7 +522,7 @@ VerilatedCovContext* VerilatedContext::coveragep() VL_MT_SAFE { const VerilatedLockGuard lock{s_mutex}; // cppcheck-suppress identicalInnerCondition if (VL_LIKELY(!m_coveragep)) { // LCOV_EXCL_LINE // Not redundant, prevents race - m_coveragep.reset(new VerilatedCovImp); + m_coveragep.reset(new VerilatedCovImp{this}); } } return reinterpret_cast(m_coveragep.get()); diff --git a/include/verilated_cov.h b/include/verilated_cov.h index d759e1a9f..2be74336b 100644 --- a/include/verilated_cov.h +++ b/include/verilated_cov.h @@ -96,12 +96,13 @@ class VerilatedCovContext VL_NOT_FINAL : public VerilatedVirtualBase { public: // METHODS - /// Return default filename - static const char* defaultFilename() VL_PURE { return "coverage.dat"; } + /// Return default filename, may override with +verilator+coverage+file + std::string defaultFilename() VL_MT_SAFE; /// Make all data per_instance, overriding point's per_instance void forcePerInstance(bool flag) VL_MT_SAFE; /// Write all coverage data to a file - void write(const char* filenamep = defaultFilename()) VL_MT_SAFE; + void write(const std::string& filename) VL_MT_SAFE; + void write() VL_MT_SAFE { write(defaultFilename()); } /// Clear coverage points (and call delete on all items) void clear() VL_MT_SAFE; /// Clear items not matching the provided string @@ -170,11 +171,10 @@ class VerilatedCov final { public: // METHODS /// Return default filename for the current thread - static const char* defaultFilename() VL_PURE { return VerilatedCovContext::defaultFilename(); } + static std::string defaultFilename() VL_MT_SAFE { return threadCovp()->defaultFilename(); } /// Write all coverage data to a file for the current thread - static void write(const char* filenamep = defaultFilename()) VL_MT_SAFE { - threadCovp()->write(filenamep); - } + static void write(const std::string filename) VL_MT_SAFE { threadCovp()->write(filename); } + static void write() VL_MT_SAFE { write(defaultFilename()); } /// Clear coverage points (and call delete on all items) for the current thread static void clear() VL_MT_SAFE { threadCovp()->clear(); } /// Clear items not matching the provided string for the current thread diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index d267cba86..4adbab1e6 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -100,8 +100,16 @@ private: puts("}\n"); puts("\n"); - puts("// Final model cleanup\n"); + puts("// Execute 'final' processes\n"); puts("topp->final();\n"); + puts("\n"); + + if (v3Global.opt.coverage()) { + puts("// Write coverage data (since Verilated with --coverage)\n"); + puts("contextp->coveragep()->write();\n"); + puts("\n"); + } + puts("return 0;\n"); puts("}\n"); diff --git a/test_regress/t/t_cover_lib_c.cpp b/test_regress/t/t_cover_lib_c.cpp index 3ba805720..2e29e0214 100644 --- a/test_regress/t/t_cover_lib_c.cpp +++ b/test_regress/t/t_cover_lib_c.cpp @@ -64,7 +64,7 @@ int main() { coverw[5] = 300; #ifdef T_COVER_LIB - TEST_CHECK_CSTR(covContextp->defaultFilename(), "coverage.dat"); + TEST_CHECK_EQ(covContextp->defaultFilename(), "coverage.dat"); covContextp->write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage1.dat"); covContextp->forcePerInstance(true); covContextp->write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage1_per_instance.dat"); @@ -74,16 +74,20 @@ int main() { covContextp->zero(); covContextp->write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage3.dat"); covContextp->clear(); - covContextp->write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + Verilated::defaultContextp()->coverageFilename(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + TEST_CHECK_EQ(covContextp->defaultFilename(), VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + covContextp->write(); // Uses defaultFilename() #elif defined(T_COVER_LIB_LEGACY) - TEST_CHECK_CSTR(VerilatedCov::defaultFilename(), "coverage.dat"); + TEST_CHECK_EQ(VerilatedCov::defaultFilename(), "coverage.dat"); VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage1.dat"); VerilatedCov::clearNonMatch("kept_"); VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage2.dat"); VerilatedCov::zero(); VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage3.dat"); VerilatedCov::clear(); - VerilatedCov::write(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + Verilated::defaultContextp()->coverageFilename(VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + TEST_CHECK_EQ(VerilatedCov::defaultFilename(), VL_STRINGIFY(TEST_OBJ_DIR) "/coverage4.dat"); + VerilatedCov::write(); // Uses defaultFilename() #else #error #endif diff --git a/test_regress/t/t_cover_main.out b/test_regress/t/t_cover_main.out new file mode 100644 index 000000000..d762fd325 --- /dev/null +++ b/test_regress/t/t_cover_main.out @@ -0,0 +1,2 @@ +# SystemC::Coverage-3 +C 'ft/t_cover_main.vl9n4pagev_line/toblockS9-11hTOP.t' 1 diff --git a/test_regress/t/t_cover_main.pl b/test_regress/t/t_cover_main.pl new file mode 100755 index 000000000..efd553940 --- /dev/null +++ b/test_regress/t/t_cover_main.pl @@ -0,0 +1,25 @@ +#!/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(simulator => 1); + +compile( + verilator_flags2 => ['--binary --coverage-line'], + ); + +execute( + all_run_flags => [" +verilator+coverage+file+$Self->{obj_dir}/coverage_renamed.dat"], + check_finished => 1, + ); + +files_identical_sorted("$Self->{obj_dir}/coverage_renamed.dat", "t/t_cover_main.out"); + +ok(1); +1; diff --git a/test_regress/t/t_cover_main.v b/test_regress/t/t_cover_main.v new file mode 100644 index 000000000..4f5101d7d --- /dev/null +++ b/test_regress/t/t_cover_main.v @@ -0,0 +1,13 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/); + + initial begin + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 3a5248a9192b2831a81dc8a58b52016460346121 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sat, 20 Jan 2024 15:06:46 -0500 Subject: [PATCH 045/116] Internals: Mark structs final/VL_NOT_FINAL. No functional change intended. --- include/verilated.h | 6 +++--- include/verilated_imp.h | 4 ++-- include/verilated_profiler.cpp | 2 +- include/verilated_syms.h | 2 +- include/verilated_threads.h | 2 +- include/verilated_timing.h | 14 +++++++------- include/verilated_trace.h | 4 ++-- include/verilated_types.h | 4 ++-- include/verilated_vpi.cpp | 2 +- include/verilatedos.h | 2 +- src/V3Ast.h | 2 +- src/V3AstNodeDType.h | 2 +- src/V3Combine.cpp | 2 +- src/V3Coverage.cpp | 4 ++-- src/V3DfgAstToDfg.cpp | 2 +- src/V3DfgDecomposition.cpp | 2 +- src/V3DupFinder.h | 2 +- src/V3EmitCFunc.h | 2 +- src/V3EmitCSyms.cpp | 10 +++++----- src/V3Error.cpp | 2 +- src/V3Force.cpp | 4 ++-- src/V3FunctionTraits.h | 2 +- src/V3GraphAcyc.cpp | 2 +- src/V3GraphAlg.cpp | 4 ++-- src/V3GraphPathChecker.cpp | 2 +- src/V3Inline.cpp | 2 +- src/V3LanguageWords.h | 2 +- src/V3LifePost.cpp | 4 ++-- src/V3LinkDot.cpp | 2 +- src/V3LinkLevel.cpp | 2 +- src/V3MergeCond.cpp | 2 +- src/V3OptionParser.cpp | 2 +- src/V3Order.cpp | 2 +- src/V3PairingHeap.h | 4 ++-- src/V3Param.cpp | 2 +- src/V3ParseImp.h | 4 ++-- src/V3Partition.cpp | 16 ++++++++-------- src/V3Rtti.h | 4 ++-- src/V3Sched.cpp | 6 +++--- src/V3Scoreboard.cpp | 2 +- src/V3SplitVar.cpp | 12 ++++++------ src/V3Task.cpp | 2 +- src/V3ThreadPool.h | 2 +- src/V3Tristate.cpp | 2 +- src/V3VariableOrder.cpp | 2 +- src/V3WidthSel.cpp | 2 +- src/VlcTop.cpp | 2 +- test_regress/t/t_dist_portability.pl | 7 +++++-- 48 files changed, 88 insertions(+), 85 deletions(-) diff --git a/include/verilated.h b/include/verilated.h index d12ac0148..0f363f417 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -349,7 +349,7 @@ protected: // Slow path variables mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members - struct Serialized { // All these members serialized/deserialized + struct Serialized final { // All these members serialized/deserialized // No std::strings or pointers or will serialize badly! // Fast path bool m_assertOn = true; // Assertions are enabled @@ -379,7 +379,7 @@ protected: std::string m_timeFormatSuffix VL_GUARDED_BY(m_timeDumpMutex); // $timeformat printf format std::string m_dumpfile VL_GUARDED_BY(m_timeDumpMutex); // $dumpfile setting - struct NonSerialized { // Non-serialized information + struct NonSerialized final { // Non-serialized information // These are reloaded from on command-line settings, so do not need to persist // Fast path uint64_t m_profExecStart = 1; // +prof+exec+start time @@ -393,7 +393,7 @@ protected: mutable VerilatedMutex m_argMutex; // Protect m_argVec, m_argVecLoaded // no need to be save-restored (serialized) the // assumption is that the restore is allowed to pass different arguments - struct NonSerializedCommandArgs { + struct NonSerializedCommandArgs final { // Medium speed std::vector m_argVec; // Argument list bool m_argVecLoaded = false; // Ever loaded argument list diff --git a/include/verilated_imp.h b/include/verilated_imp.h index 1cb19dcc5..57626a2d2 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -54,7 +54,7 @@ class VerilatedScope; class VerilatedMsg final { public: // TYPES - struct Cmp { + struct Cmp final { bool operator()(const VerilatedMsg& a, const VerilatedMsg& b) const { return a.mtaskId() < b.mtaskId(); } @@ -221,7 +221,7 @@ class VerilatedContextImp final : VerilatedContext { // Internal note: Globals may multi-construct, see verilated.cpp top. // Medium speed, so uses singleton accessing - struct Statics { + struct Statics final { VerilatedMutex s_randMutex; // Mutex protecting s_randSeedEpoch // Number incrementing on each reseed, 0=illegal int s_randSeedEpoch = 1; // Reads ok, wish had a VL_WRITE_GUARDED_BY(s_randMutex) diff --git a/include/verilated_profiler.cpp b/include/verilated_profiler.cpp index f17db8ca6..4f19fc8c0 100644 --- a/include/verilated_profiler.cpp +++ b/include/verilated_profiler.cpp @@ -106,7 +106,7 @@ VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context) if (VlThreadPool* const threadPoolp = static_cast(context.threadPoolp())) { for (int i = 0; i < threadPoolp->numThreads(); ++i) { // Data to pass to worker thread initialization - struct Data { + struct Data final { VlExecutionProfiler* const selfp; const uint32_t threadId; } data{selfp, static_cast(i + 1)}; diff --git a/include/verilated_syms.h b/include/verilated_syms.h index 1793f8b79..f4eccb301 100644 --- a/include/verilated_syms.h +++ b/include/verilated_syms.h @@ -42,7 +42,7 @@ // Types // Class to sort maps keyed by const char*'s -struct VerilatedCStrCmp { +struct VerilatedCStrCmp final { bool operator()(const char* a, const char* b) const { return std::strcmp(a, b) < 0; } }; diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 5c4cd5691..12b552e59 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -127,7 +127,7 @@ public: class VlWorkerThread final { private: // TYPES - struct ExecRec { + struct ExecRec final { VlExecFnp m_fnp = nullptr; // Function to execute VlSelfP m_selfp = nullptr; // Symbol table to execute bool m_evenCycle = false; // Even/odd for flag alternation diff --git a/include/verilated_timing.h b/include/verilated_timing.h index 5d1403eb8..b222c360c 100644 --- a/include/verilated_timing.h +++ b/include/verilated_timing.h @@ -189,7 +189,7 @@ public: // Used by coroutines for co_awaiting a certain simulation time auto delay(uint64_t delay, VlProcessRef process, const char* filename = VL_UNKNOWN, int lineno = 0) { - struct Awaitable { + struct Awaitable final { VlProcessRef process; // Data of the suspended process, null if not needed VlDelayedCoroutineQueue& queue; std::vector& queueZeroDelay; @@ -260,7 +260,7 @@ public: const char* filename = VL_UNKNOWN, int lineno = 0) { VL_DEBUG_IF(VL_DBG_MSGF(" Suspending process waiting for %s at %s:%d\n", eventDescription, filename, lineno);); - struct Awaitable { + struct Awaitable final { VlCoroutineVec& suspended; // Coros waiting on trigger VlProcessRef process; // Data of the suspended process, null if not needed VlFileLineDebug fileline; @@ -308,7 +308,7 @@ class VlDynamicTriggerScheduler final { // METHODS auto awaitable(VlProcessRef process, VlCoroutineVec& queue, const char* filename, int lineno) { - struct Awaitable { + struct Awaitable final { VlProcessRef process; // Data of the suspended process, null if not needed VlCoroutineVec& suspended; // Coros waiting on trigger VlFileLineDebug fileline; @@ -362,7 +362,7 @@ public: // VlForever is a helper awaitable type for suspending coroutines forever. Used for constant // wait statements. -struct VlForever { +struct VlForever final { bool await_ready() const { return false; } // Always suspend void await_suspend(std::coroutine_handle<> coro) const { coro.destroy(); } void await_resume() const {} @@ -374,7 +374,7 @@ struct VlForever { class VlForkSync final { // VlJoin stores the handle of a suspended coroutine that did a fork..join or fork..join_any. // If the counter reaches 0, the suspended coroutine shall be resumed. - struct VlJoin { + struct VlJoin final { size_t m_counter = 0; // When reaches 0, resume suspended coroutine VlCoroutineHandle m_susp; // Coroutine to resume }; @@ -393,7 +393,7 @@ public: assert(m_join); VL_DEBUG_IF( VL_DBG_MSGF(" Awaiting join of fork at: %s:%d\n", filename, lineno);); - struct Awaitable { + struct Awaitable final { VlProcessRef process; // Data of the suspended process, null if not needed const std::shared_ptr join; // Join to await on VlFileLineDebug fileline; @@ -415,7 +415,7 @@ public: class VlCoroutine final { private: // TYPES - struct VlPromise { + struct VlPromise final { std::coroutine_handle<> m_continuation; // Coroutine to resume after this one finishes VlCoroutine* m_corop = nullptr; // Pointer to the coroutine return object diff --git a/include/verilated_trace.h b/include/verilated_trace.h index cdf42adf1..8224d73a0 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -204,7 +204,7 @@ private: friend Buffer; friend OffloadBuffer; - struct CallbackRecord { + struct CallbackRecord final { // Note: would make these fields const, but some old STL implementations // (the one in Ubuntu 14.04 with GCC 4.8.4 in particular) use the // assignment operator on inserting into collections, so they don't work @@ -238,7 +238,7 @@ private: bool m_offload = false; // Use the offload thread bool m_parallel = false; // Use parallel tracing - struct ParallelWorkerData { + struct ParallelWorkerData final { const dumpCb_t m_cb; // The callback void* const m_userp; // The use pointer to pass to the callback Buffer* const m_bufp; // The buffer pointer to pass to the callback diff --git a/include/verilated_types.h b/include/verilated_types.h index 13a979faa..63630d595 100644 --- a/include/verilated_types.h +++ b/include/verilated_types.h @@ -1592,7 +1592,7 @@ public: // Represents the null pointer. Used for setting VlClassRef to null instead of // via nullptr_t, to prevent the implicit conversion of 0 to nullptr. -struct VlNull { +struct VlNull final { operator bool() const { return false; } }; @@ -1751,7 +1751,7 @@ template class VlSampleQueue final { // TYPES // Type representing a single value sample at a point in time - struct VlSample { + struct VlSample final { uint64_t m_timestamp; // Timestamp at which the value was sampled T_Sampled m_value; // The sampled value }; diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index 151393cf9..789065e8b 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -604,7 +604,7 @@ public: void invalidate() { m_id = 0; } }; -struct VerilatedVpiTimedCbsCmp { +struct VerilatedVpiTimedCbsCmp final { // Ordering sets keyed by time, then callback unique id bool operator()(const std::pair& a, const std::pair& b) const { diff --git a/include/verilatedos.h b/include/verilatedos.h index 57e7b8e9c..dadd06ac0 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -612,7 +612,7 @@ static inline double VL_ROUND(double n) { namespace vlstd { template -struct reverse_wrapper { +struct reverse_wrapper final { const T& m_v; explicit reverse_wrapper(const T& a_v) diff --git a/src/V3Ast.h b/src/V3Ast.h index af40b6ad9..de4b6be6c 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -98,7 +98,7 @@ using MTaskIdSet = std::set; // Set of mtaskIds for Var sorting //###################################################################### -struct VNTypeInfo { +struct VNTypeInfo final { const char* m_namep; enum uint8_t { OP_UNUSED, diff --git a/src/V3AstNodeDType.h b/src/V3AstNodeDType.h index a179a011b..d014bd205 100644 --- a/src/V3AstNodeDType.h +++ b/src/V3AstNodeDType.h @@ -339,7 +339,7 @@ public: class AstBasicDType final : public AstNodeDType { // Builtin atomic/vectored data type // @astgen op1 := rangep : Optional[AstRange] // Range of variable - struct Members { + struct Members final { VBasicDTypeKwd m_keyword; // (also in VBasicTypeKey) What keyword created basic type VNumRange m_nrange; // (also in VBasicTypeKey) Numeric msb/lsb (if non-opaque keyword) bool operator==(const Members& rhs) const { diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index 40dbbe7f6..45160d3f3 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -43,7 +43,7 @@ class CombineVisitor final : VNVisitor { // TYPES using funcit_t = std::list::iterator; - struct CFuncs { + struct CFuncs final { std::list m_fast; std::list m_slow; }; diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index dcddd0c99..9b9e119ed 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -39,7 +39,7 @@ class CoverageVisitor final : public VNVisitor { // TYPES using LinenoSet = std::set; - struct ToggleEnt { + struct ToggleEnt final { const string m_comment; // Comment for coverage dump AstNodeExpr* m_varRefp; // How to get to this element AstNodeExpr* m_chgRefp; // How to get to this element @@ -54,7 +54,7 @@ class CoverageVisitor final : public VNVisitor { } }; - struct CheckState { // State save-restored on each new coverage scope/block + struct CheckState final { // State save-restored on each new coverage scope/block bool m_on = false; // Should this block get covered? bool m_inModOff = false; // In module with no coverage int m_handle = 0; // Opaque handle for index into line tracking diff --git a/src/V3DfgAstToDfg.cpp b/src/V3DfgAstToDfg.cpp index 9310e9081..5c5e326d4 100644 --- a/src/V3DfgAstToDfg.cpp +++ b/src/V3DfgAstToDfg.cpp @@ -77,7 +77,7 @@ class AstToDfgVisitor final : public VNVisitor { // TYPES // Represents a driver during canonicalization - struct Driver { + struct Driver final { FileLine* m_fileline; DfgVertex* m_vtxp; uint32_t m_lsb; diff --git a/src/V3DfgDecomposition.cpp b/src/V3DfgDecomposition.cpp index d7a96abff..d3e7a420f 100644 --- a/src/V3DfgDecomposition.cpp +++ b/src/V3DfgDecomposition.cpp @@ -122,7 +122,7 @@ class ExtractCyclicComponents final { static constexpr size_t UNASSIGNED = std::numeric_limits::max(); // TYPES - struct VertexState { + struct VertexState final { size_t index = UNASSIGNED; // Used by Pearce's algorithm for detecting SCCs size_t component = UNASSIGNED; // Result component number (0 stays in input graph) bool merged = false; // Visited in the merging pass diff --git a/src/V3DupFinder.h b/src/V3DupFinder.h index 14c74d714..11641b7ff 100644 --- a/src/V3DupFinder.h +++ b/src/V3DupFinder.h @@ -33,7 +33,7 @@ //============================================================================ -struct V3DupFinderUserSame { +struct V3DupFinderUserSame VL_NOT_FINAL { // Functor for V3DupFinder::findDuplicate virtual bool isSame(AstNode*, AstNode*) = 0; V3DupFinderUserSame() = default; diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 0ae6f53ec..7c85832c7 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -124,7 +124,7 @@ class EmitCFunc VL_NOT_FINAL : public EmitCConstInit { bool m_emitConstInit = false; // Emitting constant initializer // State associated with processing $display style string formatting - struct EmitDispState { + struct EmitDispState final { string m_format; // "%s" and text from user std::vector m_argsChar; // Format of each argument to be printed std::vector m_argsp; // Each argument to be printed diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index a2c253150..38af0222a 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -39,7 +39,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { const VNUser1InUse m_inuser1; // TYPES - struct ScopeData { + struct ScopeData final { const string m_symName; const string m_prettyName; const int m_timeunit; @@ -51,7 +51,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { , m_timeunit{timeunit} , m_type{type} {} }; - struct ScopeFuncData { + struct ScopeFuncData final { AstScopeName* const m_scopep; AstCFunc* const m_cfuncp; AstNodeModule* const m_modp; @@ -60,7 +60,7 @@ class EmitCSyms final : EmitCBaseVisitorConst { , m_cfuncp{funcp} , m_modp{modp} {} }; - struct ScopeVarData { + struct ScopeVarData final { const string m_scopeName; const string m_varBasePretty; AstVar* const m_varp; @@ -79,12 +79,12 @@ class EmitCSyms final : EmitCBaseVisitorConst { using ModVarPair = std::pair; using ScopeNameList = std::vector; using ScopeNameHierarchy = std::map; - struct CmpName { + struct CmpName final { bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { return lhsp.first->name() < rhsp.first->name(); } }; - struct CmpDpi { + struct CmpDpi final { bool operator()(const AstCFunc* lhsp, const AstCFunc* rhsp) const { if (lhsp->dpiImportPrototype() != rhsp->dpiImportPrototype()) { // cppcheck-suppress comparisonOfFuncReturningBoolError diff --git a/src/V3Error.cpp b/src/V3Error.cpp index c490fd00f..8c0eb6935 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -27,7 +27,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //====================================================================== -struct v3errorIniter { +struct v3errorIniter final { v3errorIniter() { V3Error::init(); } }; v3errorIniter v3errorInit; diff --git a/src/V3Force.cpp b/src/V3Force.cpp index 0141efcbf..d59389f61 100644 --- a/src/V3Force.cpp +++ b/src/V3Force.cpp @@ -50,7 +50,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; class ForceConvertVisitor final : public VNVisitor { // TYPES - struct ForceComponentsVar { + struct ForceComponentsVar final { AstVar* const m_rdVarp; // New variable to replace read references with AstVar* const m_valVarp; // Forced value AstVar* const m_enVarp; // Force enabled signal @@ -76,7 +76,7 @@ class ForceConvertVisitor final : public VNVisitor { } }; - struct ForceComponentsVarScope { + struct ForceComponentsVarScope final { AstVarScope* const m_rdVscp; // New variable to replace read references with AstVarScope* const m_enVscp; // Force enabled signal AstVarScope* const m_valVscp; // Forced value diff --git a/src/V3FunctionTraits.h b/src/V3FunctionTraits.h index c9d39670f..02acf2c8a 100644 --- a/src/V3FunctionTraits.h +++ b/src/V3FunctionTraits.h @@ -42,7 +42,7 @@ struct FunctionTraits VL_NOT_FINAL { // Type of arguments template - struct arg { + struct arg final { using type = typename std::tuple_element>::type; }; }; diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 994bb7bd2..e6dc74446 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -80,7 +80,7 @@ public: //-------------------------------------------------------------------- -struct GraphAcycEdgeCmp { +struct GraphAcycEdgeCmp final { bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { if (lhsp->weight() > rhsp->weight()) return true; // LHS goes first if (lhsp->weight() < rhsp->weight()) return false; // RHS goes first diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index c64751d9d..f6bbfc92b 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -422,12 +422,12 @@ void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Grap //###################################################################### // Algorithms - sorting -struct GraphSortVertexCmp { +struct GraphSortVertexCmp final { bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } }; -struct GraphSortEdgeCmp { +struct GraphSortEdgeCmp final { bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index b9157c647..b528714d9 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -27,7 +27,7 @@ //###################################################################### // GraphPCNode -struct GraphPCNode { +struct GraphPCNode final { // User data for each node in GraphPathChecker. // // Like the LogicMTasks's, store before and after CPs for the nodes in diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 638393cd7..b7152fa80 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -45,7 +45,7 @@ static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can namespace { -struct ModuleState { +struct ModuleState final { bool m_inlined = false; // Whether to inline this module unsigned m_cellRefs = 0; // Number of AstCells instantiating this module std::vector m_childCells; // AstCells under this module (to speed up traversal) diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h index 3da1019cb..31a33eae3 100644 --- a/src/V3LanguageWords.h +++ b/src/V3LanguageWords.h @@ -28,7 +28,7 @@ class V3LanguageWords final { // List of common reserved keywords private: using KeywordMap = std::map; - struct Singleton { + struct Singleton final { KeywordMap s_kwdMap; // List of keywords, and what language applies Singleton() { init(); } void addKwd(const string& kwd, const string& why) { s_kwdMap.emplace(kwd, why); } diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 4855f800d..468e06863 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -95,7 +95,7 @@ public: // Location within the execution graph, identified by an mtask // and a sequence number within the mtask: -struct LifeLocation { +struct LifeLocation final { const ExecMTask* mtaskp = nullptr; uint32_t sequence = 0; @@ -113,7 +113,7 @@ public: } }; -struct LifePostLocation { +struct LifePostLocation final { LifeLocation loc; AstAssignPost* nodep = nullptr; LifePostLocation() = default; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 06bd30b9c..2d0887306 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2038,7 +2038,7 @@ class LinkDotResolveVisitor final : public VNVisitor { bool m_explicitSuperNew = false; // Hit a "super.new" call inside a "new" function std::map m_usedPins; // Pin used in this cell, map to duplicate - struct DotStates { + struct DotStates final { DotPosition m_dotPos; // Scope part of dotted resolution VSymEnt* m_dotSymp; // SymEnt for dotted AstParse lookup const AstDot* m_dotp; // Current dot diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index 4fbdc657f..2948e750f 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -30,7 +30,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; //###################################################################### // Levelizing class functions -struct CmpLevel { +struct CmpLevel final { bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const { return lhsp->level() < rhsp->level(); } diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index 82add8465..c743c4ad3 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -132,7 +132,7 @@ bool areDisjoint(const std::set& a, const std::set //###################################################################### // Structure containing information required for code motion/merging -struct StmtProperties { +struct StmtProperties final { AstNodeExpr* m_condp = nullptr; // The condition expression, if a conditional node std::set m_rdVars; // Variables read by this statement std::set m_wrVars; // Variables written by this statement diff --git a/src/V3OptionParser.cpp b/src/V3OptionParser.cpp index be65611be..caec1c707 100644 --- a/src/V3OptionParser.cpp +++ b/src/V3OptionParser.cpp @@ -26,7 +26,7 @@ //###################################################################### // V3OptionParser::Impl -struct V3OptionParser::Impl { +struct V3OptionParser::Impl final { // TYPES // Setting for isOnOffAllowed() and isPartialMatchAllowed() diff --git a/src/V3Order.cpp b/src/V3Order.cpp index cb5266bf9..0d155acc5 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -838,7 +838,7 @@ class OrderProcess final { int& newStmtsr); // processMTask* routines schedule threaded execution - struct MTaskState { + struct MTaskState final { AstMTaskBody* m_mtaskBodyp = nullptr; std::list m_logics; ExecMTask* m_execMTaskp = nullptr; diff --git a/src/V3PairingHeap.h b/src/V3PairingHeap.h index 6b70b7ed6..32c451f9c 100644 --- a/src/V3PairingHeap.h +++ b/src/V3PairingHeap.h @@ -41,7 +41,7 @@ public: // Just a pointer to a heap Node, but with special accessors to help keep back pointers // consistent. - struct Link { + struct Link final { Node* m_ptr = nullptr; // The managed pointer Link() = default; @@ -89,7 +89,7 @@ public: }; // A single node in the pairing heap tree - struct Node { + struct Node VL_NOT_FINAL { Link m_next; // Next in list of sibling heaps Link m_kids; // Head of list of child heaps Node** m_ownerpp = nullptr; // Pointer to the Link pointer pointing to this heap diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 5169ae83b..57de34d20 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -248,7 +248,7 @@ class ParamProcessor final { // STATE using CloneMap = std::unordered_map; - struct ModInfo { + struct ModInfo final { AstNodeModule* const m_modp; // Module with specified name CloneMap m_cloneMap; // Map of old-varp -> new cloned varp explicit ModInfo(AstNodeModule* modp) diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index 6142e5326..bc15eb068 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -45,7 +45,7 @@ enum V3ImportProperty : uint8_t { iprop_NONE, iprop_CONTEXT, iprop_PURE }; //============================================================================ // Member qualifiers -struct VMemberQualifiers { +struct VMemberQualifiers final { union { uint32_t m_flags; struct { @@ -99,7 +99,7 @@ struct VMemberQualifiers { // Parser YYSType, e.g. for parser's yylval // We can't use bison's %union as we want to pass the fileline with all tokens -struct V3ParseBisonYYSType { +struct V3ParseBisonYYSType final { FileLine* fl; AstNode* scp; // Symbol table scope for future lookups int token; // Read token, aka tok diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index ac3a7dbfb..0b1d20611 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -154,7 +154,7 @@ static void partCheckCachedScoreVsActual(uint32_t cached, uint32_t actual) { //============================================================================= // We keep MTaskEdge graph edges in a PairingHeap, sorted by score and id -struct EdgeKey { +struct EdgeKey final { // Node: Structure layout chosen to minimize padding in PairingHeao<*>::Node uint64_t m_id; // Unique ID part of edge score uint32_t m_score; // Score part of ID @@ -183,7 +183,7 @@ public: // TYPES using VxList = std::list; - struct CmpLogicMTask { + struct CmpLogicMTask final { bool operator()(const LogicMTask* ap, const LogicMTask* bp) const { return ap->id() < bp->id(); } @@ -404,7 +404,7 @@ struct MTaskIdLessThan final { } }; -struct MergeCandidateKey { +struct MergeCandidateKey final { // Note: Structure layout chosen to minimize padding in PairingHeao<*>::Node uint64_t m_id; // Unique ID part of edge score uint32_t m_score; // Score part of ID @@ -895,7 +895,7 @@ class PartPropagateCp final { // TYPES // We keep pending vertices in a heap during critical path propagation - struct PendingKey { + struct PendingKey final { LogicMTask* m_mtaskp; // The vertex in the heap uint32_t m_score; // The score of this entry void increase(uint32_t score) { @@ -1236,7 +1236,7 @@ static void partRedirectEdgesFrom(V3Graph* graphp, LogicMTask* recipientp, Logic class PartContraction final { // TYPES // New CP information for mtaskp reflecting an upcoming merge - struct NewCp { + struct NewCp final { uint32_t cp; uint32_t propagateCp; bool propagate; @@ -1673,7 +1673,7 @@ private: // and swap these sorting records very efficiently. With this the standard library sorting // functions are efficient enough and using more optimized methods (e.g.: sorting networks) // has no measurable benefit. - struct alignas(16) SortingRecord { + struct alignas(16) SortingRecord final { uint64_t m_id; uint32_t m_cp; uint8_t m_idx; @@ -2170,7 +2170,7 @@ public: static constexpr uint32_t UNASSIGNED = 0xffffffff; // TYPES - struct MTaskState { + struct MTaskState final { uint32_t completionTime = 0; // Estimated time this mtask will complete uint32_t threadId = UNASSIGNED; // Thread id this MTask is assigned to const ExecMTask* nextp = nullptr; // Next MTask on same thread after this @@ -2320,7 +2320,7 @@ void ThreadSchedule::dumpDotFile(const V3Graph& graph, const string& filename) c // "padding" avoids tight "layovers" at cross-thread dependencies. class PartPackMTasks final { // TYPES - struct MTaskCmp { + struct MTaskCmp final { bool operator()(const ExecMTask* ap, const ExecMTask* bp) const { return ap->id() < bp->id(); } diff --git a/src/V3Rtti.h b/src/V3Rtti.h index 87f2b2e2e..e671a4d50 100644 --- a/src/V3Rtti.h +++ b/src/V3Rtti.h @@ -25,7 +25,7 @@ // Holds list of types as template parameter pack. // Useful in compile-time code generation. template -struct VTypeList { +struct VTypeList final { template constexpr VTypeList operator+(VTypeList) const { return {}; @@ -36,7 +36,7 @@ struct VTypeList { // Can be safely used as a return or argument type, and even instantiated, without triggering any // potential limitations or effects of the held type. template -struct VTypeWrapper { +struct VTypeWrapper final { using type_t = T; }; diff --git a/src/V3Sched.cpp b/src/V3Sched.cpp index 331301a88..b56552c9e 100644 --- a/src/V3Sched.cpp +++ b/src/V3Sched.cpp @@ -167,7 +167,7 @@ AstNodeStmt* profExecSectionPop(FileLine* flp) { return new AstCStmt{flp, "VL_EXEC_TRACE_ADD_RECORD(vlSymsp).sectionPop();\n"}; } -struct EvalLoop { +struct EvalLoop final { // Flag set to true during the first iteration of the loop AstVarScope* firstIterp; // The loop itself and statements around it @@ -491,7 +491,7 @@ void createFinal(AstNetlist* netlistp, const LogicClasses& logicClasses) { //============================================================================ // A TriggerKit holds all the components related to a TRIGGERVEC variable -struct TriggerKit { +struct TriggerKit final { // The TRIGGERVEC AstVarScope representing these trigger flags AstVarScope* const m_vscp; // The AstCFunc that computes the current active triggers @@ -532,7 +532,7 @@ struct TriggerKit { //============================================================================ // EvalKit groups items that have to be passed to createEval() for a given eval region -struct EvalKit { +struct EvalKit final { // The TRIGGERVEC AstVarScope representing the region's trigger flags AstVarScope* const m_vscp = nullptr; // The AstCFunc that computes the region's active triggers diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp index 517d59917..0628d05d6 100644 --- a/src/V3Scoreboard.cpp +++ b/src/V3Scoreboard.cpp @@ -20,7 +20,7 @@ class ScoreboardTestElem; -struct Key { +struct Key final { // Node: Structure layout chosen to minimize padding in PairingHeao<*>::Node uint64_t m_id; // Unique ID part of edge score uint32_t m_score; // Score part of ID diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 1247581db..fb42a9fe8 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -122,7 +122,7 @@ VL_DEFINE_DEBUG_FUNCTIONS; -struct SplitVarImpl { +struct SplitVarImpl VL_NOT_FINAL { // NODE STATE // AstNodeModule::user1() -> Block number counter for generating unique names const VNUser1InUse m_user1InUse; // Only used in SplitUnpackedVarVisitor @@ -239,7 +239,7 @@ static void warnNoSplit(const AstVar* varp, const AstNode* wherep, const char* r // AstSliceSel -> Create a temporary variable and refer the variable // Compare AstNode* to get deterministic ordering when showing messages. -struct AstNodeComparator { +struct AstNodeComparator final { bool operator()(const AstNode* ap, const AstNode* bp) const { const int lineComp = ap->fileline()->operatorCompare(*bp->fileline()); if (lineComp != 0) return lineComp < 0; @@ -346,7 +346,7 @@ public: }; // Found nodes for SplitPackedVarVisitor -struct RefsInModule { +struct RefsInModule final { std::set m_vars; std::set m_refs; std::set m_sels; @@ -356,7 +356,7 @@ public: void add(AstVarRef* nodep) { m_refs.insert(nodep); } void add(AstSel* nodep) { m_sels.insert(nodep); } void remove(AstNode* nodep) { - struct Visitor : public VNVisitor { + struct Visitor final : public VNVisitor { RefsInModule& m_parent; void visit(AstNode* nodep) override { iterateChildren(nodep); } void visit(AstVar* nodep) override { m_parent.m_vars.erase(nodep); } @@ -812,7 +812,7 @@ public: } AstVar* varp() const { return m_varp; } - struct Match { + struct Match final { bool operator()(int bit, const SplitNewVar& a) const { return bit < a.m_lsb + a.m_bitwidth; } @@ -854,7 +854,7 @@ public: // How a variable is used class PackedVarRef final { - struct SortByFirst { + struct SortByFirst final { bool operator()(const std::pair& a, const std::pair& b) const { if (a.first == b.first) return a.second < b.second; return a.first < b.first; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 62d0f8c05..7c589b7b9 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -284,7 +284,7 @@ public: //###################################################################### // DPI related utility functions -struct TaskDpiUtils { +struct TaskDpiUtils final { static std::vector> unpackDimsAndStrides(AstNodeDType* dtypep) { std::vector> dimStrides; diff --git a/src/V3ThreadPool.h b/src/V3ThreadPool.h index 2b28619b7..2d552c10a 100644 --- a/src/V3ThreadPool.h +++ b/src/V3ThreadPool.h @@ -38,7 +38,7 @@ // Callable, type-erased wrapper for std::packaged_task with any Signature. class VAnyPackagedTask final { // TYPES - struct PTWrapperBase { + struct PTWrapperBase VL_NOT_FINAL { virtual ~PTWrapperBase() {} virtual void operator()() = 0; }; diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 56cf939f8..3dfba47b1 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -408,7 +408,7 @@ class TristateVisitor final : public TristateBaseVisitor { AstUser3Allocator m_varAux; // TYPES - struct RefStrength { + struct RefStrength final { AstVarRef* m_varrefp; VStrength m_strength; RefStrength(AstVarRef* varrefp, VStrength strength) diff --git a/src/V3VariableOrder.cpp b/src/V3VariableOrder.cpp index cc02a8a6c..2514b88de 100644 --- a/src/V3VariableOrder.cpp +++ b/src/V3VariableOrder.cpp @@ -78,7 +78,7 @@ class VariableOrder final { // AstVar::user1() -> attributes, via m_attributes const VNUser1InUse m_user1InUse; // AstVar - struct VarAttributes { + struct VarAttributes final { uint32_t stratum; // Roughly equivalent to alignment requirement, to avoid padding bool anonOk; // Can be emitted as part of anonymous structure }; diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index 3935d083b..12b8d6e66 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -57,7 +57,7 @@ class WidthSelVisitor final : public VNVisitor { } // RETURN TYPE - struct FromData { + struct FromData final { AstNodeDType* const m_errp; // Node that was found, for error reporting if not known type AstNodeDType* const m_dtypep; // Data type for the 'from' slice VNumRange m_fromRange; // Numeric range bounds for the 'from' slice diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index 7d9c83659..d936e5cd5 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -126,7 +126,7 @@ void VlcTop::writeInfo(const string& filename) { //******************************************************************** -struct CmpComputrons { +struct CmpComputrons final { bool operator()(const VlcTest* lhsp, const VlcTest* rhsp) const { if (lhsp->computrons() != rhsp->computrons()) { return lhsp->computrons() < rhsp->computrons(); diff --git a/test_regress/t/t_dist_portability.pl b/test_regress/t/t_dist_portability.pl index 58b8a6e00..c9db4eb9a 100755 --- a/test_regress/t/t_dist_portability.pl +++ b/test_regress/t/t_dist_portability.pl @@ -87,15 +87,18 @@ sub vsnprintf { sub final { # Note do not do test_regress, as VPI files need to compile without verilatedos.h my $files = "src/*.c* src/*.h include/*.c* include/*.h"; - my $cmd = "cd $root && grep -n -P '(class)' $files | sort"; + my $cmd = "cd $root && grep -n -P '(class|struct)' $files | sort"; print "C $cmd\n"; my $grep = `$cmd`; my %names; foreach my $line (split /\n/, $grep) { - if ($line =~ /:\s*class /) { + if ($line =~ /:\s*(class|struct) /) { next if $line =~ /final|VL_NOT_FINAL/; next if $line =~ /{}/; # e.g. 'class Foo {};' next if $line =~ /;/; # e.g. 'class Foo;' + next if $line =~ /(class|struct)\s+{/; # e.g. anon 'class {' + next if $line =~ /struct std::/; + next if $line !~ /{/; print "$line\n"; $names{$1} = 1; } From 50df902b545e9731cb069ac169d20358e4f01588 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Sun, 21 Jan 2024 21:25:24 +0900 Subject: [PATCH 046/116] Fix incorrect bit-op-tree NOT optimization (#4832) (#4847) * Fix #4832. Bit-op-tree opt. should not touch a subtree under NOT in AND/OR tree. --- src/V3Const.cpp | 3 +++ test_regress/t/t_const_opt.v | 31 +++++++++++++++++++++++++++++-- 2 files changed, 32 insertions(+), 2 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 0b12137e1..e6ef5843e 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -541,6 +541,8 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { CONST_BITOP_RETURN_IF(m_failed, nodep->rhsp()); restorer.disableRestore(); // Now all checks passed } else if (nodep->type() == m_rootp->type()) { // And, Or, Xor + // subtree under NOT can be optimized only in XOR tree. + CONST_BITOP_RETURN_IF(!m_polarity && !isXorTree(), nodep); incrOps(nodep, __LINE__); for (const bool right : {false, true}) { VL_RESTORER(m_leafp); @@ -556,6 +558,7 @@ class ConstBitOpTreeVisitor final : public VNVisitorConst { // Reach past a cast then add to frozen nodes to be added to final reduction if (const AstCCast* const castp = VN_CAST(opp, CCast)) opp = castp->lhsp(); const bool pol = isXorTree() || m_polarity; // Only AND/OR tree needs polarity + UASSERT(pol, "AND/OR tree expects m_polarity==true"); m_frozenNodes.emplace_back(opp, FrozenNodeInfo{pol, m_lsb}); m_failed = origFailed; continue; diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index ff0cebd38..37e7568bb 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -62,7 +62,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'hf5498264b93d4b48 +`define EXPECTED_SUM 64'h7f4e4dade589ada1 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -93,10 +93,11 @@ module Test(/*AUTOARG*/ logic bug3786_out; logic bug3824_out; logic bug4059_out; + logic bug4832_out; output logic o; - logic [14:0] tmp; + logic [15:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -127,6 +128,7 @@ module Test(/*AUTOARG*/ tmp[12]<= bug3786_out; tmp[13]<= bug3824_out; tmp[14]<= bug4059_out; + tmp[15]<= bug4832_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); @@ -138,6 +140,7 @@ module Test(/*AUTOARG*/ bug3786 i_bug3786(.clk(clk), .in(d), .out(bug3786_out)); bug3824 i_bug3824(.clk(clk), .in(d), .out(bug3824_out)); bug4059 i_bug4059(.clk(clk), .in(d), .out(bug4059_out)); + bug4832 i_bug4832(.clk(clk), .in(d), .out(bug4832_out)); endmodule @@ -395,3 +398,27 @@ module bug4059(input wire clk, input wire [31:0] in, output wire out); wire _013_ = ~(_009_ ^ _012_); assign out = ~(_006_ ^ _013_); endmodule + +/// See issue #4832 +// !(d[32 + 3] & in[3]) & d[32 + 22] +// was wrongly transformed to +// !d[32 + 3] & d[32 + 22] & !in[3] +// A subtree under NOT should be untouched, but was not. +// Testing OR subtree too. +module bug4832(input wire clk, input wire [31:0] in, output out); + logic [95:0] d; + always_ff @(posedge clk) + d <= {d[63:0], in}; + + logic [31:0] tmp_and; + logic [31:0] tmp_or; + logic result_and; + logic result_or; + assign tmp_and = (d[63:32] & in) >> 3; + assign tmp_or = (d[63:32] | in) >> 8; + always_ff @(posedge clk) begin + result_and <= !tmp_and[0] & d[32 + 22]; + result_or <= !tmp_or[0] | d[32 + 21]; + end + assign out = result_and ^ result_or; +endmodule From 6b8531f0a647c14ee7045ce707b3cf1961fc84d2 Mon Sep 17 00:00:00 2001 From: Yutetsu TAKATSUKASA Date: Mon, 22 Jan 2024 00:30:01 +0900 Subject: [PATCH 047/116] Fix widthMin in replaceShiftOp (#4837) (#4841) (#4849) --- src/V3Const.cpp | 3 +++ test_regress/t/t_const_opt.v | 32 ++++++++++++++++++++++++++++++-- 2 files changed, 33 insertions(+), 2 deletions(-) diff --git a/src/V3Const.cpp b/src/V3Const.cpp index e6ef5843e..522c0c3a6 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -1892,6 +1892,8 @@ class ConstVisitor final : public VNVisitor { } void replaceShiftOp(AstNodeBiop* nodep) { UINFO(5, "SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) " << nodep << endl); + const int width = nodep->width(); + const int widthMin = nodep->widthMin(); VNRelinker handle; nodep->unlinkFrBack(&handle); AstNodeBiop* const lhsp = VN_AS(nodep->lhsp(), NodeBiop); @@ -1908,6 +1910,7 @@ class ConstVisitor final : public VNVisitor { AstNodeBiop* const newp = lhsp; newp->lhsp(shift1p); newp->rhsp(shift2p); + newp->dtypeChgWidth(width, widthMin); // The new AND must have width of the original SHIFT handle.relink(newp); iterate(newp); // Further reduce, either node may have more reductions. } diff --git a/test_regress/t/t_const_opt.v b/test_regress/t/t_const_opt.v index 37e7568bb..3151eb44d 100644 --- a/test_regress/t/t_const_opt.v +++ b/test_regress/t/t_const_opt.v @@ -62,7 +62,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'h7f4e4dade589ada1 +`define EXPECTED_SUM 64'hd1610f7181cbc1b4 if (sum !== `EXPECTED_SUM) $stop; $write("*-* All Finished *-*\n"); @@ -94,10 +94,11 @@ module Test(/*AUTOARG*/ logic bug3824_out; logic bug4059_out; logic bug4832_out; + logic bug4837_out; output logic o; - logic [15:0] tmp; + logic [16:0] tmp; assign o = ^tmp; always_ff @(posedge clk) begin @@ -129,6 +130,7 @@ module Test(/*AUTOARG*/ tmp[13]<= bug3824_out; tmp[14]<= bug4059_out; tmp[15]<= bug4832_out; + tmp[16]<= bug4837_out; end bug3182 i_bug3182(.in(d[4:0]), .out(bug3182_out)); @@ -141,6 +143,7 @@ module Test(/*AUTOARG*/ bug3824 i_bug3824(.clk(clk), .in(d), .out(bug3824_out)); bug4059 i_bug4059(.clk(clk), .in(d), .out(bug4059_out)); bug4832 i_bug4832(.clk(clk), .in(d), .out(bug4832_out)); + bug4837 i_bug4837(.clk(clk), .in(d), .out(bug4837_out)); endmodule @@ -422,3 +425,28 @@ module bug4832(input wire clk, input wire [31:0] in, output out); end assign out = result_and ^ result_or; endmodule + +/// See issue #4837 and $4841 +// replaceShiftOp() in V3Const did not update widthMin, then bit-op-tree opt. +// was wrongly triggered for the subtree. +// replaceShiftOp() transforms as below: +// SHIFT(AND(a,b),CONST)->AND(SHIFT(a,CONST),SHIFT(b,CONST)) +// AND after the transformation must have same minWidth as the original SHIFT +// e.g. SHIFTL(AND(a, b), 1) => AND(SHIFTL(a, 1), SHIFTL(b, 1)) +// AND in the result must have 1 bit larger widthMin than the original AND +module bug4837(input wire clk, input wire [31:0] in, output out); + logic [95:0] d; + always_ff @(posedge clk) + d <= {d[63:0], in}; + + wire celloutsig_0z; + wire [1:0] celloutsig_1z; + wire celloutsig_2z; + wire [95:0] out_data; + assign celloutsig_0z = d[83] < d[74]; + assign celloutsig_1z = { d[54], celloutsig_0z } & { d[42], celloutsig_0z }; + assign celloutsig_2z = d[65:64] < d[83:82]; + assign { out_data[33:32], out_data[0] } = { celloutsig_1z, celloutsig_2z }; + + assign out = out_data[33] ^ out_data[32] ^ out_data[0]; +endmodule From e3f3e3399f2995c643e31c26e766862318d50d40 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Jan 2024 13:50:27 -0500 Subject: [PATCH 048/116] Commentary: Changes update --- Changes | 6 ++++++ docs/spelling.txt | 2 ++ 2 files changed, 8 insertions(+) diff --git a/Changes b/Changes index 98c816c51..26be978b1 100644 --- a/Changes +++ b/Changes @@ -27,7 +27,13 @@ Verilator 5.021 devel * Fix `vpi_get()` and `vpi_get64()` to return vpiUndefined on errors (#4795). [Marlon James] * Fix VPI parameter iteration (#4798). [Marlon James] * Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright] +* Fix warnings in verilated_sc_trace.h for Clang. (#4807) (#4827). [Anthony Donlon] +* Fix null pointer dereference (#4810) (#4825). [Adrian Sampson] +* Fix maybe-uninitialized compiler warning (#4820) (#4822). [Larry Doolittle] * Fix mis-splitting of dump control functions (#4821). [Fan Shupei] +* Fix wrong utimes() parameter (#4829). [Szymon Gizler] +* Fix incorrect bit-op-tree NOT optimization (#4832) (#4847). [Yutetsu TAKATSUKASA] +* Fix width calculation in replaceShiftOp (#4837) (#4841) (#4849). [Yutetsu TAKATSUKASA] Verilator 5.020 2024-01-01 diff --git a/docs/spelling.txt b/docs/spelling.txt index 602f3b397..017b60fe9 100644 --- a/docs/spelling.txt +++ b/docs/spelling.txt @@ -902,6 +902,7 @@ recrem redeclaring regs reloop +replaceShiftOp resetall respecified rodata @@ -1015,6 +1016,7 @@ unsup untyped urandom uselib +utimes uwire uwires vc From 1a2c9ca813fe21ac146a64c5b9116e626e4cfd74 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Jan 2024 13:59:54 -0500 Subject: [PATCH 049/116] Updat GTKwave libraries from upstream --- include/gtkwave/fstapi.c | 216 ++- include/gtkwave/lz4.c | 3212 ++++++++++++++++++++++++----------- include/gtkwave/lz4.h | 1036 ++++++++--- include/verilated_fst_c.cpp | 1 + 4 files changed, 3193 insertions(+), 1272 deletions(-) diff --git a/include/gtkwave/fstapi.c b/include/gtkwave/fstapi.c index 1405878cb..91c5401ee 100644 --- a/include/gtkwave/fstapi.c +++ b/include/gtkwave/fstapi.c @@ -34,7 +34,6 @@ * FST_DEBUG : not for production use, only enable for development * FST_REMOVE_DUPLICATE_VC : glitch removal (has writer performance impact) * HAVE_LIBPTHREAD -> FST_WRITER_PARALLEL : enables inclusion of parallel writer code - * FST_DO_MISALIGNED_OPS (defined automatically for x86 and some others) : CPU architecture can handle misaligned loads/stores * _WAVE_HAVE_JUDY : use Judy arrays instead of Jenkins (undefine if LGPL is not acceptable) * */ @@ -132,10 +131,6 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 #define FST_GZIO_LEN (32768) #define FST_HDR_FOURPACK_DUO_SIZE (4*1024*1024) -#if defined(__i386__) || defined(__x86_64__) || defined(_AIX) || defined(__aarch64__) -#define FST_DO_MISALIGNED_OPS -#endif - #if defined(__APPLE__) && defined(__MACH__) #define FST_MACOSX #include @@ -192,6 +187,16 @@ void **JenkinsIns(void *base_i, const unsigned char *mem, uint32_t length, uint3 /* 01234567 */ +/* + * report abort messages + */ +static void chk_report_abort(const char *s) +{ +fprintf(stderr,"Triggered %s security check, exiting.\n", s); +abort(); +} + + /* * prevent old file overwrite when currently being read */ @@ -367,22 +372,15 @@ return ptr; /* * regular and variable-length integer access functions */ -#ifdef FST_DO_MISALIGNED_OPS -#define fstGetUint32(x) (*(uint32_t *)(x)) -#else static uint32_t fstGetUint32(unsigned char *mem) { uint32_t u32; unsigned char *buf = (unsigned char *)(&u32); -buf[0] = mem[0]; -buf[1] = mem[1]; -buf[2] = mem[2]; -buf[3] = mem[3]; +memcpy(buf, mem, sizeof(uint32_t)); return(*(uint32_t *)buf); } -#endif static int fstWriterUint64(FILE *handle, uint64_t v) @@ -550,7 +548,8 @@ return(rc); static uint32_t fstReaderVarint32(FILE *f) { -unsigned char buf[5]; +int chk_len = 5; /* TALOS-2023-1783 */ +unsigned char buf[chk_len]; unsigned char *mem = buf; uint32_t rc = 0; int ch; @@ -559,7 +558,9 @@ do { ch = fgetc(f); *(mem++) = ch; - } while(ch & 0x80); + } while((ch & 0x80) && (--chk_len)); + +if(ch & 0x80) chk_report_abort("TALOS-2023-1783"); mem--; for(;;) @@ -579,7 +580,8 @@ return(rc); static uint32_t fstReaderVarint32WithSkip(FILE *f, uint32_t *skiplen) { -unsigned char buf[5]; +int chk_len = 5; /* TALOS-2023-1783 */ +unsigned char buf[chk_len]; unsigned char *mem = buf; uint32_t rc = 0; int ch; @@ -588,7 +590,9 @@ do { ch = fgetc(f); *(mem++) = ch; - } while(ch & 0x80); + } while((ch & 0x80) && (--chk_len)); + +if(ch & 0x80) chk_report_abort("TALOS-2023-1783"); *skiplen = mem - buf; mem--; @@ -609,7 +613,8 @@ return(rc); static uint64_t fstReaderVarint64(FILE *f) { -unsigned char buf[16]; +int chk_len = 16; /* TALOS-2023-1783 */ +unsigned char buf[chk_len]; unsigned char *mem = buf; uint64_t rc = 0; int ch; @@ -618,9 +623,12 @@ do { ch = fgetc(f); *(mem++) = ch; - } while(ch & 0x80); + } while((ch & 0x80) && (--chk_len)); + +if(ch & 0x80) chk_report_abort("TALOS-2023-1783"); mem--; + for(;;) { rc <<= 7; @@ -851,11 +859,7 @@ unsigned char *pnt = buf; uint32_t nxt; uint32_t len; -#ifdef FST_DO_MISALIGNED_OPS -(*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); -#else memcpy(pnt, u, sizeof(uint32_t)); -#endif pnt += 4; while((nxt = v>>7)) @@ -878,11 +882,7 @@ unsigned char *pnt = buf; uint32_t nxt; uint32_t len; -#ifdef FST_DO_MISALIGNED_OPS -(*(uint32_t *)(pnt)) = (*(uint32_t *)(u)); -#else memcpy(pnt, u, sizeof(uint32_t)); -#endif pnt += 4; while((nxt = v>>7)) @@ -1542,7 +1542,7 @@ for(i=0;imaxhandle;i++) dmem = packmem = (unsigned char *)malloc(packmemlen = (wrlen * 2) + 2); } - rc = (xc->fourpack) ? LZ4_compress((char *)scratchpnt, (char *)dmem, wrlen) : fastlz_compress(scratchpnt, wrlen, dmem); + rc = (xc->fourpack) ? LZ4_compress_default((char *)scratchpnt, (char *)dmem, wrlen, packmemlen) : fastlz_compress(scratchpnt, wrlen, dmem); if(rc < destlen) { #ifndef FST_DYNAMIC_ALIAS_DISABLE @@ -1838,6 +1838,14 @@ if(xc->parallel_enabled) xc->xc_parent = xc; memcpy(xc2, xc, sizeof(struct fstWriterContext)); + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1777 for 32b overflow */ + uint64_t chk_64 = xc->maxhandle * 4 * sizeof(uint32_t); + size_t chk_32 = xc->maxhandle * 4 * sizeof(uint32_t); + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1777"); + } + xc2->valpos_mem = (uint32_t *)malloc(xc->maxhandle * 4 * sizeof(uint32_t)); memcpy(xc2->valpos_mem, xc->valpos_mem, xc->maxhandle * 4 * sizeof(uint32_t)); @@ -2101,7 +2109,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) { fstWriterMmapSanity(hmem = (unsigned char *)fstMmap(NULL, xc->hier_file_len, PROT_READ|PROT_WRITE, MAP_SHARED, fileno(xc->hier_handle), 0), __FILE__, __LINE__, "hmem"); } - packed_len = LZ4_compress((char *)hmem, (char *)mem, xc->hier_file_len); + packed_len = LZ4_compress_default((char *)hmem, (char *)mem, xc->hier_file_len, lz4_maxlen); fstMunmap(hmem, xc->hier_file_len); fourpack_duo = (!xc->repack_on_close) && (xc->hier_file_len > FST_HDR_FOURPACK_DUO_SIZE); /* double pack when hierarchy is large */ @@ -2114,7 +2122,7 @@ if(xc && !xc->already_in_close && !xc->already_in_flush) lz4_maxlen_duo = LZ4_compressBound(packed_len); mem_duo = (unsigned char *)malloc(lz4_maxlen_duo); - packed_len_duo = LZ4_compress((char *)mem, (char *)mem_duo, packed_len); + packed_len_duo = LZ4_compress_default((char *)mem, (char *)mem_duo, packed_len, lz4_maxlen_duo); fstWriterVarint(xc->handle, packed_len); /* 1st round compressed length */ fstFwrite(mem_duo, packed_len_duo, 1, xc->handle); @@ -3434,7 +3442,7 @@ return(rc); #ifndef FST_WRITEX_DISABLE -static void fstWritex(struct fstReaderContext *xc, void *v, int len) +static void fstWritex(struct fstReaderContext *xc, void *v, uint32_t len) /* TALOS-2023-1793: change len to unsigned */ { unsigned char *s = (unsigned char *)v; @@ -5060,6 +5068,7 @@ if(fv) for(;;) { uint32_t *tc_head = NULL; + uint32_t tc_head_items = 0; traversal_mem_offs = 0; fstReaderFseeko(xc, xc->f, blkpos, SEEK_SET); @@ -5103,12 +5112,12 @@ for(;;) } - mem_required_for_traversal = fstReaderUint64(xc->f); - mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal + 66); /* add in potential fastlz overhead */ + mem_required_for_traversal = fstReaderUint64(xc->f) + 66; /* add in potential fastlz overhead */ + mem_for_traversal = (unsigned char *)malloc(mem_required_for_traversal); #ifdef FST_DEBUG fprintf(stderr, FST_APIMESS "sec: %u seclen: %d begtim: %d endtim: %d\n", secnum, (int)seclen, (int)beg_tim, (int)end_tim); - fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal); + fprintf(stderr, FST_APIMESS "mem_required_for_traversal: %d\n", (int)mem_required_for_traversal-66); #endif /* process time block */ { @@ -5158,6 +5167,22 @@ for(;;) } free(time_table); + + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1792 for 32b overflow */ + uint64_t chk_64 = tsec_nitems * sizeof(uint64_t); + size_t chk_32 = ((size_t)tsec_nitems) * sizeof(uint64_t); + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792"); + } + else + { + uint64_t chk_64 = tsec_nitems * sizeof(uint64_t); + if((chk_64/sizeof(uint64_t)) != tsec_nitems) + { + chk_report_abort("TALOS-2023-1792"); + } + } time_table = (uint64_t *)calloc(tsec_nitems, sizeof(uint64_t)); tpnt = ucdata; tpval = 0; @@ -5169,7 +5194,23 @@ for(;;) tpnt += skiplen; } - tc_head = (uint32_t *)calloc(tsec_nitems /* scan-build */ ? tsec_nitems : 1, sizeof(uint32_t)); + tc_head_items = tsec_nitems /* scan-build */ ? tsec_nitems : 1; + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1792 for 32b overflow */ + uint64_t chk_64 = tc_head_items * sizeof(uint32_t); + size_t chk_32 = ((size_t)tc_head_items) * sizeof(uint32_t); + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1792"); + } + else + { + uint64_t chk_64 = tc_head_items * sizeof(uint32_t); + if((chk_64/sizeof(uint32_t)) != tc_head_items) + { + chk_report_abort("TALOS-2023-1792"); + } + } + tc_head = (uint32_t *)calloc(tc_head_items, sizeof(uint32_t)); free(ucdata); } @@ -5273,6 +5314,10 @@ for(;;) { if(value_change_callback) { + if(xc->signal_lens[idx] > xc->longest_signal_value_len) + { + chk_report_abort("TALOS-2023-1797"); + } memcpy(xc->temp_signal_value_buf, mu+sig_offs, xc->signal_lens[idx]); xc->temp_signal_value_buf[xc->signal_lens[idx]] = 0; value_change_callback(user_callback_data_pointer, beg_tim, idx+1, xc->temp_signal_value_buf); @@ -5286,6 +5331,10 @@ for(;;) vcd_id[0] = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; fstWritex(xc, vcd_id, 1); + if((sig_offs + xc->signal_lens[idx]) > frame_uclen) + { + chk_report_abort("TALOS-2023-1793"); + } fstWritex(xc,mu+sig_offs, xc->signal_lens[idx]); vcd_id[0] = ' '; /* collapse 3 writes into one I/O call */ @@ -5410,7 +5459,44 @@ for(;;) free(chain_table_lengths); vc_maxhandle_largest = vc_maxhandle; + + if(!(vc_maxhandle+1)) + { + chk_report_abort("TALOS-2023-1798"); + } + + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1798 for 32b overflow */ + uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t); + size_t chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(fst_off_t); + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798"); + } + else + { + uint64_t chk_64 = (vc_maxhandle+1) * sizeof(fst_off_t); + if((chk_64/sizeof(fst_off_t)) != (vc_maxhandle+1)) + { + chk_report_abort("TALOS-2023-1798"); + } + } chain_table = (fst_off_t *)calloc((vc_maxhandle+1), sizeof(fst_off_t)); + + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1798 for 32b overflow */ + uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t); + size_t chk_32 = ((size_t)(vc_maxhandle+1)) * sizeof(uint32_t); + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1798"); + } + else + { + uint64_t chk_64 = (vc_maxhandle+1) * sizeof(uint32_t); + if((chk_64/sizeof(uint32_t)) != (vc_maxhandle+1)) + { + chk_report_abort("TALOS-2023-1798"); + } + } chain_table_lengths = (uint32_t *)calloc((vc_maxhandle+1), sizeof(uint32_t)); } @@ -5454,6 +5540,11 @@ for(;;) uint64_t val = fstGetVarint32(pnt, &skiplen); fstHandle loopcnt = val >> 1; + if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */ + { + chk_report_abort("TALOS-2023-1789"); + } + for(i=0;i> 1; + + if((idx+loopcnt-1) > vc_maxhandle) /* TALOS-2023-1789 */ + { + chk_report_abort("TALOS-2023-1789"); + } + for(i=0;i= mem_required_for_traversal) + { + chk_report_abort("TALOS-2023-1785"); + } + if(mc_mem_len < chain_table_lengths[i]) { free(mc_mem); @@ -5575,6 +5677,12 @@ for(;;) { int destlen = chain_table_lengths[i] - skiplen; unsigned char *mu = mem_for_traversal + traversal_mem_offs; + + if(traversal_mem_offs >= mem_required_for_traversal) + { + chk_report_abort("TALOS-2023-1785"); + } + fstFread(mu, destlen, 1, xc->f); /* data to process is for(j=0;j> 1; } + if(tdelta >= tc_head_items) + { + chk_report_abort("TALOS-2023-1791"); + } + scatterptr[i] = tc_head[tdelta]; tc_head[tdelta] = i+1; } @@ -5698,6 +5811,11 @@ for(;;) shamt = 2 << (vli & 1); tdelta = vli >> shamt; + if((tdelta+i) >= tc_head_items) + { + chk_report_abort("TALOS-2023-1791"); + } + scatterptr[idx] = tc_head[i+tdelta]; tc_head[i+tdelta] = idx+1; } @@ -5731,6 +5849,14 @@ for(;;) vcdid_len = fstVcdIDForFwrite(vcd_id+1, idx+1); { + if(sizeof(size_t) < sizeof(uint64_t)) + { + /* TALOS-2023-1790 for 32b overflow */ + uint64_t chk_64 = len*4 + 1; + size_t chk_32 = len*4 + 1; + if(chk_64 != chk_32) chk_report_abort("TALOS-2023-1790"); + } + unsigned char *vesc = (unsigned char *)malloc(len*4 + 1); int vlen = fstUtilityBinToEsc(vesc, vdata, len); fstWritex(xc, vesc, vlen); @@ -5756,6 +5882,11 @@ for(;;) vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); tdelta = vli >> 1; + if((tdelta+i) >= tc_head_items) + { + chk_report_abort("TALOS-2023-1791"); + } + scatterptr[idx] = tc_head[i+tdelta]; tc_head[i+tdelta] = idx+1; } @@ -5772,6 +5903,11 @@ for(;;) if(xc->signal_typs[idx] != FST_VT_VCD_REAL) { + if(len > xc->longest_signal_value_len) + { + chk_report_abort("TALOS-2023-1797"); + } + if(!(vli & 1)) { int byte = 0; @@ -5817,8 +5953,13 @@ for(;;) if(fv) { unsigned char ch_bp = (xc->signal_typs[idx] != FST_VT_VCD_PORT) ? 'b' : 'p'; + uint64_t mem_required_for_traversal_chk = vdata - mem_for_traversal + len; fstWritex(xc, &ch_bp, 1); + if(mem_required_for_traversal_chk > mem_required_for_traversal) + { + chk_report_abort("TALOS-2023-1793"); + } fstWritex(xc, vdata, len); } } @@ -5941,6 +6082,11 @@ for(;;) vli = fstGetVarint32NoSkip(mem_for_traversal + headptr[idx]); tdelta = vli >> 1; + if((tdelta+i) >= tc_head_items) + { + chk_report_abort("TALOS-2023-1791"); + } + scatterptr[idx] = tc_head[i+tdelta]; tc_head[i+tdelta] = idx+1; } diff --git a/include/gtkwave/lz4.c b/include/gtkwave/lz4.c index 55dc1a835..0a727596b 100644 --- a/include/gtkwave/lz4.c +++ b/include/gtkwave/lz4.c @@ -1,6 +1,6 @@ /* LZ4 - Fast LZ compression algorithm - Copyright (C) 2011-2015, Yann Collet. + Copyright (C) 2011-2023, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -27,213 +27,232 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - SPDX-License-Identifier: BSD-2-Clause - You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ - -/************************************** +/*-************************************ * Tuning parameters **************************************/ /* - * HEAPMODE : - * Select how default compression functions will allocate memory for their hash table, + * LZ4_HEAPMODE : + * Select how stateless compression functions like `LZ4_compress_default()` + * allocate memory for their hash table, * in memory stack (0:default, fastest), or in memory heap (1:requires malloc()). */ -#define HEAPMODE 0 +#ifndef LZ4_HEAPMODE +# define LZ4_HEAPMODE 0 +#endif /* - * ACCELERATION_DEFAULT : + * LZ4_ACCELERATION_DEFAULT : * Select "acceleration" for LZ4_compress_fast() when parameter value <= 0 */ -#define ACCELERATION_DEFAULT 1 +#define LZ4_ACCELERATION_DEFAULT 1 +/* + * LZ4_ACCELERATION_MAX : + * Any "acceleration" value higher than this threshold + * get treated as LZ4_ACCELERATION_MAX instead (fix #876) + */ +#define LZ4_ACCELERATION_MAX 65537 -/************************************** +/*-************************************ * CPU Feature Detection **************************************/ +/* LZ4_FORCE_MEMORY_ACCESS + * By default, access to unaligned memory is controlled by `memcpy()`, which is safe and portable. + * Unfortunately, on some target/compiler combinations, the generated assembly is sub-optimal. + * The below switch allow to select different access method for improved performance. + * Method 0 (default) : use `memcpy()`. Safe and portable. + * Method 1 : `__packed` statement. It depends on compiler extension (ie, not portable). + * This method is safe if your compiler supports it, and *generally* as fast or faster than `memcpy`. + * Method 2 : direct access. This method is portable but violate C standard. + * It can generate buggy code on targets which assembly generation depends on alignment. + * But in some circumstances, it's the only known way to get the most performance (ie GCC + ARMv6) + * See https://fastcompression.blogspot.fr/2015/08/accessing-unaligned-memory.html for details. + * Prefer these methods in priority order (0 > 1 > 2) + */ +#ifndef LZ4_FORCE_MEMORY_ACCESS /* can be defined externally */ +# if defined(__GNUC__) && \ + ( defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) ) +# define LZ4_FORCE_MEMORY_ACCESS 2 +# elif (defined(__INTEL_COMPILER) && !defined(_WIN32)) || defined(__GNUC__) || defined(_MSC_VER) +# define LZ4_FORCE_MEMORY_ACCESS 1 +# endif +#endif + /* * LZ4_FORCE_SW_BITCOUNT * Define this parameter if your target system or compiler does not support hardware bit count */ -#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for Windows CE does not support Hardware bit count */ +#if defined(_MSC_VER) && defined(_WIN32_WCE) /* Visual Studio for WinCE doesn't support Hardware bit count */ +# undef LZ4_FORCE_SW_BITCOUNT /* avoid double def */ # define LZ4_FORCE_SW_BITCOUNT #endif -/************************************** -* Includes + +/*-************************************ +* Dependency **************************************/ +/* + * LZ4_SRC_INCLUDED: + * Amalgamation flag, whether lz4.c is included + */ +#ifndef LZ4_SRC_INCLUDED +# define LZ4_SRC_INCLUDED 1 +#endif + +#ifndef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DISABLE_DEPRECATE_WARNINGS /* due to LZ4_decompress_safe_withPrefix64k */ +#endif + +#ifndef LZ4_STATIC_LINKING_ONLY +# define LZ4_STATIC_LINKING_ONLY +#endif #include "lz4.h" +/* see also "memory routines" below */ -/************************************** +/*-************************************ * Compiler Options **************************************/ -#ifdef _MSC_VER /* Visual Studio */ -# define FORCE_INLINE static __forceinline -# include -# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ -# pragma warning(disable : 4293) /* disable: C4293: too large shift (32-bits) */ -#else -# if defined(__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -# if defined(__GNUC__) || defined(__clang__) -# define FORCE_INLINE static inline __attribute__((always_inline)) -# else -# define FORCE_INLINE static inline -# endif -# else -# define FORCE_INLINE static -# endif /* __STDC_VERSION__ */ +#if defined(_MSC_VER) && (_MSC_VER >= 1400) /* Visual Studio 2005+ */ +# include /* only present in VS2005+ */ +# pragma warning(disable : 4127) /* disable: C4127: conditional expression is constant */ +# pragma warning(disable : 6237) /* disable: C6237: conditional expression is always 0 */ #endif /* _MSC_VER */ -/* LZ4_GCC_VERSION is defined into lz4.h */ -#if (LZ4_GCC_VERSION >= 302) || (__INTEL_COMPILER >= 800) || defined(__clang__) +#ifndef LZ4_FORCE_INLINE +# ifdef _MSC_VER /* Visual Studio */ +# define LZ4_FORCE_INLINE static __forceinline +# else +# if defined (__cplusplus) || defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L /* C99 */ +# ifdef __GNUC__ +# define LZ4_FORCE_INLINE static inline __attribute__((always_inline)) +# else +# define LZ4_FORCE_INLINE static inline +# endif +# else +# define LZ4_FORCE_INLINE static +# endif /* __STDC_VERSION__ */ +# endif /* _MSC_VER */ +#endif /* LZ4_FORCE_INLINE */ + +/* LZ4_FORCE_O2 and LZ4_FORCE_INLINE + * gcc on ppc64le generates an unrolled SIMDized loop for LZ4_wildCopy8, + * together with a simple 8-byte copy loop as a fall-back path. + * However, this optimization hurts the decompression speed by >30%, + * because the execution does not go to the optimized loop + * for typical compressible data, and all of the preamble checks + * before going to the fall-back path become useless overhead. + * This optimization happens only with the -O3 flag, and -O2 generates + * a simple 8-byte copy loop. + * With gcc on ppc64le, all of the LZ4_decompress_* and LZ4_wildCopy8 + * functions are annotated with __attribute__((optimize("O2"))), + * and also LZ4_wildCopy8 is forcibly inlined, so that the O2 attribute + * of LZ4_wildCopy8 does not affect the compression speed. + */ +#if defined(__PPC64__) && defined(__LITTLE_ENDIAN__) && defined(__GNUC__) && !defined(__clang__) +# define LZ4_FORCE_O2 __attribute__((optimize("O2"))) +# undef LZ4_FORCE_INLINE +# define LZ4_FORCE_INLINE static __inline __attribute__((optimize("O2"),always_inline)) +#else +# define LZ4_FORCE_O2 +#endif + +#if (defined(__GNUC__) && (__GNUC__ >= 3)) || (defined(__INTEL_COMPILER) && (__INTEL_COMPILER >= 800)) || defined(__clang__) # define expect(expr,value) (__builtin_expect ((expr),(value)) ) #else # define expect(expr,value) (expr) #endif +#ifndef likely #define likely(expr) expect((expr) != 0, 1) +#endif +#ifndef unlikely #define unlikely(expr) expect((expr) != 0, 0) +#endif - -/************************************** -* Memory routines -**************************************/ -#include /* malloc, calloc, free */ -#define ALLOCATOR(n,s) calloc(n,s) -#define FREEMEM free -#include /* memset, memcpy */ -#define MEM_INIT memset - - -/************************************** -* Basic Types -**************************************/ -#if defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */ -# include - typedef uint8_t BYTE; - typedef uint16_t U16; - typedef uint32_t U32; - typedef int32_t S32; - typedef uint64_t U64; -#else - typedef unsigned char BYTE; - typedef unsigned short U16; - typedef unsigned int U32; - typedef signed int S32; - typedef unsigned long long U64; +/* Should the alignment test prove unreliable, for some reason, + * it can be disabled by setting LZ4_ALIGN_TEST to 0 */ +#ifndef LZ4_ALIGN_TEST /* can be externally provided */ +# define LZ4_ALIGN_TEST 1 #endif -/************************************** -* Reading and writing into memory +/*-************************************ +* Memory routines **************************************/ -#define STEPSIZE sizeof(size_t) -static unsigned LZ4_64bits(void) { return sizeof(void*)==8; } +/*! LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION : + * Disable relatively high-level LZ4/HC functions that use dynamic memory + * allocation functions (malloc(), calloc(), free()). + * + * Note that this is a compile-time switch. And since it disables + * public/stable LZ4 v1 API functions, we don't recommend using this + * symbol to generate a library for distribution. + * + * The following public functions are removed when this symbol is defined. + * - lz4 : LZ4_createStream, LZ4_freeStream, + * LZ4_createStreamDecode, LZ4_freeStreamDecode, LZ4_create (deprecated) + * - lz4hc : LZ4_createStreamHC, LZ4_freeStreamHC, + * LZ4_createHC (deprecated), LZ4_freeHC (deprecated) + * - lz4frame, lz4file : All LZ4F_* functions + */ +#if defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) +# define ALLOC(s) lz4_error_memory_allocation_is_disabled +# define ALLOC_AND_ZERO(s) lz4_error_memory_allocation_is_disabled +# define FREEMEM(p) lz4_error_memory_allocation_is_disabled +#elif defined(LZ4_USER_MEMORY_FUNCTIONS) +/* memory management functions can be customized by user project. + * Below functions must exist somewhere in the Project + * and be available at link time */ +void* LZ4_malloc(size_t s); +void* LZ4_calloc(size_t n, size_t s); +void LZ4_free(void* p); +# define ALLOC(s) LZ4_malloc(s) +# define ALLOC_AND_ZERO(s) LZ4_calloc(1,s) +# define FREEMEM(p) LZ4_free(p) +#else +# include /* malloc, calloc, free */ +# define ALLOC(s) malloc(s) +# define ALLOC_AND_ZERO(s) calloc(1,s) +# define FREEMEM(p) free(p) +#endif -static unsigned LZ4_isLittleEndian(void) -{ - const union { U32 i; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ - return one.c[0]; -} +#if ! LZ4_FREESTANDING +# include /* memset, memcpy */ +#endif +#if !defined(LZ4_memset) +# define LZ4_memset(p,v,s) memset((p),(v),(s)) +#endif +#define MEM_INIT(p,v,s) LZ4_memset((p),(v),(s)) -static U16 LZ4_read16(const void* memPtr) -{ - U16 val16; - memcpy(&val16, memPtr, 2); - return val16; -} - -static U16 LZ4_readLE16(const void* memPtr) -{ - if (LZ4_isLittleEndian()) - { - return LZ4_read16(memPtr); - } - else - { - const BYTE* p = (const BYTE*)memPtr; - return (U16)((U16)p[0] + (p[1]<<8)); - } -} - -static void LZ4_writeLE16(void* memPtr, U16 value) -{ - if (LZ4_isLittleEndian()) - { - memcpy(memPtr, &value, 2); - } - else - { - BYTE* p = (BYTE*)memPtr; - p[0] = (BYTE) value; - p[1] = (BYTE)(value>>8); - } -} - -static U32 LZ4_read32(const void* memPtr) -{ - U32 val32; - memcpy(&val32, memPtr, 4); - return val32; -} - -static U64 LZ4_read64(const void* memPtr) -{ - U64 val64; - memcpy(&val64, memPtr, 8); - return val64; -} - -static size_t LZ4_read_ARCH(const void* p) -{ - if (LZ4_64bits()) - return (size_t)LZ4_read64(p); - else - return (size_t)LZ4_read32(p); -} - - -static void LZ4_copy4(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 4); } - -static void LZ4_copy8(void* dstPtr, const void* srcPtr) { memcpy(dstPtr, srcPtr, 8); } - -/* customized version of memcpy, which may overwrite up to 7 bytes beyond dstEnd */ -static void LZ4_wildCopy(void* dstPtr, const void* srcPtr, void* dstEnd) -{ - BYTE* d = (BYTE*)dstPtr; - const BYTE* s = (const BYTE*)srcPtr; - BYTE* e = (BYTE*)dstEnd; - do { LZ4_copy8(d,s); d+=8; s+=8; } while (d LZ4_DISTANCE_ABSOLUTE_MAX) /* max supported by LZ4 format */ +# error "LZ4_DISTANCE_MAX is too big : must be <= 65535" #endif -#define MAX_DISTANCE ((1 << MAXD_LOG) - 1) #define ML_BITS 4 #define ML_MASK ((1U<=1) +# include +#else +# ifndef assert +# define assert(condition) ((void)0) +# endif +#endif + +#define LZ4_STATIC_ASSERT(c) { enum { LZ4_static_assert = 1/(int)(!!(c)) }; } /* use after variable declarations */ + +#if defined(LZ4_DEBUG) && (LZ4_DEBUG>=2) +# include + static int g_debuglog_enable = 1; +# define DEBUGLOG(l, ...) { \ + if ((g_debuglog_enable) && (l<=LZ4_DEBUG)) { \ + fprintf(stderr, __FILE__ " %i: ", __LINE__); \ + fprintf(stderr, __VA_ARGS__); \ + fprintf(stderr, " \n"); \ + } } +#else +# define DEBUGLOG(l, ...) {} /* disabled */ +#endif + +static int LZ4_isAligned(const void* ptr, size_t alignment) +{ + return ((size_t)ptr & (alignment -1)) == 0; +} -/************************************** +/*-************************************ +* Types +**************************************/ +#include +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# include + typedef uint8_t BYTE; + typedef uint16_t U16; + typedef uint32_t U32; + typedef int32_t S32; + typedef uint64_t U64; + typedef uintptr_t uptrval; +#else +# if UINT_MAX != 4294967295UL +# error "LZ4 code (when not C++ or C99) assumes that sizeof(int) == 4" +# endif + typedef unsigned char BYTE; + typedef unsigned short U16; + typedef unsigned int U32; + typedef signed int S32; + typedef unsigned long long U64; + typedef size_t uptrval; /* generally true, except OpenVMS-64 */ +#endif + +#if defined(__x86_64__) + typedef U64 reg_t; /* 64-bits in x32 mode */ +#else + typedef size_t reg_t; /* 32-bits in x32 mode */ +#endif + +typedef enum { + notLimited = 0, + limitedOutput = 1, + fillOutput = 2 +} limitedOutput_directive; + + +/*-************************************ +* Reading and writing into memory +**************************************/ + +/** + * LZ4 relies on memcpy with a constant size being inlined. In freestanding + * environments, the compiler can't assume the implementation of memcpy() is + * standard compliant, so it can't apply its specialized memcpy() inlining + * logic. When possible, use __builtin_memcpy() to tell the compiler to analyze + * memcpy() as if it were standard compliant, so it can inline it in freestanding + * environments. This is needed when decompressing the Linux Kernel, for example. + */ +#if !defined(LZ4_memcpy) +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4_memcpy(dst, src, size) __builtin_memcpy(dst, src, size) +# else +# define LZ4_memcpy(dst, src, size) memcpy(dst, src, size) +# endif +#endif + +#if !defined(LZ4_memmove) +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4_memmove __builtin_memmove +# else +# define LZ4_memmove memmove +# endif +#endif + +static unsigned LZ4_isLittleEndian(void) +{ + const union { U32 u; BYTE c[4]; } one = { 1 }; /* don't use static : performance detrimental */ + return one.c[0]; +} + +#if defined(__GNUC__) || defined(__INTEL_COMPILER) +#define LZ4_PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#elif defined(_MSC_VER) +#define LZ4_PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) +#endif + +#if defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==2) +/* lie to the compiler about data alignment; use with caution */ + +static U16 LZ4_read16(const void* memPtr) { return *(const U16*) memPtr; } +static U32 LZ4_read32(const void* memPtr) { return *(const U32*) memPtr; } +static reg_t LZ4_read_ARCH(const void* memPtr) { return *(const reg_t*) memPtr; } + +static void LZ4_write16(void* memPtr, U16 value) { *(U16*)memPtr = value; } +static void LZ4_write32(void* memPtr, U32 value) { *(U32*)memPtr = value; } + +#elif defined(LZ4_FORCE_MEMORY_ACCESS) && (LZ4_FORCE_MEMORY_ACCESS==1) + +/* __pack instructions are safer, but compiler specific, hence potentially problematic for some compilers */ +/* currently only defined for gcc and icc */ +LZ4_PACK(typedef struct { U16 u16; }) LZ4_unalign16; +LZ4_PACK(typedef struct { U32 u32; }) LZ4_unalign32; +LZ4_PACK(typedef struct { reg_t uArch; }) LZ4_unalignST; + +static U16 LZ4_read16(const void* ptr) { return ((const LZ4_unalign16*)ptr)->u16; } +static U32 LZ4_read32(const void* ptr) { return ((const LZ4_unalign32*)ptr)->u32; } +static reg_t LZ4_read_ARCH(const void* ptr) { return ((const LZ4_unalignST*)ptr)->uArch; } + +static void LZ4_write16(void* memPtr, U16 value) { ((LZ4_unalign16*)memPtr)->u16 = value; } +static void LZ4_write32(void* memPtr, U32 value) { ((LZ4_unalign32*)memPtr)->u32 = value; } + +#else /* safe and portable access using memcpy() */ + +static U16 LZ4_read16(const void* memPtr) +{ + U16 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; +} + +static U32 LZ4_read32(const void* memPtr) +{ + U32 val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; +} + +static reg_t LZ4_read_ARCH(const void* memPtr) +{ + reg_t val; LZ4_memcpy(&val, memPtr, sizeof(val)); return val; +} + +static void LZ4_write16(void* memPtr, U16 value) +{ + LZ4_memcpy(memPtr, &value, sizeof(value)); +} + +static void LZ4_write32(void* memPtr, U32 value) +{ + LZ4_memcpy(memPtr, &value, sizeof(value)); +} + +#endif /* LZ4_FORCE_MEMORY_ACCESS */ + + +static U16 LZ4_readLE16(const void* memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read16(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U16)((U16)p[0] + (p[1]<<8)); + } +} + +#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT +static U32 LZ4_readLE32(const void* memPtr) +{ + if (LZ4_isLittleEndian()) { + return LZ4_read32(memPtr); + } else { + const BYTE* p = (const BYTE*)memPtr; + return (U32)p[0] + (p[1]<<8) + (p[2]<<16) + (p[3]<<24); + } +} +#endif + +static void LZ4_writeLE16(void* memPtr, U16 value) +{ + if (LZ4_isLittleEndian()) { + LZ4_write16(memPtr, value); + } else { + BYTE* p = (BYTE*)memPtr; + p[0] = (BYTE) value; + p[1] = (BYTE)(value>>8); + } +} + +/* customized variant of memcpy, which can overwrite up to 8 bytes beyond dstEnd */ +LZ4_FORCE_INLINE +void LZ4_wildCopy8(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + + do { LZ4_memcpy(d,s,8); d+=8; s+=8; } while (d= 16. */ +LZ4_FORCE_INLINE void +LZ4_wildCopy32(void* dstPtr, const void* srcPtr, void* dstEnd) +{ + BYTE* d = (BYTE*)dstPtr; + const BYTE* s = (const BYTE*)srcPtr; + BYTE* const e = (BYTE*)dstEnd; + + do { LZ4_memcpy(d,s,16); LZ4_memcpy(d+16,s+16,16); d+=32; s+=32; } while (d= dstPtr + MINMATCH + * - there is at least 8 bytes available to write after dstEnd */ +LZ4_FORCE_INLINE void +LZ4_memcpy_using_offset(BYTE* dstPtr, const BYTE* srcPtr, BYTE* dstEnd, const size_t offset) +{ + BYTE v[8]; + + assert(dstEnd >= dstPtr + MINMATCH); + + switch(offset) { + case 1: + MEM_INIT(v, *srcPtr, 8); + break; + case 2: + LZ4_memcpy(v, srcPtr, 2); + LZ4_memcpy(&v[2], srcPtr, 2); +#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ +# pragma warning(push) +# pragma warning(disable : 6385) /* warning C6385: Reading invalid data from 'v'. */ +#endif + LZ4_memcpy(&v[4], v, 4); +#if defined(_MSC_VER) && (_MSC_VER <= 1937) /* MSVC 2022 ver 17.7 or earlier */ +# pragma warning(pop) +#endif + break; + case 4: + LZ4_memcpy(v, srcPtr, 4); + LZ4_memcpy(&v[4], srcPtr, 4); + break; + default: + LZ4_memcpy_using_offset_base(dstPtr, srcPtr, dstEnd, offset); + return; + } + + LZ4_memcpy(dstPtr, v, 8); + dstPtr += 8; + while (dstPtr < dstEnd) { + LZ4_memcpy(dstPtr, v, 8); + dstPtr += 8; + } +} +#endif + + +/*-************************************ * Common functions **************************************/ -static unsigned LZ4_NbCommonBytes (size_t val) +static unsigned LZ4_NbCommonBytes (reg_t val) { - if (LZ4_isLittleEndian()) - { - if (LZ4_64bits()) - { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) + assert(val != 0); + if (LZ4_isLittleEndian()) { + if (sizeof(val) == 8) { +# if defined(_MSC_VER) && (_MSC_VER >= 1800) && (defined(_M_AMD64) && !defined(_M_ARM64EC)) && !defined(LZ4_FORCE_SW_BITCOUNT) +/*-************************************************************************************************* +* ARM64EC is a Microsoft-designed ARM64 ABI compatible with AMD64 applications on ARM64 Windows 11. +* The ARM64EC ABI does not support AVX/AVX2/AVX512 instructions, nor their relevant intrinsics +* including _tzcnt_u64. Therefore, we need to neuter the _tzcnt_u64 code path for ARM64EC. +****************************************************************************************************/ +# if defined(__clang__) && (__clang_major__ < 10) + /* Avoid undefined clang-cl intrinsics issue. + * See https://github.com/lz4/lz4/pull/1017 for details. */ + return (unsigned)__builtin_ia32_tzcnt_u64(val) >> 3; +# else + /* x64 CPUS without BMI support interpret `TZCNT` as `REP BSF` */ + return (unsigned)_tzcnt_u64(val) >> 3; +# endif +# elif defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r = 0; - _BitScanForward64( &r, (U64)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctzll((U64)val) >> 3); + _BitScanForward64(&r, (U64)val); + return (unsigned)r >> 3; +# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_ctzll((U64)val) >> 3; # else - static const int DeBruijnBytePos[64] = { 0, 0, 0, 0, 0, 1, 1, 2, 0, 3, 1, 3, 1, 4, 2, 7, 0, 2, 3, 6, 1, 5, 3, 5, 1, 3, 4, 4, 2, 5, 6, 7, 7, 0, 1, 2, 3, 3, 4, 6, 2, 6, 5, 5, 3, 4, 5, 6, 7, 1, 2, 4, 6, 4, 4, 5, 7, 2, 6, 5, 7, 6, 7, 7 }; - return DeBruijnBytePos[((U64)((val & -(long long)val) * 0x0218A392CDABBD3FULL)) >> 58]; + const U64 m = 0x0101010101010101ULL; + val ^= val - 1; + return (unsigned)(((U64)((val & (m - 1)) * m)) >> 56); # endif - } - else /* 32 bits */ - { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) + } else /* 32 bits */ { +# if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(LZ4_FORCE_SW_BITCOUNT) unsigned long r; - _BitScanForward( &r, (U32)val ); - return (int)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_ctz((U32)val) >> 3); + _BitScanForward(&r, (U32)val); + return (unsigned)r >> 3; +# elif (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_ctz((U32)val) >> 3; # else - static const int DeBruijnBytePos[32] = { 0, 0, 3, 0, 3, 1, 3, 0, 3, 2, 2, 1, 3, 2, 0, 1, 3, 3, 1, 2, 2, 2, 2, 0, 3, 1, 2, 0, 1, 0, 1, 1 }; - return DeBruijnBytePos[((U32)((val & -(S32)val) * 0x077CB531U)) >> 27]; + const U32 m = 0x01010101; + return (unsigned)((((val - 1) ^ val) & (m - 1)) * m) >> 24; # endif } - } - else /* Big Endian CPU */ - { - if (LZ4_64bits()) - { -# if defined(_MSC_VER) && defined(_WIN64) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse64( &r, val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clzll((U64)val) >> 3); + } else /* Big Endian CPU */ { + if (sizeof(val)==8) { +# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(__TINYC__) && !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_clzll((U64)val) >> 3; # else +#if 1 + /* this method is probably faster, + * but adds a 128 bytes lookup table */ + static const unsigned char ctz7_tab[128] = { + 7, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 6, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 5, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + 4, 0, 1, 0, 2, 0, 1, 0, 3, 0, 1, 0, 2, 0, 1, 0, + }; + U64 const mask = 0x0101010101010101ULL; + U64 const t = (((val >> 8) - mask) | val) & mask; + return ctz7_tab[(t * 0x0080402010080402ULL) >> 57]; +#else + /* this method doesn't consume memory space like the previous one, + * but it contains several branches, + * that may end up slowing execution */ + static const U32 by32 = sizeof(val)*4; /* 32 on 64 bits (goal), 16 on 32 bits. + Just to avoid some static analyzer complaining about shift by 32 on 32-bits target. + Note that this code path is never triggered in 32-bits mode. */ unsigned r; - if (!(val>>32)) { r=4; } else { r=0; val>>=32; } + if (!(val>>by32)) { r=4; } else { r=0; val>>=by32; } if (!(val>>16)) { r+=2; val>>=8; } else { val>>=24; } r += (!val); return r; +#endif # endif - } - else /* 32 bits */ - { -# if defined(_MSC_VER) && !defined(LZ4_FORCE_SW_BITCOUNT) - unsigned long r = 0; - _BitScanReverse( &r, (unsigned long)val ); - return (unsigned)(r>>3); -# elif (defined(__clang__) || (LZ4_GCC_VERSION >= 304)) && !defined(LZ4_FORCE_SW_BITCOUNT) - return (__builtin_clz((U32)val) >> 3); + } else /* 32 bits */ { +# if (defined(__clang__) || (defined(__GNUC__) && ((__GNUC__ > 3) || \ + ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 4))))) && \ + !defined(LZ4_FORCE_SW_BITCOUNT) + return (unsigned)__builtin_clz((U32)val) >> 3; # else - unsigned r; - if (!(val>>16)) { r=2; val>>=8; } else { r=0; val>>=24; } - r += (!val); - return r; + val >>= 8; + val = ((((val + 0x00FFFF00) | 0x00FFFFFF) + val) | + (val + 0x00FF0000)) >> 24; + return (unsigned)val ^ 3; # endif } } } -static unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) + +#define STEPSIZE sizeof(reg_t) +LZ4_FORCE_INLINE +unsigned LZ4_count(const BYTE* pIn, const BYTE* pMatch, const BYTE* pInLimit) { const BYTE* const pStart = pIn; - while (likely(pIn compression run slower on incompressible data */ -/************************************** +/*-************************************ * Local Structures and types **************************************/ -typedef struct { - U32 hashTable[HASH_SIZE_U32]; - U32 currentOffset; - U32 initCheck; - const BYTE* dictionary; - BYTE* bufferStart; /* obsolete, used for slideInputBuffer */ - U32 dictSize; -} LZ4_stream_t_internal; +typedef enum { clearedTable = 0, byPtr, byU32, byU16 } tableType_t; -typedef enum { notLimited = 0, limitedOutput = 1 } limitedOutput_directive; -typedef enum { byPtr, byU32, byU16 } tableType_t; - -typedef enum { noDict = 0, withPrefix64k, usingExtDict } dict_directive; +/** + * This enum distinguishes several different modes of accessing previous + * content in the stream. + * + * - noDict : There is no preceding content. + * - withPrefix64k : Table entries up to ctx->dictSize before the current blob + * blob being compressed are valid and refer to the preceding + * content (of length ctx->dictSize), which is available + * contiguously preceding in memory the content currently + * being compressed. + * - usingExtDict : Like withPrefix64k, but the preceding content is somewhere + * else in memory, starting at ctx->dictionary with length + * ctx->dictSize. + * - usingDictCtx : Everything concerning the preceding content is + * in a separate context, pointed to by ctx->dictCtx. + * ctx->dictionary, ctx->dictSize, and table entries + * in the current context that refer to positions + * preceding the beginning of the current compression are + * ignored. Instead, ctx->dictCtx->dictionary and ctx->dictCtx + * ->dictSize describe the location and size of the preceding + * content, and matches are found by looking in the ctx + * ->dictCtx->hashTable. + */ +typedef enum { noDict = 0, withPrefix64k, usingExtDict, usingDictCtx } dict_directive; typedef enum { noDictIssue = 0, dictSmall } dictIssue_directive; -typedef enum { endOnOutputSize = 0, endOnInputSize = 1 } endCondition_directive; -typedef enum { full = 0, partial = 1 } earlyEnd_directive; - -/************************************** +/*-************************************ * Local Utils **************************************/ int LZ4_versionNumber (void) { return LZ4_VERSION_NUMBER; } +const char* LZ4_versionString(void) { return LZ4_VERSION_STRING; } int LZ4_compressBound(int isize) { return LZ4_COMPRESSBOUND(isize); } -int LZ4_sizeofState() { return LZ4_STREAMSIZE; } +int LZ4_sizeofState(void) { return sizeof(LZ4_stream_t); } +/*-**************************************** +* Internal Definitions, used only in Tests +*******************************************/ +#if defined (__cplusplus) +extern "C" { +#endif -/******************************** +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize); + +int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, + int compressedSize, int maxOutputSize, + const void* dictStart, size_t dictSize); +int LZ4_decompress_safe_partial_forceExtDict(const char* source, char* dest, + int compressedSize, int targetOutputSize, int dstCapacity, + const void* dictStart, size_t dictSize); +#if defined (__cplusplus) +} +#endif + +/*-****************************** * Compression functions ********************************/ - -static U32 LZ4_hashSequence(U32 sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash4(U32 sequence, tableType_t const tableType) { if (tableType == byU16) - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-(LZ4_HASHLOG+1))); else - return (((sequence) * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); + return ((sequence * 2654435761U) >> ((MINMATCH*8)-LZ4_HASHLOG)); } -static const U64 prime5bytes = 889523592379ULL; -static U32 LZ4_hashSequence64(size_t sequence, tableType_t const tableType) +LZ4_FORCE_INLINE U32 LZ4_hash5(U64 sequence, tableType_t const tableType) { const U32 hashLog = (tableType == byU16) ? LZ4_HASHLOG+1 : LZ4_HASHLOG; - const U32 hashMask = (1<> (40 - hashLog)) & hashMask; -} - -static U32 LZ4_hashSequenceT(size_t sequence, tableType_t const tableType) -{ - if (LZ4_64bits()) - return LZ4_hashSequence64(sequence, tableType); - return LZ4_hashSequence((U32)sequence, tableType); -} - -static U32 LZ4_hashPosition(const void* p, tableType_t tableType) { return LZ4_hashSequenceT(LZ4_read_ARCH(p), tableType); } - -static void LZ4_putPositionOnHash(const BYTE* p, U32 h, void* tableBase, tableType_t const tableType, const BYTE* srcBase) -{ - switch (tableType) - { - case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = p; return; } - case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = (U32)(p-srcBase); return; } - case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = (U16)(p-srcBase); return; } + if (LZ4_isLittleEndian()) { + const U64 prime5bytes = 889523592379ULL; + return (U32)(((sequence << 24) * prime5bytes) >> (64 - hashLog)); + } else { + const U64 prime8bytes = 11400714785074694791ULL; + return (U32)(((sequence >> 24) * prime8bytes) >> (64 - hashLog)); } } -static void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +LZ4_FORCE_INLINE U32 LZ4_hashPosition(const void* const p, tableType_t const tableType) { - U32 h = LZ4_hashPosition(p, tableType); - LZ4_putPositionOnHash(p, h, tableBase, tableType, srcBase); + if ((sizeof(reg_t)==8) && (tableType != byU16)) return LZ4_hash5(LZ4_read_ARCH(p), tableType); + +#ifdef LZ4_STATIC_LINKING_ONLY_ENDIANNESS_INDEPENDENT_OUTPUT + return LZ4_hash4(LZ4_readLE32(p), tableType); +#else + return LZ4_hash4(LZ4_read32(p), tableType); +#endif } -static const BYTE* LZ4_getPositionOnHash(U32 h, void* tableBase, tableType_t tableType, const BYTE* srcBase) +LZ4_FORCE_INLINE void LZ4_clearHash(U32 h, void* tableBase, tableType_t const tableType) { - if (tableType == byPtr) { const BYTE** hashTable = (const BYTE**) tableBase; return hashTable[h]; } - if (tableType == byU32) { U32* hashTable = (U32*) tableBase; return hashTable[h] + srcBase; } - { U16* hashTable = (U16*) tableBase; return hashTable[h] + srcBase; } /* default, to ensure a return */ + switch (tableType) + { + default: /* fallthrough */ + case clearedTable: { /* illegal! */ assert(0); return; } + case byPtr: { const BYTE** hashTable = (const BYTE**)tableBase; hashTable[h] = NULL; return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = 0; return; } + case byU16: { U16* hashTable = (U16*) tableBase; hashTable[h] = 0; return; } + } } -static const BYTE* LZ4_getPosition(const BYTE* p, void* tableBase, tableType_t tableType, const BYTE* srcBase) +LZ4_FORCE_INLINE void LZ4_putIndexOnHash(U32 idx, U32 h, void* tableBase, tableType_t const tableType) { - U32 h = LZ4_hashPosition(p, tableType); - return LZ4_getPositionOnHash(h, tableBase, tableType, srcBase); + switch (tableType) + { + default: /* fallthrough */ + case clearedTable: /* fallthrough */ + case byPtr: { /* illegal! */ assert(0); return; } + case byU32: { U32* hashTable = (U32*) tableBase; hashTable[h] = idx; return; } + case byU16: { U16* hashTable = (U16*) tableBase; assert(idx < 65536); hashTable[h] = (U16)idx; return; } + } } -FORCE_INLINE int LZ4_compress_generic( - void* const ctx, +/* LZ4_putPosition*() : only used in byPtr mode */ +LZ4_FORCE_INLINE void LZ4_putPositionOnHash(const BYTE* p, U32 h, + void* tableBase, tableType_t const tableType) +{ + const BYTE** const hashTable = (const BYTE**)tableBase; + assert(tableType == byPtr); (void)tableType; + hashTable[h] = p; +} + +LZ4_FORCE_INLINE void LZ4_putPosition(const BYTE* p, void* tableBase, tableType_t tableType) +{ + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putPositionOnHash(p, h, tableBase, tableType); +} + +/* LZ4_getIndexOnHash() : + * Index of match position registered in hash table. + * hash position must be calculated by using base+index, or dictBase+index. + * Assumption 1 : only valid if tableType == byU32 or byU16. + * Assumption 2 : h is presumed valid (within limits of hash table) + */ +LZ4_FORCE_INLINE U32 LZ4_getIndexOnHash(U32 h, const void* tableBase, tableType_t tableType) +{ + LZ4_STATIC_ASSERT(LZ4_MEMORY_USAGE > 2); + if (tableType == byU32) { + const U32* const hashTable = (const U32*) tableBase; + assert(h < (1U << (LZ4_MEMORY_USAGE-2))); + return hashTable[h]; + } + if (tableType == byU16) { + const U16* const hashTable = (const U16*) tableBase; + assert(h < (1U << (LZ4_MEMORY_USAGE-1))); + return hashTable[h]; + } + assert(0); return 0; /* forbidden case */ +} + +static const BYTE* LZ4_getPositionOnHash(U32 h, const void* tableBase, tableType_t tableType) +{ + assert(tableType == byPtr); (void)tableType; + { const BYTE* const* hashTable = (const BYTE* const*) tableBase; return hashTable[h]; } +} + +LZ4_FORCE_INLINE const BYTE* +LZ4_getPosition(const BYTE* p, + const void* tableBase, tableType_t tableType) +{ + U32 const h = LZ4_hashPosition(p, tableType); + return LZ4_getPositionOnHash(h, tableBase, tableType); +} + +LZ4_FORCE_INLINE void +LZ4_prepareTable(LZ4_stream_t_internal* const cctx, + const int inputSize, + const tableType_t tableType) { + /* If the table hasn't been used, it's guaranteed to be zeroed out, and is + * therefore safe to use no matter what mode we're in. Otherwise, we figure + * out if it's safe to leave as is or whether it needs to be reset. + */ + if ((tableType_t)cctx->tableType != clearedTable) { + assert(inputSize >= 0); + if ((tableType_t)cctx->tableType != tableType + || ((tableType == byU16) && cctx->currentOffset + (unsigned)inputSize >= 0xFFFFU) + || ((tableType == byU32) && cctx->currentOffset > 1 GB) + || tableType == byPtr + || inputSize >= 4 KB) + { + DEBUGLOG(4, "LZ4_prepareTable: Resetting table in %p", cctx); + MEM_INIT(cctx->hashTable, 0, LZ4_HASHTABLESIZE); + cctx->currentOffset = 0; + cctx->tableType = (U32)clearedTable; + } else { + DEBUGLOG(4, "LZ4_prepareTable: Re-use hash table (no reset)"); + } + } + + /* Adding a gap, so all previous entries are > LZ4_DISTANCE_MAX back, + * is faster than compressing without a gap. + * However, compressing with currentOffset == 0 is faster still, + * so we preserve that case. + */ + if (cctx->currentOffset != 0 && tableType == byU32) { + DEBUGLOG(5, "LZ4_prepareTable: adding 64KB to currentOffset"); + cctx->currentOffset += 64 KB; + } + + /* Finally, clear history */ + cctx->dictCtx = NULL; + cctx->dictionary = NULL; + cctx->dictSize = 0; +} + +/** LZ4_compress_generic_validated() : + * inlined, to ensure branches are decided at compilation time. + * The following conditions are presumed already validated: + * - source != NULL + * - inputSize > 0 + */ +LZ4_FORCE_INLINE int LZ4_compress_generic_validated( + LZ4_stream_t_internal* const cctx, const char* const source, char* const dest, const int inputSize, + int* inputConsumed, /* only written when outputDirective == fillOutput */ const int maxOutputSize, - const limitedOutput_directive outputLimited, + const limitedOutput_directive outputDirective, const tableType_t tableType, - const dict_directive dict, + const dict_directive dictDirective, const dictIssue_directive dictIssue, - const U32 acceleration) + const int acceleration) { - LZ4_stream_t_internal* const dictPtr = (LZ4_stream_t_internal*)ctx; + int result; + const BYTE* ip = (const BYTE*)source; - const BYTE* ip = (const BYTE*) source; - const BYTE* base; + U32 const startIndex = cctx->currentOffset; + const BYTE* base = (const BYTE*)source - startIndex; const BYTE* lowLimit; - const BYTE* const lowRefLimit = ip - dictPtr->dictSize; - const BYTE* const dictionary = dictPtr->dictionary; - const BYTE* const dictEnd = dictionary + dictPtr->dictSize; - const size_t dictDelta = dictEnd - (const BYTE*)source; + + const LZ4_stream_t_internal* dictCtx = (const LZ4_stream_t_internal*) cctx->dictCtx; + const BYTE* const dictionary = + dictDirective == usingDictCtx ? dictCtx->dictionary : cctx->dictionary; + const U32 dictSize = + dictDirective == usingDictCtx ? dictCtx->dictSize : cctx->dictSize; + const U32 dictDelta = + (dictDirective == usingDictCtx) ? startIndex - dictCtx->currentOffset : 0; /* make indexes in dictCtx comparable with indexes in current context */ + + int const maybe_extMem = (dictDirective == usingExtDict) || (dictDirective == usingDictCtx); + U32 const prefixIdxLimit = startIndex - dictSize; /* used when dictDirective == dictSmall */ + const BYTE* const dictEnd = dictionary ? dictionary + dictSize : dictionary; const BYTE* anchor = (const BYTE*) source; const BYTE* const iend = ip + inputSize; - const BYTE* const mflimit = iend - MFLIMIT; + const BYTE* const mflimitPlusOne = iend - MFLIMIT + 1; const BYTE* const matchlimit = iend - LASTLITERALS; + /* the dictCtx currentOffset is indexed on the start of the dictionary, + * while a dictionary in the current context precedes the currentOffset */ + const BYTE* dictBase = (dictionary == NULL) ? NULL : + (dictDirective == usingDictCtx) ? + dictionary + dictSize - dictCtx->currentOffset : + dictionary + dictSize - startIndex; + BYTE* op = (BYTE*) dest; BYTE* const olimit = op + maxOutputSize; + U32 offset = 0; U32 forwardH; - size_t refDelta=0; - /* Init conditions */ - if ((U32)inputSize > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ - switch(dict) - { - case noDict: - default: - base = (const BYTE*)source; - lowLimit = (const BYTE*)source; - break; - case withPrefix64k: - base = (const BYTE*)source - dictPtr->currentOffset; - lowLimit = (const BYTE*)source - dictPtr->dictSize; - break; - case usingExtDict: - base = (const BYTE*)source - dictPtr->currentOffset; - lowLimit = (const BYTE*)source; - break; + DEBUGLOG(5, "LZ4_compress_generic_validated: srcSize=%i, tableType=%u", inputSize, tableType); + assert(ip != NULL); + if (tableType == byU16) assert(inputSize= 1); + + lowLimit = (const BYTE*)source - (dictDirective == withPrefix64k ? dictSize : 0); + + /* Update context state */ + if (dictDirective == usingDictCtx) { + /* Subsequent linked blocks can't use the dictionary. */ + /* Instead, they use the block we just compressed. */ + cctx->dictCtx = NULL; + cctx->dictSize = (U32)inputSize; + } else { + cctx->dictSize += (U32)inputSize; } - if ((tableType == byU16) && (inputSize>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (inputSizecurrentOffset += (U32)inputSize; + cctx->tableType = (U32)tableType; + + if (inputSizehashTable, byPtr); + } else { + LZ4_putIndexOnHash(startIndex, h, cctx->hashTable, tableType); + } } ip++; forwardH = LZ4_hashPosition(ip, tableType); /* Main Loop */ - for ( ; ; ) - { + for ( ; ; ) { const BYTE* match; BYTE* token; - { - const BYTE* forwardIp = ip; - unsigned step = 1; - unsigned searchMatchNb = acceleration << LZ4_skipTrigger; + const BYTE* filledIp; - /* Find a match */ + /* Find a match */ + if (tableType == byPtr) { + const BYTE* forwardIp = ip; + int step = 1; + int searchMatchNb = acceleration << LZ4_skipTrigger; do { - U32 h = forwardH; + U32 const h = forwardH; ip = forwardIp; forwardIp += step; step = (searchMatchNb++ >> LZ4_skipTrigger); - if (unlikely(forwardIp > mflimit)) goto _last_literals; + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + assert(ip < mflimitPlusOne); - match = LZ4_getPositionOnHash(h, ctx, tableType, base); - if (dict==usingExtDict) - { - if (match<(const BYTE*)source) - { - refDelta = dictDelta; + match = LZ4_getPositionOnHash(h, cctx->hashTable, tableType); + forwardH = LZ4_hashPosition(forwardIp, tableType); + LZ4_putPositionOnHash(ip, h, cctx->hashTable, tableType); + + } while ( (match+LZ4_DISTANCE_MAX < ip) + || (LZ4_read32(match) != LZ4_read32(ip)) ); + + } else { /* byU32, byU16 */ + + const BYTE* forwardIp = ip; + int step = 1; + int searchMatchNb = acceleration << LZ4_skipTrigger; + do { + U32 const h = forwardH; + U32 const current = (U32)(forwardIp - base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + assert(matchIndex <= current); + assert(forwardIp - base < (ptrdiff_t)(2 GB - 1)); + ip = forwardIp; + forwardIp += step; + step = (searchMatchNb++ >> LZ4_skipTrigger); + + if (unlikely(forwardIp > mflimitPlusOne)) goto _last_literals; + assert(ip < mflimitPlusOne); + + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + assert(tableType == byU32); + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + matchIndex += dictDelta; /* make dictCtx index comparable with current context */ lowLimit = dictionary; - } - else - { - refDelta = 0; + } else { + match = base + matchIndex; lowLimit = (const BYTE*)source; } + } else if (dictDirective == usingExtDict) { + if (matchIndex < startIndex) { + DEBUGLOG(7, "extDict candidate: matchIndex=%5u < startIndex=%5u", matchIndex, startIndex); + assert(startIndex - matchIndex >= MINMATCH); + assert(dictBase); + match = dictBase + matchIndex; + lowLimit = dictionary; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; + } + } else { /* single continuous memory segment */ + match = base + matchIndex; } forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); - } while ( ((dictIssue==dictSmall) ? (match < lowRefLimit) : 0) - || ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match+refDelta) != LZ4_read32(ip)) ); + DEBUGLOG(7, "candidate at pos=%u (offset=%u \n", matchIndex, current - matchIndex); + if ((dictIssue == dictSmall) && (matchIndex < prefixIdxLimit)) { continue; } /* match outside of valid area */ + assert(matchIndex < current); + if ( ((tableType != byU16) || (LZ4_DISTANCE_MAX < LZ4_DISTANCE_ABSOLUTE_MAX)) + && (matchIndex+LZ4_DISTANCE_MAX < current)) { + continue; + } /* too far */ + assert((current - matchIndex) <= LZ4_DISTANCE_MAX); /* match now expected within distance */ + + if (LZ4_read32(match) == LZ4_read32(ip)) { + if (maybe_extMem) offset = current - matchIndex; + break; /* match found */ + } + + } while(1); } /* Catch up */ - while ((ip>anchor) && (match+refDelta > lowLimit) && (unlikely(ip[-1]==match[refDelta-1]))) { ip--; match--; } + filledIp = ip; + assert(ip > anchor); /* this is always true as ip has been advanced before entering the main loop */ + if ((match > lowLimit) && unlikely(ip[-1] == match[-1])) { + do { ip--; match--; } while (((ip > anchor) & (match > lowLimit)) && (unlikely(ip[-1] == match[-1]))); + } - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); + /* Encode Literals */ + { unsigned const litLength = (unsigned)(ip - anchor); token = op++; - if ((outputLimited) && (unlikely(op + litLength + (2 + 1 + LASTLITERALS) + (litLength/255) > olimit))) - return 0; /* Check output limit */ - if (litLength>=RUN_MASK) - { - int len = (int)litLength-RUN_MASK; - *token=(RUN_MASK< olimit)) ) { + return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ + } + if ((outputDirective == fillOutput) && + (unlikely(op + (litLength+240)/255 /* litlen */ + litLength /* literals */ + 2 /* offset */ + 1 /* token */ + MFLIMIT - MINMATCH /* min last literals so last match is <= end - MFLIMIT */ > olimit))) { + op--; + goto _last_literals; + } + if (litLength >= RUN_MASK) { + int len = (int)(litLength - RUN_MASK); + *token = (RUN_MASK<= 255 ; len-=255) *op++ = 255; *op++ = (BYTE)len; } else *token = (BYTE)(litLength< olimit)) { + /* the match was too close to the end, rewind and go to last literals */ + op = token; + goto _last_literals; + } + /* Encode Offset */ - LZ4_writeLE16(op, (U16)(ip-match)); op+=2; + if (maybe_extMem) { /* static test */ + DEBUGLOG(6, " with offset=%u (ext if > %i)", offset, (int)(ip - (const BYTE*)source)); + assert(offset <= LZ4_DISTANCE_MAX && offset > 0); + LZ4_writeLE16(op, (U16)offset); op+=2; + } else { + DEBUGLOG(6, " with offset=%u (same segment)", (U32)(ip - match)); + assert(ip-match <= LZ4_DISTANCE_MAX); + LZ4_writeLE16(op, (U16)(ip - match)); op+=2; + } /* Encode MatchLength */ - { - unsigned matchLength; + { unsigned matchCode; - if ((dict==usingExtDict) && (lowLimit==dictionary)) - { - const BYTE* limit; - match += refDelta; - limit = ip + (dictEnd-match); + if ( (dictDirective==usingExtDict || dictDirective==usingDictCtx) + && (lowLimit==dictionary) /* match within extDict */ ) { + const BYTE* limit = ip + (dictEnd-match); + assert(dictEnd > match); if (limit > matchlimit) limit = matchlimit; - matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); - ip += MINMATCH + matchLength; - if (ip==limit) - { - unsigned more = LZ4_count(ip, (const BYTE*)source, matchlimit); - matchLength += more; + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, limit); + ip += (size_t)matchCode + MINMATCH; + if (ip==limit) { + unsigned const more = LZ4_count(limit, (const BYTE*)source, matchlimit); + matchCode += more; ip += more; } - } - else - { - matchLength = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); - ip += MINMATCH + matchLength; + DEBUGLOG(6, " with matchLength=%u starting in extDict", matchCode+MINMATCH); + } else { + matchCode = LZ4_count(ip+MINMATCH, match+MINMATCH, matchlimit); + ip += (size_t)matchCode + MINMATCH; + DEBUGLOG(6, " with matchLength=%u", matchCode+MINMATCH); } - if ((outputLimited) && (unlikely(op + (1 + LASTLITERALS) + (matchLength>>8) > olimit))) - return 0; /* Check output limit */ - if (matchLength>=ML_MASK) - { - *token += ML_MASK; - matchLength -= ML_MASK; - for (; matchLength >= 510 ; matchLength-=510) { *op++ = 255; *op++ = 255; } - if (matchLength >= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; + if ((outputDirective) && /* Check output buffer overflow */ + (unlikely(op + (1 + LASTLITERALS) + (matchCode+240)/255 > olimit)) ) { + if (outputDirective == fillOutput) { + /* Match description too long : reduce it */ + U32 newMatchCode = 15 /* in token */ - 1 /* to avoid needing a zero byte */ + ((U32)(olimit - op) - 1 - LASTLITERALS) * 255; + ip -= matchCode - newMatchCode; + assert(newMatchCode < matchCode); + matchCode = newMatchCode; + if (unlikely(ip <= filledIp)) { + /* We have already filled up to filledIp so if ip ends up less than filledIp + * we have positions in the hash table beyond the current position. This is + * a problem if we reuse the hash table. So we have to remove these positions + * from the hash table. + */ + const BYTE* ptr; + DEBUGLOG(5, "Clearing %u positions", (U32)(filledIp - ip)); + for (ptr = ip; ptr <= filledIp; ++ptr) { + U32 const h = LZ4_hashPosition(ptr, tableType); + LZ4_clearHash(h, cctx->hashTable, tableType); + } + } + } else { + assert(outputDirective == limitedOutput); + return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ + } } - else *token += (BYTE)(matchLength); + if (matchCode >= ML_MASK) { + *token += ML_MASK; + matchCode -= ML_MASK; + LZ4_write32(op, 0xFFFFFFFF); + while (matchCode >= 4*255) { + op+=4; + LZ4_write32(op, 0xFFFFFFFF); + matchCode -= 4*255; + } + op += matchCode / 255; + *op++ = (BYTE)(matchCode % 255); + } else + *token += (BYTE)(matchCode); } + /* Ensure we have enough space for the last literals. */ + assert(!(outputDirective == fillOutput && op + 1 + LASTLITERALS > olimit)); anchor = ip; /* Test end of chunk */ - if (ip > mflimit) break; + if (ip >= mflimitPlusOne) break; /* Fill table */ - LZ4_putPosition(ip-2, ctx, tableType, base); + { U32 const h = LZ4_hashPosition(ip-2, tableType); + if (tableType == byPtr) { + LZ4_putPositionOnHash(ip-2, h, cctx->hashTable, byPtr); + } else { + U32 const idx = (U32)((ip-2) - base); + LZ4_putIndexOnHash(idx, h, cctx->hashTable, tableType); + } } /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - if (dict==usingExtDict) - { - if (match<(const BYTE*)source) - { - refDelta = dictDelta; - lowLimit = dictionary; + if (tableType == byPtr) { + + match = LZ4_getPosition(ip, cctx->hashTable, tableType); + LZ4_putPosition(ip, cctx->hashTable, tableType); + if ( (match+LZ4_DISTANCE_MAX >= ip) + && (LZ4_read32(match) == LZ4_read32(ip)) ) + { token=op++; *token=0; goto _next_match; } + + } else { /* byU32, byU16 */ + + U32 const h = LZ4_hashPosition(ip, tableType); + U32 const current = (U32)(ip-base); + U32 matchIndex = LZ4_getIndexOnHash(h, cctx->hashTable, tableType); + assert(matchIndex < current); + if (dictDirective == usingDictCtx) { + if (matchIndex < startIndex) { + /* there was no match, try the dictionary */ + assert(tableType == byU32); + matchIndex = LZ4_getIndexOnHash(h, dictCtx->hashTable, byU32); + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + matchIndex += dictDelta; + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else if (dictDirective==usingExtDict) { + if (matchIndex < startIndex) { + assert(dictBase); + match = dictBase + matchIndex; + lowLimit = dictionary; /* required for match length counter */ + } else { + match = base + matchIndex; + lowLimit = (const BYTE*)source; /* required for match length counter */ + } + } else { /* single memory segment */ + match = base + matchIndex; } - else - { - refDelta = 0; - lowLimit = (const BYTE*)source; + LZ4_putIndexOnHash(current, h, cctx->hashTable, tableType); + assert(matchIndex < current); + if ( ((dictIssue==dictSmall) ? (matchIndex >= prefixIdxLimit) : 1) + && (((tableType==byU16) && (LZ4_DISTANCE_MAX == LZ4_DISTANCE_ABSOLUTE_MAX)) ? 1 : (matchIndex+LZ4_DISTANCE_MAX >= current)) + && (LZ4_read32(match) == LZ4_read32(ip)) ) { + token=op++; + *token=0; + if (maybe_extMem) offset = current - matchIndex; + DEBUGLOG(6, "seq.start:%i, literals=%u, match.start:%i", + (int)(anchor-(const BYTE*)source), 0, (int)(ip-(const BYTE*)source)); + goto _next_match; } } - LZ4_putPosition(ip, ctx, tableType, base); - if ( ((dictIssue==dictSmall) ? (match>=lowRefLimit) : 1) - && (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match+refDelta)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } /* Prepare next loop */ forwardH = LZ4_hashPosition(++ip, tableType); + } _last_literals: /* Encode Last Literals */ - { - const size_t lastRun = (size_t)(iend - anchor); - if ((outputLimited) && ((op - (BYTE*)dest) + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > (U32)maxOutputSize)) - return 0; /* Check output limit */ - if (lastRun >= RUN_MASK) - { + { size_t lastRun = (size_t)(iend - anchor); + if ( (outputDirective) && /* Check output buffer overflow */ + (op + lastRun + 1 + ((lastRun+255-RUN_MASK)/255) > olimit)) { + if (outputDirective == fillOutput) { + /* adapt lastRun to fill 'dst' */ + assert(olimit >= op); + lastRun = (size_t)(olimit-op) - 1/*token*/; + lastRun -= (lastRun + 256 - RUN_MASK) / 256; /*additional length tokens*/ + } else { + assert(outputDirective == limitedOutput); + return 0; /* cannot compress within `dst` budget. Stored indexes in hash table are nonetheless fine */ + } + } + DEBUGLOG(6, "Final literal run : %i literals", (int)lastRun); + if (lastRun >= RUN_MASK) { size_t accumulator = lastRun - RUN_MASK; *op++ = RUN_MASK << ML_BITS; for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; *op++ = (BYTE) accumulator; - } - else - { + } else { *op++ = (BYTE)(lastRun< 0); + DEBUGLOG(5, "LZ4_compress_generic: compressed %i bytes into %i bytes", inputSize, result); + return result; +} + +/** LZ4_compress_generic() : + * inlined, to ensure branches are decided at compilation time; + * takes care of src == (NULL, 0) + * and forward the rest to LZ4_compress_generic_validated */ +LZ4_FORCE_INLINE int LZ4_compress_generic( + LZ4_stream_t_internal* const cctx, + const char* const src, + char* const dst, + const int srcSize, + int *inputConsumed, /* only written when outputDirective == fillOutput */ + const int dstCapacity, + const limitedOutput_directive outputDirective, + const tableType_t tableType, + const dict_directive dictDirective, + const dictIssue_directive dictIssue, + const int acceleration) +{ + DEBUGLOG(5, "LZ4_compress_generic: srcSize=%i, dstCapacity=%i", + srcSize, dstCapacity); + + if ((U32)srcSize > (U32)LZ4_MAX_INPUT_SIZE) { return 0; } /* Unsupported srcSize, too large (or negative) */ + if (srcSize == 0) { /* src == NULL supported if srcSize == 0 */ + if (outputDirective != notLimited && dstCapacity <= 0) return 0; /* no output, can't write anything */ + DEBUGLOG(5, "Generating an empty block"); + assert(outputDirective == notLimited || dstCapacity >= 1); + assert(dst != NULL); + dst[0] = 0; + if (outputDirective == fillOutput) { + assert (inputConsumed != NULL); + *inputConsumed = 0; + } + return 1; + } + assert(src != NULL); + + return LZ4_compress_generic_validated(cctx, src, dst, srcSize, + inputConsumed, /* only written into if outputDirective == fillOutput */ + dstCapacity, outputDirective, + tableType, dictDirective, dictIssue, acceleration); } int LZ4_compress_fast_extState(void* state, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) { - LZ4_resetStream((LZ4_stream_t*)state); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; - - if (maxOutputSize >= LZ4_compressBound(inputSize)) - { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(state, source, dest, inputSize, 0, notLimited, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + LZ4_stream_t_internal* const ctx = & LZ4_initStream(state, sizeof(LZ4_stream_t)) -> internal_donotuse; + assert(ctx != NULL); + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; + if (maxOutputSize >= LZ4_compressBound(inputSize)) { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (inputSize < LZ4_64Klimit) { + return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)source > LZ4_DISTANCE_MAX)) ? byPtr : byU32; + return LZ4_compress_generic(ctx, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } } - else - { - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(state, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); +} + +/** + * LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. It is only safe + * to call if the state buffer is known to be correctly initialized already + * (see comment in lz4.h on LZ4_resetStream_fast() for a definition of + * "correctly initialized"). + */ +int LZ4_compress_fast_extState_fastReset(void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration) +{ + LZ4_stream_t_internal* const ctx = &((LZ4_stream_t*)state)->internal_donotuse; + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; + assert(ctx != NULL); + + if (dstCapacity >= LZ4_compressBound(srcSize)) { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, 0, notLimited, tableType, noDict, noDictIssue, acceleration); + } + } else { + if (srcSize < LZ4_64Klimit) { + const tableType_t tableType = byU16; + LZ4_prepareTable(ctx, srcSize, tableType); + if (ctx->currentOffset) { + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, dictSmall, acceleration); + } else { + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } + } else { + const tableType_t tableType = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; + LZ4_prepareTable(ctx, srcSize, tableType); + return LZ4_compress_generic(ctx, src, dst, srcSize, NULL, dstCapacity, limitedOutput, tableType, noDict, noDictIssue, acceleration); + } } } -int LZ4_compress_fast(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +int LZ4_compress_fast(const char* src, char* dest, int srcSize, int dstCapacity, int acceleration) { -#if (HEAPMODE) - void* ctxPtr = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + int result; +#if (LZ4_HEAPMODE) + LZ4_stream_t* const ctxPtr = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + if (ctxPtr == NULL) return 0; #else LZ4_stream_t ctx; - void* ctxPtr = &ctx; + LZ4_stream_t* const ctxPtr = &ctx; #endif + result = LZ4_compress_fast_extState(ctxPtr, src, dest, srcSize, dstCapacity, acceleration); - int result = LZ4_compress_fast_extState(ctxPtr, source, dest, inputSize, maxOutputSize, acceleration); - -#if (HEAPMODE) +#if (LZ4_HEAPMODE) FREEMEM(ctxPtr); #endif return result; } -int LZ4_compress_default(const char* source, char* dest, int inputSize, int maxOutputSize) +int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity) { - return LZ4_compress_fast(source, dest, inputSize, maxOutputSize, 1); + return LZ4_compress_fast(src, dst, srcSize, dstCapacity, 1); } -/* hidden debug function */ -/* strangely enough, gcc generates faster code when this function is uncommented, even if unused */ -int LZ4_compress_fast_force(const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +/* Note!: This function leaves the stream in an unclean/broken state! + * It is not safe to subsequently use the same state with a _fastReset() or + * _continue() call without resetting it. */ +static int LZ4_compress_destSize_extState_internal(LZ4_stream_t* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration) { - LZ4_stream_t ctx; + void* const s = LZ4_initStream(state, sizeof (*state)); + assert(s != NULL); (void)s; - LZ4_resetStream(&ctx); - - if (inputSize < LZ4_64Klimit) - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, byU16, noDict, noDictIssue, acceleration); - else - return LZ4_compress_generic(&ctx, source, dest, inputSize, maxOutputSize, limitedOutput, LZ4_64bits() ? byU32 : byPtr, noDict, noDictIssue, acceleration); + if (targetDstSize >= LZ4_compressBound(*srcSizePtr)) { /* compression success is guaranteed */ + return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, acceleration); + } else { + if (*srcSizePtr < LZ4_64Klimit) { + return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, byU16, noDict, noDictIssue, acceleration); + } else { + tableType_t const addrMode = ((sizeof(void*)==4) && ((uptrval)src > LZ4_DISTANCE_MAX)) ? byPtr : byU32; + return LZ4_compress_generic(&state->internal_donotuse, src, dst, *srcSizePtr, srcSizePtr, targetDstSize, fillOutput, addrMode, noDict, noDictIssue, acceleration); + } } } - -/******************************** -* destSize variant -********************************/ - -static int LZ4_compress_destSize_generic( - void* const ctx, - const char* const src, - char* const dst, - int* const srcSizePtr, - const int targetDstSize, - const tableType_t tableType) +int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration) { - const BYTE* ip = (const BYTE*) src; - const BYTE* base = (const BYTE*) src; - const BYTE* lowLimit = (const BYTE*) src; - const BYTE* anchor = ip; - const BYTE* const iend = ip + *srcSizePtr; - const BYTE* const mflimit = iend - MFLIMIT; - const BYTE* const matchlimit = iend - LASTLITERALS; - - BYTE* op = (BYTE*) dst; - BYTE* const oend = op + targetDstSize; - BYTE* const oMaxLit = op + targetDstSize - 2 /* offset */ - 8 /* because 8+MINMATCH==MFLIMIT */ - 1 /* token */; - BYTE* const oMaxMatch = op + targetDstSize - (LASTLITERALS + 1 /* token */); - BYTE* const oMaxSeq = oMaxLit - 1 /* token */; - - U32 forwardH; - - - /* Init conditions */ - if (targetDstSize < 1) return 0; /* Impossible to store anything */ - if ((U32)*srcSizePtr > (U32)LZ4_MAX_INPUT_SIZE) return 0; /* Unsupported input size, too large (or negative) */ - if ((tableType == byU16) && (*srcSizePtr>=LZ4_64Klimit)) return 0; /* Size too large (not within 64K limit) */ - if (*srcSizePtr> LZ4_skipTrigger); - - if (unlikely(forwardIp > mflimit)) - goto _last_literals; - - match = LZ4_getPositionOnHash(h, ctx, tableType, base); - forwardH = LZ4_hashPosition(forwardIp, tableType); - LZ4_putPositionOnHash(ip, h, ctx, tableType, base); - - } while ( ((tableType==byU16) ? 0 : (match + MAX_DISTANCE < ip)) - || (LZ4_read32(match) != LZ4_read32(ip)) ); - } - - /* Catch up */ - while ((ip>anchor) && (match > lowLimit) && (unlikely(ip[-1]==match[-1]))) { ip--; match--; } - - { - /* Encode Literal length */ - unsigned litLength = (unsigned)(ip - anchor); - token = op++; - if (op + ((litLength+240)/255) + litLength > oMaxLit) - { - /* Not enough space for a last match */ - op--; - goto _last_literals; - } - if (litLength>=RUN_MASK) - { - unsigned len = litLength - RUN_MASK; - *token=(RUN_MASK<= 255 ; len-=255) *op++ = 255; - *op++ = (BYTE)len; - } - else *token = (BYTE)(litLength< oMaxMatch) - { - /* Match description too long : reduce it */ - matchLength = (15-1) + (oMaxMatch-op) * 255; - } - /*printf("offset %5i, matchLength%5i \n", (int)(ip-match), matchLength + MINMATCH);*/ - ip += MINMATCH + matchLength; - - if (matchLength>=ML_MASK) - { - *token += ML_MASK; - matchLength -= ML_MASK; - while (matchLength >= 255) { matchLength-=255; *op++ = 255; } - *op++ = (BYTE)matchLength; - } - else *token += (BYTE)(matchLength); - } - - anchor = ip; - - /* Test end of block */ - if (ip > mflimit) break; - if (op > oMaxSeq) break; - - /* Fill table */ - LZ4_putPosition(ip-2, ctx, tableType, base); - - /* Test next position */ - match = LZ4_getPosition(ip, ctx, tableType, base); - LZ4_putPosition(ip, ctx, tableType, base); - if ( (match+MAX_DISTANCE>=ip) - && (LZ4_read32(match)==LZ4_read32(ip)) ) - { token=op++; *token=0; goto _next_match; } - - /* Prepare next loop */ - forwardH = LZ4_hashPosition(++ip, tableType); - } - -_last_literals: - /* Encode Last Literals */ - { - size_t lastRunSize = (size_t)(iend - anchor); - if (op + 1 /* token */ + ((lastRunSize+240)/255) /* litLength */ + lastRunSize /* literals */ > oend) - { - /* adapt lastRunSize to fill 'dst' */ - lastRunSize = (oend-op) - 1; - lastRunSize -= (lastRunSize+240)/255; - } - ip = anchor + lastRunSize; - - if (lastRunSize >= RUN_MASK) - { - size_t accumulator = lastRunSize - RUN_MASK; - *op++ = RUN_MASK << ML_BITS; - for(; accumulator >= 255 ; accumulator-=255) *op++ = 255; - *op++ = (BYTE) accumulator; - } - else - { - *op++ = (BYTE)(lastRunSize<= LZ4_compressBound(*srcSizePtr)) /* compression success is guaranteed */ - { - return LZ4_compress_fast_extState(state, src, dst, *srcSizePtr, targetDstSize, 1); - } - else - { - if (*srcSizePtr < LZ4_64Klimit) - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, byU16); - else - return LZ4_compress_destSize_generic(state, src, dst, srcSizePtr, targetDstSize, LZ4_64bits() ? byU32 : byPtr); - } + int const r = LZ4_compress_destSize_extState_internal((LZ4_stream_t*)state, src, dst, srcSizePtr, targetDstSize, acceleration); + /* clean the state on exit */ + LZ4_initStream(state, sizeof (LZ4_stream_t)); + return r; } int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize) { -#if (HEAPMODE) - void* ctx = ALLOCATOR(1, sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ +#if (LZ4_HEAPMODE) + LZ4_stream_t* const ctx = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); /* malloc-calloc always properly aligned */ + if (ctx == NULL) return 0; #else LZ4_stream_t ctxBody; - void* ctx = &ctxBody; + LZ4_stream_t* const ctx = &ctxBody; #endif - int result = LZ4_compress_destSize_extState(ctx, src, dst, srcSizePtr, targetDstSize); + int result = LZ4_compress_destSize_extState_internal(ctx, src, dst, srcSizePtr, targetDstSize, 1); -#if (HEAPMODE) +#if (LZ4_HEAPMODE) FREEMEM(ctx); #endif return result; @@ -933,76 +1520,148 @@ int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targe -/******************************** +/*-****************************** * Streaming functions ********************************/ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) LZ4_stream_t* LZ4_createStream(void) { - LZ4_stream_t* lz4s = (LZ4_stream_t*)ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_STATIC_ASSERT(LZ4_STREAMSIZE >= sizeof(LZ4_stream_t_internal)); /* A compilation error here means LZ4_STREAMSIZE is not large enough */ - LZ4_resetStream(lz4s); + LZ4_stream_t* const lz4s = (LZ4_stream_t*)ALLOC(sizeof(LZ4_stream_t)); + LZ4_STATIC_ASSERT(sizeof(LZ4_stream_t) >= sizeof(LZ4_stream_t_internal)); + DEBUGLOG(4, "LZ4_createStream %p", lz4s); + if (lz4s == NULL) return NULL; + LZ4_initStream(lz4s, sizeof(*lz4s)); return lz4s; } +#endif -void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +static size_t LZ4_stream_t_alignment(void) { - MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t)); +#if LZ4_ALIGN_TEST + typedef struct { char c; LZ4_stream_t t; } t_a; + return sizeof(t_a) - sizeof(LZ4_stream_t); +#else + return 1; /* effectively disabled */ +#endif } +LZ4_stream_t* LZ4_initStream (void* buffer, size_t size) +{ + DEBUGLOG(5, "LZ4_initStream"); + if (buffer == NULL) { return NULL; } + if (size < sizeof(LZ4_stream_t)) { return NULL; } + if (!LZ4_isAligned(buffer, LZ4_stream_t_alignment())) return NULL; + MEM_INIT(buffer, 0, sizeof(LZ4_stream_t_internal)); + return (LZ4_stream_t*)buffer; +} + +/* resetStream is now deprecated, + * prefer initStream() which is more general */ +void LZ4_resetStream (LZ4_stream_t* LZ4_stream) +{ + DEBUGLOG(5, "LZ4_resetStream (ctx:%p)", LZ4_stream); + MEM_INIT(LZ4_stream, 0, sizeof(LZ4_stream_t_internal)); +} + +void LZ4_resetStream_fast(LZ4_stream_t* ctx) { + LZ4_prepareTable(&(ctx->internal_donotuse), 0, byU32); +} + +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) int LZ4_freeStream (LZ4_stream_t* LZ4_stream) { + if (!LZ4_stream) return 0; /* support free on NULL */ + DEBUGLOG(5, "LZ4_freeStream %p", LZ4_stream); FREEMEM(LZ4_stream); return (0); } +#endif -#define HASH_UNIT sizeof(size_t) +#define HASH_UNIT sizeof(reg_t) int LZ4_loadDict (LZ4_stream_t* LZ4_dict, const char* dictionary, int dictSize) { - LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; + const tableType_t tableType = byU32; const BYTE* p = (const BYTE*)dictionary; const BYTE* const dictEnd = p + dictSize; - const BYTE* base; + U32 idx32; - if ((dict->initCheck) || (dict->currentOffset > 1 GB)) /* Uninitialized structure, or reuse overflow */ - LZ4_resetStream(LZ4_dict); + DEBUGLOG(4, "LZ4_loadDict (%i bytes from %p into %p)", dictSize, dictionary, LZ4_dict); - if (dictSize < (int)HASH_UNIT) - { - dict->dictionary = NULL; - dict->dictSize = 0; + /* It's necessary to reset the context, + * and not just continue it with prepareTable() + * to avoid any risk of generating overflowing matchIndex + * when compressing using this dictionary */ + LZ4_resetStream(LZ4_dict); + + /* We always increment the offset by 64 KB, since, if the dict is longer, + * we truncate it to the last 64k, and if it's shorter, we still want to + * advance by a whole window length so we can provide the guarantee that + * there are only valid offsets in the window, which allows an optimization + * in LZ4_compress_fast_continue() where it uses noDictIssue even when the + * dictionary isn't a full 64k. */ + dict->currentOffset += 64 KB; + + if (dictSize < (int)HASH_UNIT) { return 0; } if ((dictEnd - p) > 64 KB) p = dictEnd - 64 KB; - dict->currentOffset += 64 KB; - base = p - dict->currentOffset; dict->dictionary = p; dict->dictSize = (U32)(dictEnd - p); - dict->currentOffset += dict->dictSize; + dict->tableType = (U32)tableType; + idx32 = dict->currentOffset - dict->dictSize; - while (p <= dictEnd-HASH_UNIT) - { - LZ4_putPosition(p, dict->hashTable, byU32, base); - p+=3; + while (p <= dictEnd-HASH_UNIT) { + U32 const h = LZ4_hashPosition(p, tableType); + LZ4_putIndexOnHash(idx32, h, dict->hashTable, tableType); + p+=3; idx32+=3; } - return dict->dictSize; + return (int)dict->dictSize; +} + +void LZ4_attach_dictionary(LZ4_stream_t* workingStream, const LZ4_stream_t* dictionaryStream) +{ + const LZ4_stream_t_internal* dictCtx = (dictionaryStream == NULL) ? NULL : + &(dictionaryStream->internal_donotuse); + + DEBUGLOG(4, "LZ4_attach_dictionary (%p, %p, size %u)", + workingStream, dictionaryStream, + dictCtx != NULL ? dictCtx->dictSize : 0); + + if (dictCtx != NULL) { + /* If the current offset is zero, we will never look in the + * external dictionary context, since there is no value a table + * entry can take that indicate a miss. In that case, we need + * to bump the offset to something non-zero. + */ + if (workingStream->internal_donotuse.currentOffset == 0) { + workingStream->internal_donotuse.currentOffset = 64 KB; + } + + /* Don't actually attach an empty dictionary. + */ + if (dictCtx->dictSize == 0) { + dictCtx = NULL; + } + } + workingStream->internal_donotuse.dictCtx = dictCtx; } -static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) +static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, int nextSize) { - if ((LZ4_dict->currentOffset > 0x80000000) || - ((size_t)LZ4_dict->currentOffset > (size_t)src)) /* address space overflow */ - { + assert(nextSize >= 0); + if (LZ4_dict->currentOffset + (unsigned)nextSize > 0x80000000) { /* potential ptrdiff_t overflow (32-bits mode) */ /* rescale hash table */ - U32 delta = LZ4_dict->currentOffset - 64 KB; + U32 const delta = LZ4_dict->currentOffset - 64 KB; const BYTE* dictEnd = LZ4_dict->dictionary + LZ4_dict->dictSize; int i; - for (i=0; ihashTable[i] < delta) LZ4_dict->hashTable[i]=0; else LZ4_dict->hashTable[i] -= delta; } @@ -1013,87 +1672,128 @@ static void LZ4_renormDictT(LZ4_stream_t_internal* LZ4_dict, const BYTE* src) } -int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize, int maxOutputSize, int acceleration) +int LZ4_compress_fast_continue (LZ4_stream_t* LZ4_stream, + const char* source, char* dest, + int inputSize, int maxOutputSize, + int acceleration) { - LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_stream; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; + const tableType_t tableType = byU32; + LZ4_stream_t_internal* const streamPtr = &LZ4_stream->internal_donotuse; + const char* dictEnd = streamPtr->dictSize ? (const char*)streamPtr->dictionary + streamPtr->dictSize : NULL; - const BYTE* smallest = (const BYTE*) source; - if (streamPtr->initCheck) return 0; /* Uninitialized structure detected */ - if ((streamPtr->dictSize>0) && (smallest>dictEnd)) smallest = dictEnd; - LZ4_renormDictT(streamPtr, smallest); - if (acceleration < 1) acceleration = ACCELERATION_DEFAULT; + DEBUGLOG(5, "LZ4_compress_fast_continue (inputSize=%i, dictSize=%u)", inputSize, streamPtr->dictSize); + + LZ4_renormDictT(streamPtr, inputSize); /* fix index overflow */ + if (acceleration < 1) acceleration = LZ4_ACCELERATION_DEFAULT; + if (acceleration > LZ4_ACCELERATION_MAX) acceleration = LZ4_ACCELERATION_MAX; + + /* invalidate tiny dictionaries */ + if ( (streamPtr->dictSize < 4) /* tiny dictionary : not enough for a hash */ + && (dictEnd != source) /* prefix mode */ + && (inputSize > 0) /* tolerance : don't lose history, in case next invocation would use prefix mode */ + && (streamPtr->dictCtx == NULL) /* usingDictCtx */ + ) { + DEBUGLOG(5, "LZ4_compress_fast_continue: dictSize(%u) at addr:%p is too small", streamPtr->dictSize, streamPtr->dictionary); + /* remove dictionary existence from history, to employ faster prefix mode */ + streamPtr->dictSize = 0; + streamPtr->dictionary = (const BYTE*)source; + dictEnd = source; + } /* Check overlapping input/dictionary space */ - { - const BYTE* sourceEnd = (const BYTE*) source + inputSize; - if ((sourceEnd > streamPtr->dictionary) && (sourceEnd < dictEnd)) - { + { const char* const sourceEnd = source + inputSize; + if ((sourceEnd > (const char*)streamPtr->dictionary) && (sourceEnd < dictEnd)) { streamPtr->dictSize = (U32)(dictEnd - sourceEnd); if (streamPtr->dictSize > 64 KB) streamPtr->dictSize = 64 KB; if (streamPtr->dictSize < 4) streamPtr->dictSize = 0; - streamPtr->dictionary = dictEnd - streamPtr->dictSize; + streamPtr->dictionary = (const BYTE*)dictEnd - streamPtr->dictSize; } } /* prefix mode : source data follows dictionary */ - if (dictEnd == (const BYTE*)source) - { - int result; + if (dictEnd == source) { if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, dictSmall, acceleration); + return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, dictSmall, acceleration); else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, withPrefix64k, noDictIssue, acceleration); - streamPtr->dictSize += (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; - return result; + return LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, withPrefix64k, noDictIssue, acceleration); } /* external dictionary mode */ - { - int result; - if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, dictSmall, acceleration); - else - result = LZ4_compress_generic(LZ4_stream, source, dest, inputSize, maxOutputSize, limitedOutput, byU32, usingExtDict, noDictIssue, acceleration); + { int result; + if (streamPtr->dictCtx) { + /* We depend here on the fact that dictCtx'es (produced by + * LZ4_loadDict) guarantee that their tables contain no references + * to offsets between dictCtx->currentOffset - 64 KB and + * dictCtx->currentOffset - dictCtx->dictSize. This makes it safe + * to use noDictIssue even when the dict isn't a full 64 KB. + */ + if (inputSize > 4 KB) { + /* For compressing large blobs, it is faster to pay the setup + * cost to copy the dictionary's tables into the active context, + * so that the compression loop is only looking into one table. + */ + LZ4_memcpy(streamPtr, streamPtr->dictCtx, sizeof(*streamPtr)); + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingDictCtx, noDictIssue, acceleration); + } + } else { /* small data <= 4 KB */ + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, dictSmall, acceleration); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, inputSize, NULL, maxOutputSize, limitedOutput, tableType, usingExtDict, noDictIssue, acceleration); + } + } streamPtr->dictionary = (const BYTE*)source; streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; return result; } } -/* Hidden debug function, to force external dictionary mode */ -int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int inputSize) +/* Hidden debug function, to force-test external dictionary mode */ +int LZ4_compress_forceExtDict (LZ4_stream_t* LZ4_dict, const char* source, char* dest, int srcSize) { - LZ4_stream_t_internal* streamPtr = (LZ4_stream_t_internal*)LZ4_dict; + LZ4_stream_t_internal* const streamPtr = &LZ4_dict->internal_donotuse; int result; - const BYTE* const dictEnd = streamPtr->dictionary + streamPtr->dictSize; - const BYTE* smallest = dictEnd; - if (smallest > (const BYTE*) source) smallest = (const BYTE*) source; - LZ4_renormDictT((LZ4_stream_t_internal*)LZ4_dict, smallest); + LZ4_renormDictT(streamPtr, srcSize); - result = LZ4_compress_generic(LZ4_dict, source, dest, inputSize, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + if ((streamPtr->dictSize < 64 KB) && (streamPtr->dictSize < streamPtr->currentOffset)) { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, dictSmall, 1); + } else { + result = LZ4_compress_generic(streamPtr, source, dest, srcSize, NULL, 0, notLimited, byU32, usingExtDict, noDictIssue, 1); + } streamPtr->dictionary = (const BYTE*)source; - streamPtr->dictSize = (U32)inputSize; - streamPtr->currentOffset += (U32)inputSize; + streamPtr->dictSize = (U32)srcSize; return result; } +/*! LZ4_saveDict() : + * If previously compressed data block is not guaranteed to remain available at its memory location, + * save it into a safer place (char* safeBuffer). + * Note : no need to call LZ4_loadDict() afterwards, dictionary is immediately usable, + * one can therefore call LZ4_compress_fast_continue() right after. + * @return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error. + */ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) { - LZ4_stream_t_internal* dict = (LZ4_stream_t_internal*) LZ4_dict; - const BYTE* previousDictEnd = dict->dictionary + dict->dictSize; + LZ4_stream_t_internal* const dict = &LZ4_dict->internal_donotuse; - if ((U32)dictSize > 64 KB) dictSize = 64 KB; /* useless to define a dictionary > 64 KB */ - if ((U32)dictSize > dict->dictSize) dictSize = dict->dictSize; + DEBUGLOG(5, "LZ4_saveDict : dictSize=%i, safeBuffer=%p", dictSize, safeBuffer); - memmove(safeBuffer, previousDictEnd - dictSize, dictSize); + if ((U32)dictSize > 64 KB) { dictSize = 64 KB; } /* useless to define a dictionary > 64 KB */ + if ((U32)dictSize > dict->dictSize) { dictSize = (int)dict->dictSize; } + + if (safeBuffer == NULL) assert(dictSize == 0); + if (dictSize > 0) { + const BYTE* const previousDictEnd = dict->dictionary + dict->dictSize; + assert(dict->dictionary); + LZ4_memmove(safeBuffer, previousDictEnd - dictSize, (size_t)dictSize); + } dict->dictionary = (const BYTE*)safeBuffer; dict->dictSize = (U32)dictSize; @@ -1103,253 +1803,783 @@ int LZ4_saveDict (LZ4_stream_t* LZ4_dict, char* safeBuffer, int dictSize) -/******************************* -* Decompression functions -*******************************/ -/* - * This generic decompression function cover all use cases. - * It shall be instantiated several times, using different sets of directives - * Note that it is essential this generic function is really inlined, - * in order to remove useless branches during compilation optimization. - */ -FORCE_INLINE int LZ4_decompress_generic( - const char* const source, - char* const dest, - int inputSize, - int outputSize, /* If endOnInput==endOnInputSize, this value is the max size of Output Buffer. */ +/*-******************************* + * Decompression functions + ********************************/ - int endOnInput, /* endOnOutputSize, endOnInputSize */ - int partialDecoding, /* full, partial */ - int targetOutputSize, /* only used if partialDecoding==partial */ - int dict, /* noDict, withPrefix64k, usingExtDict */ - const BYTE* const lowPrefix, /* == dest if dict == noDict */ +typedef enum { decode_full_block = 0, partial_decode = 1 } earlyEnd_directive; + +#undef MIN +#define MIN(a,b) ( (a) < (b) ? (a) : (b) ) + + +/* variant for decompress_unsafe() + * does not know end of input + * presumes input is well formed + * note : will consume at least one byte */ +static size_t read_long_length_no_check(const BYTE** pp) +{ + size_t b, l = 0; + do { b = **pp; (*pp)++; l += b; } while (b==255); + DEBUGLOG(6, "read_long_length_no_check: +length=%zu using %zu input bytes", l, l/255 + 1) + return l; +} + +/* core decoder variant for LZ4_decompress_fast*() + * for legacy support only : these entry points are deprecated. + * - Presumes input is correctly formed (no defense vs malformed inputs) + * - Does not know input size (presume input buffer is "large enough") + * - Decompress a full block (only) + * @return : nb of bytes read from input. + * Note : this variant is not optimized for speed, just for maintenance. + * the goal is to remove support of decompress_fast*() variants by v2.0 +**/ +LZ4_FORCE_INLINE int +LZ4_decompress_unsafe_generic( + const BYTE* const istart, + BYTE* const ostart, + int decompressedSize, + + size_t prefixSize, + const BYTE* const dictStart, /* only if dict==usingExtDict */ + const size_t dictSize /* note: =0 if dictStart==NULL */ + ) +{ + const BYTE* ip = istart; + BYTE* op = (BYTE*)ostart; + BYTE* const oend = ostart + decompressedSize; + const BYTE* const prefixStart = ostart - prefixSize; + + DEBUGLOG(5, "LZ4_decompress_unsafe_generic"); + if (dictStart == NULL) assert(dictSize == 0); + + while (1) { + /* start new sequence */ + unsigned token = *ip++; + + /* literals */ + { size_t ll = token >> ML_BITS; + if (ll==15) { + /* long literal length */ + ll += read_long_length_no_check(&ip); + } + if ((size_t)(oend-op) < ll) return -1; /* output buffer overflow */ + LZ4_memmove(op, ip, ll); /* support in-place decompression */ + op += ll; + ip += ll; + if ((size_t)(oend-op) < MFLIMIT) { + if (op==oend) break; /* end of block */ + DEBUGLOG(5, "invalid: literals end at distance %zi from end of block", oend-op); + /* incorrect end of block : + * last match must start at least MFLIMIT==12 bytes before end of output block */ + return -1; + } } + + /* match */ + { size_t ml = token & 15; + size_t const offset = LZ4_readLE16(ip); + ip+=2; + + if (ml==15) { + /* long literal length */ + ml += read_long_length_no_check(&ip); + } + ml += MINMATCH; + + if ((size_t)(oend-op) < ml) return -1; /* output buffer overflow */ + + { const BYTE* match = op - offset; + + /* out of range */ + if (offset > (size_t)(op - prefixStart) + dictSize) { + DEBUGLOG(6, "offset out of range"); + return -1; + } + + /* check special case : extDict */ + if (offset > (size_t)(op - prefixStart)) { + /* extDict scenario */ + const BYTE* const dictEnd = dictStart + dictSize; + const BYTE* extMatch = dictEnd - (offset - (size_t)(op-prefixStart)); + size_t const extml = (size_t)(dictEnd - extMatch); + if (extml > ml) { + /* match entirely within extDict */ + LZ4_memmove(op, extMatch, ml); + op += ml; + ml = 0; + } else { + /* match split between extDict & prefix */ + LZ4_memmove(op, extMatch, extml); + op += extml; + ml -= extml; + } + match = prefixStart; + } + + /* match copy - slow variant, supporting overlap copy */ + { size_t u; + for (u=0; u= ipmax before start of loop. Returns initial_error if so. + * @error (output) - error code. Must be set to 0 before call. +**/ +typedef size_t Rvl_t; +static const Rvl_t rvl_error = (Rvl_t)(-1); +LZ4_FORCE_INLINE Rvl_t +read_variable_length(const BYTE** ip, const BYTE* ilimit, + int initial_check) +{ + Rvl_t s, length = 0; + assert(ip != NULL); + assert(*ip != NULL); + assert(ilimit != NULL); + if (initial_check && unlikely((*ip) >= ilimit)) { /* read limit reached */ + return rvl_error; + } + s = **ip; + (*ip)++; + length += s; + if (unlikely((*ip) > ilimit)) { /* read limit reached */ + return rvl_error; + } + /* accumulator overflow detection (32-bit mode only) */ + if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { + return rvl_error; + } + if (likely(s != 255)) return length; + do { + s = **ip; + (*ip)++; + length += s; + if (unlikely((*ip) > ilimit)) { /* read limit reached */ + return rvl_error; + } + /* accumulator overflow detection (32-bit mode only) */ + if ((sizeof(length) < 8) && unlikely(length > ((Rvl_t)(-1)/2)) ) { + return rvl_error; + } + } while (s == 255); + + return length; +} + +/*! LZ4_decompress_generic() : + * This generic decompression function covers all use cases. + * It shall be instantiated several times, using different sets of directives. + * Note that it is important for performance that this function really get inlined, + * in order to remove useless branches during compilation optimization. + */ +LZ4_FORCE_INLINE int +LZ4_decompress_generic( + const char* const src, + char* const dst, + int srcSize, + int outputSize, /* If endOnInput==endOnInputSize, this value is `dstCapacity` */ + + earlyEnd_directive partialDecoding, /* full, partial */ + dict_directive dict, /* noDict, withPrefix64k, usingExtDict */ + const BYTE* const lowPrefix, /* always <= dst, == dst when no prefix */ const BYTE* const dictStart, /* only if dict==usingExtDict */ const size_t dictSize /* note : = 0 if noDict */ ) { - /* Local Variables */ - const BYTE* ip = (const BYTE*) source; - const BYTE* const iend = ip + inputSize; + if ((src == NULL) || (outputSize < 0)) { return -1; } - BYTE* op = (BYTE*) dest; - BYTE* const oend = op + outputSize; - BYTE* cpy; - BYTE* oexit = op + targetOutputSize; - const BYTE* const lowLimit = lowPrefix - dictSize; + { const BYTE* ip = (const BYTE*) src; + const BYTE* const iend = ip + srcSize; - const BYTE* const dictEnd = (const BYTE*)dictStart + dictSize; - const size_t dec32table[] = {4, 1, 2, 1, 4, 4, 4, 4}; - const size_t dec64table[] = {0, 0, 0, (size_t)-1, 0, 1, 2, 3}; + BYTE* op = (BYTE*) dst; + BYTE* const oend = op + outputSize; + BYTE* cpy; - const int safeDecode = (endOnInput==endOnInputSize); - const int checkOffset = ((safeDecode) && (dictSize < (int)(64 KB))); + const BYTE* const dictEnd = (dictStart == NULL) ? NULL : dictStart + dictSize; + + const int checkOffset = (dictSize < (int)(64 KB)); - /* Special cases */ - if ((partialDecoding) && (oexit> oend-MFLIMIT)) oexit = oend-MFLIMIT; /* targetOutputSize too high => decode everything */ - if ((endOnInput) && (unlikely(outputSize==0))) return ((inputSize==1) && (*ip==0)) ? 0 : -1; /* Empty output buffer */ - if ((!endOnInput) && (unlikely(outputSize==0))) return (*ip==0?1:-1); + /* Set up the "end" pointers for the shortcut. */ + const BYTE* const shortiend = iend - 14 /*maxLL*/ - 2 /*offset*/; + const BYTE* const shortoend = oend - 14 /*maxLL*/ - 18 /*maxML*/; - - /* Main Loop */ - while (1) - { + const BYTE* match; + size_t offset; unsigned token; size_t length; - const BYTE* match; - /* get literal length */ - token = *ip++; - if ((length=(token>>ML_BITS)) == RUN_MASK) - { - unsigned s; - do - { - s = *ip++; - length += s; - } - while (likely((endOnInput)?ip(partialDecoding?oexit:oend-MFLIMIT)) || (ip+length>iend-(2+1+LASTLITERALS))) ) - || ((!endOnInput) && (cpy>oend-COPYLENGTH))) - { - if (partialDecoding) - { - if (cpy > oend) goto _output_error; /* Error : write attempt beyond end of output buffer */ - if ((endOnInput) && (ip+length > iend)) goto _output_error; /* Error : read attempt beyond end of input buffer */ - } - else - { - if ((!endOnInput) && (cpy != oend)) goto _output_error; /* Error : block decoding must stop exactly there */ - if ((endOnInput) && ((ip+length != iend) || (cpy > oend))) goto _output_error; /* Error : input must be consumed */ - } - memcpy(op, ip, length); - ip += length; - op += length; - break; /* Necessarily EOF, due to parsing restrictions */ - } - LZ4_wildCopy(op, ip, cpy); - ip += length; op = cpy; + /* Fast loop : decode sequences as long as output < oend-FASTLOOP_SAFE_DISTANCE */ + DEBUGLOG(6, "using fast decode loop"); + while (1) { + /* Main fastloop assertion: We can always wildcopy FASTLOOP_SAFE_DISTANCE */ + assert(oend - op >= FASTLOOP_SAFE_DISTANCE); + assert(ip < iend); + token = *ip++; + length = token >> ML_BITS; /* literal length */ - /* get offset */ - match = cpy - LZ4_readLE16(ip); ip+=2; - if ((checkOffset) && (unlikely(match < lowLimit))) goto _output_error; /* Error : offset outside destination buffer */ - - /* get matchlength */ - length = token & ML_MASK; - if (length == ML_MASK) - { - unsigned s; - do - { - if ((endOnInput) && (ip > iend-LASTLITERALS)) goto _output_error; - s = *ip++; - length += s; - } while (s==255); - if ((safeDecode) && unlikely((size_t)(op+length)<(size_t)op)) goto _output_error; /* overflow detection */ - } - length += MINMATCH; - - /* check external dictionary */ - if ((dict==usingExtDict) && (match < lowPrefix)) - { - if (unlikely(op+length > oend-LASTLITERALS)) goto _output_error; /* doesn't respect parsing restriction */ - - if (length <= (size_t)(lowPrefix-match)) - { - /* match can be copied as a single segment from external dictionary */ - match = dictEnd - (lowPrefix-match); - memmove(op, match, length); op += length; - } - else - { - /* match encompass external dictionary and current segment */ - size_t copySize = (size_t)(lowPrefix-match); - memcpy(op, dictEnd - copySize, copySize); - op += copySize; - copySize = length - copySize; - if (copySize > (size_t)(op-lowPrefix)) /* overlap within current segment */ - { - BYTE* const endOfMatch = op + copySize; - const BYTE* copyFrom = lowPrefix; - while (op < endOfMatch) *op++ = *copyFrom++; + /* decode literal length */ + if (length == RUN_MASK) { + size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); + if (addl == rvl_error) { + DEBUGLOG(6, "error reading long literal length"); + goto _output_error; } - else - { - memcpy(op, lowPrefix, copySize); + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ + if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ + + /* copy literals */ + LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); + if ((op+length>oend-32) || (ip+length>iend-32)) { goto safe_literal_copy; } + LZ4_wildCopy32(op, ip, op+length); + ip += length; op += length; + } else if (ip <= iend-(16 + 1/*max lit + offset + nextToken*/)) { + /* We don't need to check oend, since we check it once for each loop below */ + DEBUGLOG(7, "copy %u bytes in a 16-bytes stripe", (unsigned)length); + /* Literals can only be <= 14, but hope compilers optimize better when copy by a register size */ + LZ4_memcpy(op, ip, 16); + ip += length; op += length; + } else { + goto safe_literal_copy; + } + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + DEBUGLOG(6, " offset = %zu", offset); + match = op - offset; + assert(match <= op); /* overflow check */ + + /* get matchlength */ + length = token & ML_MASK; + + if (length == ML_MASK) { + size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { + DEBUGLOG(6, "error reading long match length"); + goto _output_error; + } + length += addl; + length += MINMATCH; + if (unlikely((uptrval)(op)+length<(uptrval)op)) { goto _output_error; } /* overflow detection */ + if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { + goto safe_match_copy; + } + } else { + length += MINMATCH; + if (op + length >= oend - FASTLOOP_SAFE_DISTANCE) { + goto safe_match_copy; + } + + /* Fastpath check: skip LZ4_wildCopy32 when true */ + if ((dict == withPrefix64k) || (match >= lowPrefix)) { + if (offset >= 8) { + assert(match >= lowPrefix); + assert(match <= op); + assert(op + 18 <= oend); + + LZ4_memcpy(op, match, 8); + LZ4_memcpy(op+8, match+8, 8); + LZ4_memcpy(op+16, match+16, 2); + op += length; + continue; + } } } + + if ( checkOffset && (unlikely(match + dictSize < lowPrefix)) ) { + DEBUGLOG(6, "Error : pos=%zi, offset=%zi => outside buffers", op-lowPrefix, op-match); + goto _output_error; + } + /* match starting within external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); + if (unlikely(op+length > oend-LASTLITERALS)) { + if (partialDecoding) { + DEBUGLOG(7, "partialDecoding: dictionary match, close to dstEnd"); + length = MIN(length, (size_t)(oend-op)); + } else { + DEBUGLOG(6, "end-of-block condition violated") + goto _output_error; + } } + + if (length <= (size_t)(lowPrefix-match)) { + /* match fits entirely within external dictionary : just copy */ + LZ4_memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match stretches into both external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + LZ4_memcpy(op, dictEnd - copySize, copySize); op += copySize; + if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) { *op++ = *copyFrom++; } + } else { + LZ4_memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + + /* copy match within block */ + cpy = op + length; + + assert((op <= oend) && (oend-op >= 32)); + if (unlikely(offset<16)) { + LZ4_memcpy_using_offset(op, match, cpy, offset); + } else { + LZ4_wildCopy32(op, match, cpy); + } + + op = cpy; /* wildcopy correction */ + } + safe_decode: +#endif + + /* Main Loop : decode remaining sequences where output < FASTLOOP_SAFE_DISTANCE */ + DEBUGLOG(6, "using safe decode loop"); + while (1) { + assert(ip < iend); + token = *ip++; + length = token >> ML_BITS; /* literal length */ + + /* A two-stage shortcut for the most common case: + * 1) If the literal length is 0..14, and there is enough space, + * enter the shortcut and copy 16 bytes on behalf of the literals + * (in the fast mode, only 8 bytes can be safely copied this way). + * 2) Further if the match length is 4..18, copy 18 bytes in a similar + * manner; but we ensure that there's enough space in the output for + * those 18 bytes earlier, upon entering the shortcut (in other words, + * there is a combined check for both stages). + */ + if ( (length != RUN_MASK) + /* strictly "less than" on input, to re-enter the loop with at least one byte */ + && likely((ip < shortiend) & (op <= shortoend)) ) { + /* Copy the literals */ + LZ4_memcpy(op, ip, 16); + op += length; ip += length; + + /* The second stage: prepare for match copying, decode full info. + * If it doesn't work out, the info won't be wasted. */ + length = token & ML_MASK; /* match length */ + offset = LZ4_readLE16(ip); ip += 2; + match = op - offset; + assert(match <= op); /* check overflow */ + + /* Do not deal with overlapping matches. */ + if ( (length != ML_MASK) + && (offset >= 8) + && (dict==withPrefix64k || match >= lowPrefix) ) { + /* Copy the match. */ + LZ4_memcpy(op + 0, match + 0, 8); + LZ4_memcpy(op + 8, match + 8, 8); + LZ4_memcpy(op +16, match +16, 2); + op += length + MINMATCH; + /* Both stages worked, load the next token. */ + continue; } + + /* The second stage didn't work out, but the info is ready. + * Propel it right to the point of match copying. */ + goto _copy_match; } - continue; + + /* decode literal length */ + if (length == RUN_MASK) { + size_t const addl = read_variable_length(&ip, iend-RUN_MASK, 1); + if (addl == rvl_error) { goto _output_error; } + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)(op))) { goto _output_error; } /* overflow detection */ + if (unlikely((uptrval)(ip)+length<(uptrval)(ip))) { goto _output_error; } /* overflow detection */ + } + +#if LZ4_FAST_DEC_LOOP + safe_literal_copy: +#endif + /* copy literals */ + cpy = op+length; + + LZ4_STATIC_ASSERT(MFLIMIT >= WILDCOPYLENGTH); + if ((cpy>oend-MFLIMIT) || (ip+length>iend-(2+1+LASTLITERALS))) { + /* We've either hit the input parsing restriction or the output parsing restriction. + * In the normal scenario, decoding a full block, it must be the last sequence, + * otherwise it's an error (invalid input or dimensions). + * In partialDecoding scenario, it's necessary to ensure there is no buffer overflow. + */ + if (partialDecoding) { + /* Since we are partial decoding we may be in this block because of the output parsing + * restriction, which is not valid since the output buffer is allowed to be undersized. + */ + DEBUGLOG(7, "partialDecoding: copying literals, close to input or output end") + DEBUGLOG(7, "partialDecoding: literal length = %u", (unsigned)length); + DEBUGLOG(7, "partialDecoding: remaining space in dstBuffer : %i", (int)(oend - op)); + DEBUGLOG(7, "partialDecoding: remaining space in srcBuffer : %i", (int)(iend - ip)); + /* Finishing in the middle of a literals segment, + * due to lack of input. + */ + if (ip+length > iend) { + length = (size_t)(iend-ip); + cpy = op + length; + } + /* Finishing in the middle of a literals segment, + * due to lack of output space. + */ + if (cpy > oend) { + cpy = oend; + assert(op<=oend); + length = (size_t)(oend-op); + } + } else { + /* We must be on the last sequence (or invalid) because of the parsing limitations + * so check that we exactly consume the input and don't overrun the output buffer. + */ + if ((ip+length != iend) || (cpy > oend)) { + DEBUGLOG(6, "should have been last run of literals") + DEBUGLOG(6, "ip(%p) + length(%i) = %p != iend (%p)", ip, (int)length, ip+length, iend); + DEBUGLOG(6, "or cpy(%p) > oend(%p)", cpy, oend); + goto _output_error; + } + } + LZ4_memmove(op, ip, length); /* supports overlapping memory regions, for in-place decompression scenarios */ + ip += length; + op += length; + /* Necessarily EOF when !partialDecoding. + * When partialDecoding, it is EOF if we've either + * filled the output buffer or + * can't proceed with reading an offset for following match. + */ + if (!partialDecoding || (cpy == oend) || (ip >= (iend-2))) { + break; + } + } else { + LZ4_wildCopy8(op, ip, cpy); /* can overwrite up to 8 bytes beyond cpy */ + ip += length; op = cpy; + } + + /* get offset */ + offset = LZ4_readLE16(ip); ip+=2; + match = op - offset; + + /* get matchlength */ + length = token & ML_MASK; + + _copy_match: + if (length == ML_MASK) { + size_t const addl = read_variable_length(&ip, iend - LASTLITERALS + 1, 0); + if (addl == rvl_error) { goto _output_error; } + length += addl; + if (unlikely((uptrval)(op)+length<(uptrval)op)) goto _output_error; /* overflow detection */ + } + length += MINMATCH; + +#if LZ4_FAST_DEC_LOOP + safe_match_copy: +#endif + if ((checkOffset) && (unlikely(match + dictSize < lowPrefix))) goto _output_error; /* Error : offset outside buffers */ + /* match starting within external dictionary */ + if ((dict==usingExtDict) && (match < lowPrefix)) { + assert(dictEnd != NULL); + if (unlikely(op+length > oend-LASTLITERALS)) { + if (partialDecoding) length = MIN(length, (size_t)(oend-op)); + else goto _output_error; /* doesn't respect parsing restriction */ + } + + if (length <= (size_t)(lowPrefix-match)) { + /* match fits entirely within external dictionary : just copy */ + LZ4_memmove(op, dictEnd - (lowPrefix-match), length); + op += length; + } else { + /* match stretches into both external dictionary and current block */ + size_t const copySize = (size_t)(lowPrefix - match); + size_t const restSize = length - copySize; + LZ4_memcpy(op, dictEnd - copySize, copySize); + op += copySize; + if (restSize > (size_t)(op - lowPrefix)) { /* overlap copy */ + BYTE* const endOfMatch = op + restSize; + const BYTE* copyFrom = lowPrefix; + while (op < endOfMatch) *op++ = *copyFrom++; + } else { + LZ4_memcpy(op, lowPrefix, restSize); + op += restSize; + } } + continue; + } + assert(match >= lowPrefix); + + /* copy match within block */ + cpy = op + length; + + /* partialDecoding : may end anywhere within the block */ + assert(op<=oend); + if (partialDecoding && (cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { + size_t const mlen = MIN(length, (size_t)(oend-op)); + const BYTE* const matchEnd = match + mlen; + BYTE* const copyEnd = op + mlen; + if (matchEnd > op) { /* overlap copy */ + while (op < copyEnd) { *op++ = *match++; } + } else { + LZ4_memcpy(op, match, mlen); + } + op = copyEnd; + if (op == oend) { break; } + continue; + } + + if (unlikely(offset<8)) { + LZ4_write32(op, 0); /* silence msan warning when offset==0 */ + op[0] = match[0]; + op[1] = match[1]; + op[2] = match[2]; + op[3] = match[3]; + match += inc32table[offset]; + LZ4_memcpy(op+4, match, 4); + match -= dec64table[offset]; + } else { + LZ4_memcpy(op, match, 8); + match += 8; + } + op += 8; + + if (unlikely(cpy > oend-MATCH_SAFEGUARD_DISTANCE)) { + BYTE* const oCopyLimit = oend - (WILDCOPYLENGTH-1); + if (cpy > oend-LASTLITERALS) { goto _output_error; } /* Error : last LASTLITERALS bytes must be literals (uncompressed) */ + if (op < oCopyLimit) { + LZ4_wildCopy8(op, match, oCopyLimit); + match += oCopyLimit - op; + op = oCopyLimit; + } + while (op < cpy) { *op++ = *match++; } + } else { + LZ4_memcpy(op, match, 8); + if (length > 16) { LZ4_wildCopy8(op+8, match+8, cpy); } + } + op = cpy; /* wildcopy correction */ } - /* copy repeated sequence */ - cpy = op + length; - if (unlikely((op-match)<8)) - { - const size_t dec64 = dec64table[op-match]; - op[0] = match[0]; - op[1] = match[1]; - op[2] = match[2]; - op[3] = match[3]; - match += dec32table[op-match]; - LZ4_copy4(op+4, match); - op += 8; match -= dec64; - } else { LZ4_copy8(op, match); op+=8; match+=8; } + /* end of decoding */ + DEBUGLOG(5, "decoded %i bytes", (int) (((char*)op)-dst)); + return (int) (((char*)op)-dst); /* Nb of output bytes decoded */ - if (unlikely(cpy>oend-12)) - { - if (cpy > oend-LASTLITERALS) goto _output_error; /* Error : last LASTLITERALS bytes must be literals */ - if (op < oend-8) - { - LZ4_wildCopy(op, match, oend-8); - match += (oend-8) - op; - op = oend-8; - } - while (op= sizeof(LZ4_streamDecode_t_internal)); + return (LZ4_streamDecode_t*) ALLOC_AND_ZERO(sizeof(LZ4_streamDecode_t)); } int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream) { + if (LZ4_stream == NULL) { return 0; } /* support free on NULL */ FREEMEM(LZ4_stream); return 0; } +#endif -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary - * This function is not necessary if previous data is still available where it was decoded. - * Loading a size of 0 is allowed (same effect as no dictionary). - * Return : 1 if OK, 0 if error +/*! LZ4_setStreamDecode() : + * Use this function to instruct where to find the dictionary. + * This function is not necessary if previous data is still available where it was decoded. + * Loading a size of 0 is allowed (same effect as no dictionary). + * @return : 1 if OK, 0 if error */ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; - lz4sd->prefixSize = (size_t) dictSize; - lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; + lz4sd->prefixSize = (size_t)dictSize; + if (dictSize) { + assert(dictionary != NULL); + lz4sd->prefixEnd = (const BYTE*) dictionary + dictSize; + } else { + lz4sd->prefixEnd = (const BYTE*) dictionary; + } lz4sd->externalDict = NULL; lz4sd->extDictSize = 0; return 1; } +/*! LZ4_decoderRingBufferSize() : + * when setting a ring buffer for streaming decompression (optional scenario), + * provides the minimum size of this ring buffer + * to be compatible with any source respecting maxBlockSize condition. + * Note : in a ring buffer scenario, + * blocks are presumed decompressed next to each other. + * When not enough space remains for next block (remainingSize < maxBlockSize), + * decoding resumes from beginning of ring buffer. + * @return : minimum ring buffer size, + * or 0 if there is an error (invalid maxBlockSize). + */ +int LZ4_decoderRingBufferSize(int maxBlockSize) +{ + if (maxBlockSize < 0) return 0; + if (maxBlockSize > LZ4_MAX_INPUT_SIZE) return 0; + if (maxBlockSize < 16) maxBlockSize = 16; + return LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize); +} + /* *_continue() : These decoding functions allow decompression of multiple blocks in "streaming" mode. @@ -1357,58 +2587,81 @@ int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dicti If it's not possible, save the relevant part of decoded data into a safe buffer, and indicate where it stands using LZ4_setStreamDecode() */ +LZ4_FORCE_O2 int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxOutputSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + LZ4_streamDecode_t_internal* lz4sd = &LZ4_streamDecode->internal_donotuse; int result; - if (lz4sd->prefixEnd == (BYTE*)dest) - { - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (lz4sd->prefixSize == 0) { + /* The first call, no dictionary yet. */ + assert(lz4sd->extDictSize == 0); + result = LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); if (result <= 0) return result; - lz4sd->prefixSize += result; + lz4sd->prefixSize = (size_t)result; + lz4sd->prefixEnd = (BYTE*)dest + result; + } else if (lz4sd->prefixEnd == (BYTE*)dest) { + /* They're rolling the current segment. */ + if (lz4sd->prefixSize >= 64 KB - 1) + result = LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize); + else if (lz4sd->extDictSize == 0) + result = LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, + lz4sd->prefixSize); + else + result = LZ4_decompress_safe_doubleDict(source, dest, compressedSize, maxOutputSize, + lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += (size_t)result; lz4sd->prefixEnd += result; - } - else - { + } else { + /* The buffer wraps around, or they're switching to another buffer. */ lz4sd->extDictSize = lz4sd->prefixSize; lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, - endOnInputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + result = LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, + lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize = result; + lz4sd->prefixSize = (size_t)result; lz4sd->prefixEnd = (BYTE*)dest + result; } return result; } -int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize) +LZ4_FORCE_O2 int +LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, + const char* source, char* dest, int originalSize) { - LZ4_streamDecode_t_internal* lz4sd = (LZ4_streamDecode_t_internal*) LZ4_streamDecode; + LZ4_streamDecode_t_internal* const lz4sd = + (assert(LZ4_streamDecode!=NULL), &LZ4_streamDecode->internal_donotuse); int result; - if (lz4sd->prefixEnd == (BYTE*)dest) - { - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, lz4sd->prefixEnd - lz4sd->prefixSize, lz4sd->externalDict, lz4sd->extDictSize); + DEBUGLOG(5, "LZ4_decompress_fast_continue (toDecodeSize=%i)", originalSize); + assert(originalSize >= 0); + + if (lz4sd->prefixSize == 0) { + DEBUGLOG(5, "first invocation : no prefix nor extDict"); + assert(lz4sd->extDictSize == 0); + result = LZ4_decompress_fast(source, dest, originalSize); if (result <= 0) return result; - lz4sd->prefixSize += originalSize; + lz4sd->prefixSize = (size_t)originalSize; + lz4sd->prefixEnd = (BYTE*)dest + originalSize; + } else if (lz4sd->prefixEnd == (BYTE*)dest) { + DEBUGLOG(5, "continue using existing prefix"); + result = LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + lz4sd->prefixSize, + lz4sd->externalDict, lz4sd->extDictSize); + if (result <= 0) return result; + lz4sd->prefixSize += (size_t)originalSize; lz4sd->prefixEnd += originalSize; - } - else - { + } else { + DEBUGLOG(5, "prefix becomes extDict"); lz4sd->extDictSize = lz4sd->prefixSize; - lz4sd->externalDict = (BYTE*)dest - lz4sd->extDictSize; - result = LZ4_decompress_generic(source, dest, 0, originalSize, - endOnOutputSize, full, 0, - usingExtDict, (BYTE*)dest, lz4sd->externalDict, lz4sd->extDictSize); + lz4sd->externalDict = lz4sd->prefixEnd - lz4sd->extDictSize; + result = LZ4_decompress_fast_extDict(source, dest, originalSize, + lz4sd->externalDict, lz4sd->extDictSize); if (result <= 0) return result; - lz4sd->prefixSize = originalSize; + lz4sd->prefixSize = (size_t)originalSize; lz4sd->prefixEnd = (BYTE*)dest + originalSize; } @@ -1423,99 +2676,114 @@ Advanced decoding functions : the dictionary must be explicitly provided within parameters */ -FORCE_INLINE int LZ4_decompress_usingDict_generic(const char* source, char* dest, int compressedSize, int maxOutputSize, int safe, const char* dictStart, int dictSize) -{ - if (dictSize==0) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest, NULL, 0); - if (dictStart+dictSize == dest) - { - if (dictSize >= (int)(64 KB - 1)) - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, withPrefix64k, (BYTE*)dest-64 KB, NULL, 0); - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, noDict, (BYTE*)dest-dictSize, NULL, 0); - } - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, safe, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); -} - int LZ4_decompress_safe_usingDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, compressedSize, maxOutputSize, 1, dictStart, dictSize); + if (dictSize==0) + return LZ4_decompress_safe(source, dest, compressedSize, maxOutputSize); + if (dictStart+dictSize == dest) { + if (dictSize >= 64 KB - 1) { + return LZ4_decompress_safe_withPrefix64k(source, dest, compressedSize, maxOutputSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_withSmallPrefix(source, dest, compressedSize, maxOutputSize, (size_t)dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_forceExtDict(source, dest, compressedSize, maxOutputSize, dictStart, (size_t)dictSize); +} + +int LZ4_decompress_safe_partial_usingDict(const char* source, char* dest, int compressedSize, int targetOutputSize, int dstCapacity, const char* dictStart, int dictSize) +{ + if (dictSize==0) + return LZ4_decompress_safe_partial(source, dest, compressedSize, targetOutputSize, dstCapacity); + if (dictStart+dictSize == dest) { + if (dictSize >= 64 KB - 1) { + return LZ4_decompress_safe_partial_withPrefix64k(source, dest, compressedSize, targetOutputSize, dstCapacity); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_withSmallPrefix(source, dest, compressedSize, targetOutputSize, dstCapacity, (size_t)dictSize); + } + assert(dictSize >= 0); + return LZ4_decompress_safe_partial_forceExtDict(source, dest, compressedSize, targetOutputSize, dstCapacity, dictStart, (size_t)dictSize); } int LZ4_decompress_fast_usingDict(const char* source, char* dest, int originalSize, const char* dictStart, int dictSize) { - return LZ4_decompress_usingDict_generic(source, dest, 0, originalSize, 0, dictStart, dictSize); -} - -/* debug function */ -int LZ4_decompress_safe_forceExtDict(const char* source, char* dest, int compressedSize, int maxOutputSize, const char* dictStart, int dictSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, usingExtDict, (BYTE*)dest, (const BYTE*)dictStart, dictSize); + if (dictSize==0 || dictStart+dictSize == dest) + return LZ4_decompress_unsafe_generic( + (const BYTE*)source, (BYTE*)dest, originalSize, + (size_t)dictSize, NULL, 0); + assert(dictSize >= 0); + return LZ4_decompress_fast_extDict(source, dest, originalSize, dictStart, (size_t)dictSize); } -/*************************************************** +/*=************************************************* * Obsolete Functions ***************************************************/ /* obsolete compression functions */ -int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) { return LZ4_compress_default(source, dest, inputSize, maxOutputSize); } -int LZ4_compress(const char* source, char* dest, int inputSize) { return LZ4_compress_default(source, dest, inputSize, LZ4_compressBound(inputSize)); } -int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); } -int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) { return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); } -int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int maxDstSize) { return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, maxDstSize, 1); } -int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) { return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); } +int LZ4_compress_limitedOutput(const char* source, char* dest, int inputSize, int maxOutputSize) +{ + return LZ4_compress_default(source, dest, inputSize, maxOutputSize); +} +int LZ4_compress(const char* src, char* dest, int srcSize) +{ + return LZ4_compress_default(src, dest, srcSize, LZ4_compressBound(srcSize)); +} +int LZ4_compress_limitedOutput_withState (void* state, const char* src, char* dst, int srcSize, int dstSize) +{ + return LZ4_compress_fast_extState(state, src, dst, srcSize, dstSize, 1); +} +int LZ4_compress_withState (void* state, const char* src, char* dst, int srcSize) +{ + return LZ4_compress_fast_extState(state, src, dst, srcSize, LZ4_compressBound(srcSize), 1); +} +int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_stream, const char* src, char* dst, int srcSize, int dstCapacity) +{ + return LZ4_compress_fast_continue(LZ4_stream, src, dst, srcSize, dstCapacity, 1); +} +int LZ4_compress_continue (LZ4_stream_t* LZ4_stream, const char* source, char* dest, int inputSize) +{ + return LZ4_compress_fast_continue(LZ4_stream, source, dest, inputSize, LZ4_compressBound(inputSize), 1); +} /* -These function names are deprecated and should no longer be used. +These decompression functions are deprecated and should no longer be used. They are only provided here for compatibility with older user programs. - LZ4_uncompress is totally equivalent to LZ4_decompress_fast - LZ4_uncompress_unknownOutputSize is totally equivalent to LZ4_decompress_safe */ -int LZ4_uncompress (const char* source, char* dest, int outputSize) { return LZ4_decompress_fast(source, dest, outputSize); } -int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) { return LZ4_decompress_safe(source, dest, isize, maxOutputSize); } - +int LZ4_uncompress (const char* source, char* dest, int outputSize) +{ + return LZ4_decompress_fast(source, dest, outputSize); +} +int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize) +{ + return LZ4_decompress_safe(source, dest, isize, maxOutputSize); +} /* Obsolete Streaming functions */ -int LZ4_sizeofStreamState() { return LZ4_STREAMSIZE; } - -static void LZ4_init(LZ4_stream_t_internal* lz4ds, BYTE* base) -{ - MEM_INIT(lz4ds, 0, LZ4_STREAMSIZE); - lz4ds->bufferStart = base; -} +int LZ4_sizeofStreamState(void) { return sizeof(LZ4_stream_t); } int LZ4_resetStreamState(void* state, char* inputBuffer) { - if ((((size_t)state) & 3) != 0) return 1; /* Error : pointer is not aligned on 4-bytes boundary */ - LZ4_init((LZ4_stream_t_internal*)state, (BYTE*)inputBuffer); + (void)inputBuffer; + LZ4_resetStream((LZ4_stream_t*)state); return 0; } +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) void* LZ4_create (char* inputBuffer) { - void* lz4ds = ALLOCATOR(8, LZ4_STREAMSIZE_U64); - LZ4_init ((LZ4_stream_t_internal*)lz4ds, (BYTE*)inputBuffer); - return lz4ds; + (void)inputBuffer; + return LZ4_createStream(); } +#endif -char* LZ4_slideInputBuffer (void* LZ4_Data) +char* LZ4_slideInputBuffer (void* state) { - LZ4_stream_t_internal* ctx = (LZ4_stream_t_internal*)LZ4_Data; - int dictSize = LZ4_saveDict((LZ4_stream_t*)LZ4_Data, (char*)ctx->bufferStart, 64 KB); - return (char*)(ctx->bufferStart + dictSize); -} - -/* Obsolete streaming decompression functions */ - -int LZ4_decompress_safe_withPrefix64k(const char* source, char* dest, int compressedSize, int maxOutputSize) -{ - return LZ4_decompress_generic(source, dest, compressedSize, maxOutputSize, endOnInputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); -} - -int LZ4_decompress_fast_withPrefix64k(const char* source, char* dest, int originalSize) -{ - return LZ4_decompress_generic(source, dest, 0, originalSize, endOnOutputSize, full, 0, withPrefix64k, (BYTE*)dest - 64 KB, NULL, 64 KB); + /* avoid const char * -> char * conversion warning */ + return (char *)(uptrval)((LZ4_stream_t*)state)->internal_donotuse.dictionary; } #endif /* LZ4_COMMONDEFS_ONLY */ - diff --git a/include/gtkwave/lz4.h b/include/gtkwave/lz4.h index bd5245ea5..7a2dbfd4b 100644 --- a/include/gtkwave/lz4.h +++ b/include/gtkwave/lz4.h @@ -1,7 +1,7 @@ /* - LZ4 - Fast LZ compression algorithm - Header File - Copyright (C) 2011-2015, Yann Collet. + * LZ4 - Fast LZ compression algorithm + * Header File + * Copyright (C) 2011-2023, Yann Collet. BSD 2-Clause License (http://www.opensource.org/licenses/bsd-license.php) @@ -28,333 +28,839 @@ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - SPDX-License-Identifier: BSD-2-Clause - You can contact the author at : - - LZ4 source repository : https://github.com/Cyan4973/lz4 - - LZ4 public forum : https://groups.google.com/forum/#!forum/lz4c + - LZ4 homepage : http://www.lz4.org + - LZ4 source repository : https://github.com/lz4/lz4 */ -#pragma once - #if defined (__cplusplus) extern "C" { #endif -/* - * lz4.h provides block compression functions, and gives full buffer control to programmer. - * If you need to generate inter-operable compressed data (respecting LZ4 frame specification), - * and can let the library handle its own memory, please use lz4frame.h instead. +#ifndef LZ4_H_2983827168210 +#define LZ4_H_2983827168210 + +/* --- Dependency --- */ +#include /* size_t */ + + +/** + Introduction + + LZ4 is lossless compression algorithm, providing compression speed >500 MB/s per core, + scalable with multi-cores CPU. It features an extremely fast decoder, with speed in + multiple GB/s per core, typically reaching RAM speed limits on multi-core systems. + + The LZ4 compression library provides in-memory compression and decompression functions. + It gives full buffer control to user. + Compression can be done in: + - a single step (described as Simple Functions) + - a single step, reusing a context (described in Advanced Functions) + - unbounded multiple steps (described as Streaming compression) + + lz4.h generates and decodes LZ4-compressed blocks (doc/lz4_Block_format.md). + Decompressing such a compressed block requires additional metadata. + Exact metadata depends on exact decompression function. + For the typical case of LZ4_decompress_safe(), + metadata includes block's compressed size, and maximum bound of decompressed size. + Each application is free to encode and pass such metadata in whichever way it wants. + + lz4.h only handle blocks, it can not generate Frames. + + Blocks are different from Frames (doc/lz4_Frame_format.md). + Frames bundle both blocks and metadata in a specified manner. + Embedding metadata is required for compressed data to be self-contained and portable. + Frame format is delivered through a companion API, declared in lz4frame.h. + The `lz4` CLI can only manage frames. */ -/************************************** -* Version -**************************************/ -#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ -#define LZ4_VERSION_MINOR 7 /* for new (non-breaking) interface capabilities */ -#define LZ4_VERSION_RELEASE 1 /* for tweaks, bug-fixes, or development */ -#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) -int LZ4_versionNumber (void); - -/************************************** -* Tuning parameter -**************************************/ +/*^*************************************************************** +* Export parameters +*****************************************************************/ /* - * LZ4_MEMORY_USAGE : - * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB; etc.) - * Increasing memory usage improves compression ratio - * Reduced memory usage can improve speed, due to cache effect - * Default value is 14, for 16KB, which nicely fits into Intel x86 L1 cache +* LZ4_DLL_EXPORT : +* Enable exporting of functions when building a Windows DLL +* LZ4LIB_VISIBILITY : +* Control library symbols visibility. +*/ +#ifndef LZ4LIB_VISIBILITY +# if defined(__GNUC__) && (__GNUC__ >= 4) +# define LZ4LIB_VISIBILITY __attribute__ ((visibility ("default"))) +# else +# define LZ4LIB_VISIBILITY +# endif +#endif +#if defined(LZ4_DLL_EXPORT) && (LZ4_DLL_EXPORT==1) +# define LZ4LIB_API __declspec(dllexport) LZ4LIB_VISIBILITY +#elif defined(LZ4_DLL_IMPORT) && (LZ4_DLL_IMPORT==1) +# define LZ4LIB_API __declspec(dllimport) LZ4LIB_VISIBILITY /* It isn't required but allows to generate better code, saving a function pointer load from the IAT and an indirect jump.*/ +#else +# define LZ4LIB_API LZ4LIB_VISIBILITY +#endif + +/*! LZ4_FREESTANDING : + * When this macro is set to 1, it enables "freestanding mode" that is + * suitable for typical freestanding environment which doesn't support + * standard C library. + * + * - LZ4_FREESTANDING is a compile-time switch. + * - It requires the following macros to be defined: + * LZ4_memcpy, LZ4_memmove, LZ4_memset. + * - It only enables LZ4/HC functions which don't use heap. + * All LZ4F_* functions are not supported. + * - See tests/freestanding.c to check its basic setup. */ -#define LZ4_MEMORY_USAGE 14 +#if defined(LZ4_FREESTANDING) && (LZ4_FREESTANDING == 1) +# define LZ4_HEAPMODE 0 +# define LZ4HC_HEAPMODE 0 +# define LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION 1 +# if !defined(LZ4_memcpy) +# error "LZ4_FREESTANDING requires macro 'LZ4_memcpy'." +# endif +# if !defined(LZ4_memset) +# error "LZ4_FREESTANDING requires macro 'LZ4_memset'." +# endif +# if !defined(LZ4_memmove) +# error "LZ4_FREESTANDING requires macro 'LZ4_memmove'." +# endif +#elif ! defined(LZ4_FREESTANDING) +# define LZ4_FREESTANDING 0 +#endif -/************************************** +/*------ Version ------*/ +#define LZ4_VERSION_MAJOR 1 /* for breaking interface changes */ +#define LZ4_VERSION_MINOR 9 /* for new (non-breaking) interface capabilities */ +#define LZ4_VERSION_RELEASE 5 /* for tweaks, bug-fixes, or development */ + +#define LZ4_VERSION_NUMBER (LZ4_VERSION_MAJOR *100*100 + LZ4_VERSION_MINOR *100 + LZ4_VERSION_RELEASE) + +#define LZ4_LIB_VERSION LZ4_VERSION_MAJOR.LZ4_VERSION_MINOR.LZ4_VERSION_RELEASE +#define LZ4_QUOTE(str) #str +#define LZ4_EXPAND_AND_QUOTE(str) LZ4_QUOTE(str) +#define LZ4_VERSION_STRING LZ4_EXPAND_AND_QUOTE(LZ4_LIB_VERSION) /* requires v1.7.3+ */ + +LZ4LIB_API int LZ4_versionNumber (void); /**< library version number; useful to check dll version; requires v1.3.0+ */ +LZ4LIB_API const char* LZ4_versionString (void); /**< library version string; useful to check dll version; requires v1.7.5+ */ + + +/*-************************************ +* Tuning memory usage +**************************************/ +/*! + * LZ4_MEMORY_USAGE : + * Memory usage formula : N->2^N Bytes (examples : 10 -> 1KB; 12 -> 4KB ; 16 -> 64KB; 20 -> 1MB) + * Increasing memory usage improves compression ratio, generally at the cost of speed. + * Reduced memory usage may improve speed at the cost of ratio, thanks to better cache locality. + * Default value is 14, for 16KB, which nicely fits into most L1 caches. + */ +#ifndef LZ4_MEMORY_USAGE +# define LZ4_MEMORY_USAGE LZ4_MEMORY_USAGE_DEFAULT +#endif + +#define LZ4_MEMORY_USAGE_MIN 10 +#define LZ4_MEMORY_USAGE_DEFAULT 14 +#define LZ4_MEMORY_USAGE_MAX 20 + +#if (LZ4_MEMORY_USAGE < LZ4_MEMORY_USAGE_MIN) +# error "LZ4_MEMORY_USAGE is too small !" +#endif + +#if (LZ4_MEMORY_USAGE > LZ4_MEMORY_USAGE_MAX) +# error "LZ4_MEMORY_USAGE is too large !" +#endif + +/*-************************************ * Simple Functions **************************************/ +/*! LZ4_compress_default() : + * Compresses 'srcSize' bytes from buffer 'src' + * into already allocated 'dst' buffer of size 'dstCapacity'. + * Compression is guaranteed to succeed if 'dstCapacity' >= LZ4_compressBound(srcSize). + * It also runs faster, so it's a recommended setting. + * If the function cannot compress 'src' into a more limited 'dst' budget, + * compression stops *immediately*, and the function result is zero. + * In which case, 'dst' content is undefined (invalid). + * srcSize : max supported value is LZ4_MAX_INPUT_SIZE. + * dstCapacity : size of buffer 'dst' (which must be already allocated) + * @return : the number of bytes written into buffer 'dst' (necessarily <= dstCapacity) + * or 0 if compression fails + * Note : This function is protected against buffer overflow scenarios (never writes outside 'dst' buffer, nor read outside 'source' buffer). + */ +LZ4LIB_API int LZ4_compress_default(const char* src, char* dst, int srcSize, int dstCapacity); -int LZ4_compress_default(const char* source, char* dest, int sourceSize, int maxDestSize); -int LZ4_decompress_safe (const char* source, char* dest, int compressedSize, int maxDecompressedSize); - -/* -LZ4_compress_default() : - Compresses 'sourceSize' bytes from buffer 'source' - into already allocated 'dest' buffer of size 'maxDestSize'. - Compression is guaranteed to succeed if 'maxDestSize' >= LZ4_compressBound(sourceSize). - It also runs faster, so it's a recommended setting. - If the function cannot compress 'source' into a more limited 'dest' budget, - compression stops *immediately*, and the function result is zero. - As a consequence, 'dest' content is not valid. - This function never writes outside 'dest' buffer, nor read outside 'source' buffer. - sourceSize : Max supported value is LZ4_MAX_INPUT_VALUE - maxDestSize : full or partial size of buffer 'dest' (which must be already allocated) - return : the number of bytes written into buffer 'dest' (necessarily <= maxOutputSize) - or 0 if compression fails - -LZ4_decompress_safe() : - compressedSize : is the precise full size of the compressed block. - maxDecompressedSize : is the size of destination buffer, which must be already allocated. - return : the number of bytes decompressed into destination buffer (necessarily <= maxDecompressedSize) - If destination buffer is not large enough, decoding will stop and output an error code (<0). - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function is protected against buffer overflow exploits, including malicious data packets. - It never writes outside output buffer, nor reads outside input buffer. -*/ +/*! LZ4_decompress_safe() : + * @compressedSize : is the exact complete size of the compressed block. + * @dstCapacity : is the size of destination buffer (which must be already allocated), + * presumed an upper bound of decompressed size. + * @return : the number of bytes decompressed into destination buffer (necessarily <= dstCapacity) + * If destination buffer is not large enough, decoding will stop and output an error code (negative value). + * If the source stream is detected malformed, the function will stop decoding and return a negative result. + * Note 1 : This function is protected against malicious data packets : + * it will never writes outside 'dst' buffer, nor read outside 'source' buffer, + * even if the compressed block is maliciously modified to order the decoder to do these actions. + * In such case, the decoder stops immediately, and considers the compressed block malformed. + * Note 2 : compressedSize and dstCapacity must be provided to the function, the compressed block does not contain them. + * The implementation is free to send / store / derive this information in whichever way is most beneficial. + * If there is a need for a different format which bundles together both compressed data and its metadata, consider looking at lz4frame.h instead. + */ +LZ4LIB_API int LZ4_decompress_safe (const char* src, char* dst, int compressedSize, int dstCapacity); -/************************************** +/*-************************************ * Advanced Functions **************************************/ #define LZ4_MAX_INPUT_SIZE 0x7E000000 /* 2 113 929 216 bytes */ #define LZ4_COMPRESSBOUND(isize) ((unsigned)(isize) > (unsigned)LZ4_MAX_INPUT_SIZE ? 0 : (isize) + ((isize)/255) + 16) -/* -LZ4_compressBound() : +/*! LZ4_compressBound() : Provides the maximum size that LZ4 compression may output in a "worst case" scenario (input data not compressible) This function is primarily useful for memory allocation purposes (destination buffer size). Macro LZ4_COMPRESSBOUND() is also provided for compilation-time evaluation (stack memory allocation for example). - Note that LZ4_compress_default() compress faster when dest buffer size is >= LZ4_compressBound(srcSize) + Note that LZ4_compress_default() compresses faster when dstCapacity is >= LZ4_compressBound(srcSize) inputSize : max supported value is LZ4_MAX_INPUT_SIZE return : maximum output size in a "worst case" scenario - or 0, if input size is too large ( > LZ4_MAX_INPUT_SIZE) + or 0, if input size is incorrect (too large or negative) */ -int LZ4_compressBound(int inputSize); +LZ4LIB_API int LZ4_compressBound(int inputSize); -/* -LZ4_compress_fast() : - Same as LZ4_compress_default(), but allows to select an "acceleration" factor. +/*! LZ4_compress_fast() : + Same as LZ4_compress_default(), but allows selection of "acceleration" factor. The larger the acceleration value, the faster the algorithm, but also the lesser the compression. It's a trade-off. It can be fine tuned, with each successive value providing roughly +~3% to speed. An acceleration value of "1" is the same as regular LZ4_compress_default() - Values <= 0 will be replaced by ACCELERATION_DEFAULT (see lz4.c), which is 1. + Values <= 0 will be replaced by LZ4_ACCELERATION_DEFAULT (currently == 1, see lz4.c). + Values > LZ4_ACCELERATION_MAX will be replaced by LZ4_ACCELERATION_MAX (currently == 65537, see lz4.c). */ -int LZ4_compress_fast (const char* source, char* dest, int sourceSize, int maxDestSize, int acceleration); +LZ4LIB_API int LZ4_compress_fast (const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); -/* -LZ4_compress_fast_extState() : - Same compression function, just using an externally allocated memory space to store compression state. - Use LZ4_sizeofState() to know how much memory must be allocated, - and allocate it on 8-bytes boundaries (using malloc() typically). - Then, provide it as 'void* state' to compression function. -*/ -int LZ4_sizeofState(void); -int LZ4_compress_fast_extState (void* state, const char* source, char* dest, int inputSize, int maxDestSize, int acceleration); +/*! LZ4_compress_fast_extState() : + * Same as LZ4_compress_fast(), using an externally allocated memory space for its state. + * Use LZ4_sizeofState() to know how much memory must be allocated, + * and allocate it on 8-bytes boundaries (using `malloc()` typically). + * Then, provide this buffer as `void* state` to compression function. + */ +LZ4LIB_API int LZ4_sizeofState(void); +LZ4LIB_API int LZ4_compress_fast_extState (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_compress_destSize() : + * Reverse the logic : compresses as much data as possible from 'src' buffer + * into already allocated buffer 'dst', of size >= 'dstCapacity'. + * This function either compresses the entire 'src' content into 'dst' if it's large enough, + * or fill 'dst' buffer completely with as much data as possible from 'src'. + * note: acceleration parameter is fixed to "default". + * + * *srcSizePtr : in+out parameter. Initially contains size of input. + * Will be modified to indicate how many bytes where read from 'src' to fill 'dst'. + * New value is necessarily <= input value. + * @return : Nb bytes written into 'dst' (necessarily <= dstCapacity) + * or 0 if compression fails. + * + * Note : from v1.8.2 to v1.9.1, this function had a bug (fixed in v1.9.2+): + * the produced compressed content could, in specific circumstances, + * require to be decompressed into a destination buffer larger + * by at least 1 byte than the content to decompress. + * If an application uses `LZ4_compress_destSize()`, + * it's highly recommended to update liblz4 to v1.9.2 or better. + * If this can't be done or ensured, + * the receiving decompression function should provide + * a dstCapacity which is > decompressedSize, by at least 1 byte. + * See https://github.com/lz4/lz4/issues/859 for details + */ +LZ4LIB_API int LZ4_compress_destSize(const char* src, char* dst, int* srcSizePtr, int targetDstSize); + +/*! LZ4_decompress_safe_partial() : + * Decompress an LZ4 compressed block, of size 'srcSize' at position 'src', + * into destination buffer 'dst' of size 'dstCapacity'. + * Up to 'targetOutputSize' bytes will be decoded. + * The function stops decoding on reaching this objective. + * This can be useful to boost performance + * whenever only the beginning of a block is required. + * + * @return : the number of bytes decoded in `dst` (necessarily <= targetOutputSize) + * If source stream is detected malformed, function returns a negative result. + * + * Note 1 : @return can be < targetOutputSize, if compressed block contains less data. + * + * Note 2 : targetOutputSize must be <= dstCapacity + * + * Note 3 : this function effectively stops decoding on reaching targetOutputSize, + * so dstCapacity is kind of redundant. + * This is because in older versions of this function, + * decoding operation would still write complete sequences. + * Therefore, there was no guarantee that it would stop writing at exactly targetOutputSize, + * it could write more bytes, though only up to dstCapacity. + * Some "margin" used to be required for this operation to work properly. + * Thankfully, this is no longer necessary. + * The function nonetheless keeps the same signature, in an effort to preserve API compatibility. + * + * Note 4 : If srcSize is the exact size of the block, + * then targetOutputSize can be any value, + * including larger than the block's decompressed size. + * The function will, at most, generate block's decompressed size. + * + * Note 5 : If srcSize is _larger_ than block's compressed size, + * then targetOutputSize **MUST** be <= block's decompressed size. + * Otherwise, *silent corruption will occur*. + */ +LZ4LIB_API int LZ4_decompress_safe_partial (const char* src, char* dst, int srcSize, int targetOutputSize, int dstCapacity); -/* -LZ4_compress_destSize() : - Reverse the logic, by compressing as much data as possible from 'source' buffer - into already allocated buffer 'dest' of size 'targetDestSize'. - This function either compresses the entire 'source' content into 'dest' if it's large enough, - or fill 'dest' buffer completely with as much data as possible from 'source'. - *sourceSizePtr : will be modified to indicate how many bytes where read from 'source' to fill 'dest'. - New value is necessarily <= old value. - return : Nb bytes written into 'dest' (necessarily <= targetDestSize) - or 0 if compression fails -*/ -int LZ4_compress_destSize (const char* source, char* dest, int* sourceSizePtr, int targetDestSize); - - -/* -LZ4_decompress_fast() : - originalSize : is the original and therefore uncompressed size - return : the number of bytes read from the source buffer (in other words, the compressed size) - If the source stream is detected malformed, the function will stop decoding and return a negative result. - Destination buffer must be already allocated. Its size must be a minimum of 'originalSize' bytes. - note : This function fully respect memory boundaries for properly formed compressed data. - It is a bit faster than LZ4_decompress_safe(). - However, it does not provide any protection against intentionally modified data stream (malicious input). - Use this function in trusted environment only (data to decode comes from a trusted source). -*/ -int LZ4_decompress_fast (const char* source, char* dest, int originalSize); - -/* -LZ4_decompress_safe_partial() : - This function decompress a compressed block of size 'compressedSize' at position 'source' - into destination buffer 'dest' of size 'maxDecompressedSize'. - The function tries to stop decompressing operation as soon as 'targetOutputSize' has been reached, - reducing decompression time. - return : the number of bytes decoded in the destination buffer (necessarily <= maxDecompressedSize) - Note : this number can be < 'targetOutputSize' should the compressed block to decode be smaller. - Always control how many bytes were decoded. - If the source stream is detected malformed, the function will stop decoding and return a negative result. - This function never writes outside of output buffer, and never reads outside of input buffer. It is therefore protected against malicious data packets -*/ -int LZ4_decompress_safe_partial (const char* source, char* dest, int compressedSize, int targetOutputSize, int maxDecompressedSize); - - -/*********************************************** +/*-********************************************* * Streaming Compression Functions ***********************************************/ -#define LZ4_STREAMSIZE_U64 ((1 << (LZ4_MEMORY_USAGE-3)) + 4) -#define LZ4_STREAMSIZE (LZ4_STREAMSIZE_U64 * sizeof(long long)) -/* - * LZ4_stream_t - * information structure to track an LZ4 stream. - * important : init this structure content before first use ! - * note : only allocated directly the structure if you are statically linking LZ4 - * If you are using liblz4 as a DLL, please use below construction methods instead. - */ -typedef struct { long long table[LZ4_STREAMSIZE_U64]; } LZ4_stream_t; +typedef union LZ4_stream_u LZ4_stream_t; /* incomplete type (defined later) */ -/* - * LZ4_resetStream - * Use this function to init an allocated LZ4_stream_t structure - */ -void LZ4_resetStream (LZ4_stream_t* streamPtr); +/*! + Note about RC_INVOKED -/* - * LZ4_createStream will allocate and initialize an LZ4_stream_t structure - * LZ4_freeStream releases its memory. - * In the context of a DLL (liblz4), please use these methods rather than the static struct. - * They are more future proof, in case of a change of LZ4_stream_t size. - */ -LZ4_stream_t* LZ4_createStream(void); -int LZ4_freeStream (LZ4_stream_t* streamPtr); + - RC_INVOKED is predefined symbol of rc.exe (the resource compiler which is part of MSVC/Visual Studio). + https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros -/* - * LZ4_loadDict - * Use this function to load a static dictionary into LZ4_stream. - * Any previous data will be forgotten, only 'dictionary' will remain in memory. - * Loading a size of 0 is allowed. - * Return : dictionary size, in bytes (necessarily <= 64 KB) - */ -int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); + - Since rc.exe is a legacy compiler, it truncates long symbol (> 30 chars) + and reports warning "RC4011: identifier truncated". -/* - * LZ4_compress_fast_continue - * Compress buffer content 'src', using data from previously compressed blocks as dictionary to improve compression ratio. - * Important : Previous data blocks are assumed to still be present and unmodified ! - * 'dst' buffer must be already allocated. - * If maxDstSize >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. - * If not, and if compressed data cannot fit into 'dst' buffer size, compression stops, and function returns a zero. - */ -int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int maxDstSize, int acceleration); + - To eliminate the warning, we surround long preprocessor symbol with + "#if !defined(RC_INVOKED) ... #endif" block that means + "skip this block when rc.exe is trying to read it". +*/ +#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) +LZ4LIB_API LZ4_stream_t* LZ4_createStream(void); +LZ4LIB_API int LZ4_freeStream (LZ4_stream_t* streamPtr); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif -/* - * LZ4_saveDict - * If previously compressed data block is not guaranteed to remain available at its memory location - * save it into a safer place (char* safeBuffer) - * Note : you don't need to call LZ4_loadDict() afterwards, - * dictionary is immediately usable, you can therefore call LZ4_compress_fast_continue() - * Return : saved dictionary size in bytes (necessarily <= dictSize), or 0 if error - */ -int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int dictSize); - - -/************************************************ -* Streaming Decompression Functions -************************************************/ - -#define LZ4_STREAMDECODESIZE_U64 4 -#define LZ4_STREAMDECODESIZE (LZ4_STREAMDECODESIZE_U64 * sizeof(unsigned long long)) -typedef struct { unsigned long long table[LZ4_STREAMDECODESIZE_U64]; } LZ4_streamDecode_t; -/* - * LZ4_streamDecode_t - * information structure to track an LZ4 stream. - * init this structure content using LZ4_setStreamDecode or memset() before first use ! +/*! LZ4_resetStream_fast() : v1.9.0+ + * Use this to prepare an LZ4_stream_t for a new chain of dependent blocks + * (e.g., LZ4_compress_fast_continue()). * - * In the context of a DLL (liblz4) please prefer usage of construction methods below. - * They are more future proof, in case of a change of LZ4_streamDecode_t size in the future. - * LZ4_createStreamDecode will allocate and initialize an LZ4_streamDecode_t structure - * LZ4_freeStreamDecode releases its memory. + * An LZ4_stream_t must be initialized once before usage. + * This is automatically done when created by LZ4_createStream(). + * However, should the LZ4_stream_t be simply declared on stack (for example), + * it's necessary to initialize it first, using LZ4_initStream(). + * + * After init, start any new stream with LZ4_resetStream_fast(). + * A same LZ4_stream_t can be re-used multiple times consecutively + * and compress multiple streams, + * provided that it starts each new stream with LZ4_resetStream_fast(). + * + * LZ4_resetStream_fast() is much faster than LZ4_initStream(), + * but is not compatible with memory regions containing garbage data. + * + * Note: it's only useful to call LZ4_resetStream_fast() + * in the context of streaming compression. + * The *extState* functions perform their own resets. + * Invoking LZ4_resetStream_fast() before is redundant, and even counterproductive. */ -LZ4_streamDecode_t* LZ4_createStreamDecode(void); -int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); +LZ4LIB_API void LZ4_resetStream_fast (LZ4_stream_t* streamPtr); -/* - * LZ4_setStreamDecode - * Use this function to instruct where to find the dictionary. - * Setting a size of 0 is allowed (same effect as reset). - * Return : 1 if OK, 0 if error +/*! LZ4_loadDict() : + * Use this function to reference a static dictionary into LZ4_stream_t. + * The dictionary must remain available during compression. + * LZ4_loadDict() triggers a reset, so any previous data will be forgotten. + * The same dictionary will have to be loaded on decompression side for successful decoding. + * Dictionary are useful for better compression of small data (KB range). + * While LZ4 itself accepts any input as dictionary, dictionary efficiency is also a topic. + * When in doubt, employ the Zstandard's Dictionary Builder. + * Loading a size of 0 is allowed, and is the same as reset. + * @return : loaded dictionary size, in bytes (note: only the last 64 KB are loaded) */ -int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); +LZ4LIB_API int LZ4_loadDict (LZ4_stream_t* streamPtr, const char* dictionary, int dictSize); -/* -*_continue() : - These decoding functions allow decompression of multiple blocks in "streaming" mode. - Previously decoded blocks *must* remain available at the memory position where they were decoded (up to 64 KB) - In the case of a ring buffers, decoding buffer must be either : - - Exactly same size as encoding buffer, with same update rule (block boundaries at same positions) - In which case, the decoding & encoding ring buffer can have any size, including very small ones ( < 64 KB). - - Larger than encoding buffer, by a minimum of maxBlockSize more bytes. - maxBlockSize is implementation dependent. It's the maximum size you intend to compress into a single block. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including small ones ( < 64 KB). - - _At least_ 64 KB + 8 bytes + maxBlockSize. - In which case, encoding and decoding buffers do not need to be synchronized, - and encoding ring buffer can have any size, including larger than decoding buffer. - Whenever these conditions are not possible, save the last 64KB of decoded data into a safe buffer, - and indicate where it is saved using LZ4_setStreamDecode() +/*! LZ4_compress_fast_continue() : + * Compress 'src' content using data from previously compressed blocks, for better compression ratio. + * 'dst' buffer must be already allocated. + * If dstCapacity >= LZ4_compressBound(srcSize), compression is guaranteed to succeed, and runs faster. + * + * @return : size of compressed block + * or 0 if there is an error (typically, cannot fit into 'dst'). + * + * Note 1 : Each invocation to LZ4_compress_fast_continue() generates a new block. + * Each block has precise boundaries. + * Each block must be decompressed separately, calling LZ4_decompress_*() with relevant metadata. + * It's not possible to append blocks together and expect a single invocation of LZ4_decompress_*() to decompress them together. + * + * Note 2 : The previous 64KB of source data is __assumed__ to remain present, unmodified, at same address in memory ! + * + * Note 3 : When input is structured as a double-buffer, each buffer can have any size, including < 64 KB. + * Make sure that buffers are separated, by at least one byte. + * This construction ensures that each block only depends on previous block. + * + * Note 4 : If input buffer is a ring-buffer, it can have any size, including < 64 KB. + * + * Note 5 : After an error, the stream status is undefined (invalid), it can only be reset or freed. + */ +LZ4LIB_API int LZ4_compress_fast_continue (LZ4_stream_t* streamPtr, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_saveDict() : + * If last 64KB data cannot be guaranteed to remain available at its current memory location, + * save it into a safer place (char* safeBuffer). + * This is schematically equivalent to a memcpy() followed by LZ4_loadDict(), + * but is much faster, because LZ4_saveDict() doesn't need to rebuild tables. + * @return : saved dictionary size in bytes (necessarily <= maxDictSize), or 0 if error. + */ +LZ4LIB_API int LZ4_saveDict (LZ4_stream_t* streamPtr, char* safeBuffer, int maxDictSize); + + +/*-********************************************** +* Streaming Decompression Functions +* Bufferless synchronous API +************************************************/ +typedef union LZ4_streamDecode_u LZ4_streamDecode_t; /* tracking context */ + +/*! LZ4_createStreamDecode() and LZ4_freeStreamDecode() : + * creation / destruction of streaming decompression tracking context. + * A tracking context can be re-used multiple times. + */ +#if !defined(RC_INVOKED) /* https://docs.microsoft.com/en-us/windows/win32/menurc/predefined-macros */ +#if !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) +LZ4LIB_API LZ4_streamDecode_t* LZ4_createStreamDecode(void); +LZ4LIB_API int LZ4_freeStreamDecode (LZ4_streamDecode_t* LZ4_stream); +#endif /* !defined(LZ4_STATIC_LINKING_ONLY_DISABLE_MEMORY_ALLOCATION) */ +#endif + +/*! LZ4_setStreamDecode() : + * An LZ4_streamDecode_t context can be allocated once and re-used multiple times. + * Use this function to start decompression of a new stream of blocks. + * A dictionary can optionally be set. Use NULL or size 0 for a reset order. + * Dictionary is presumed stable : it must remain accessible and unmodified during next decompression. + * @return : 1 if OK, 0 if error + */ +LZ4LIB_API int LZ4_setStreamDecode (LZ4_streamDecode_t* LZ4_streamDecode, const char* dictionary, int dictSize); + +/*! LZ4_decoderRingBufferSize() : v1.8.2+ + * Note : in a ring buffer scenario (optional), + * blocks are presumed decompressed next to each other + * up to the moment there is not enough remaining space for next block (remainingSize < maxBlockSize), + * at which stage it resumes from beginning of ring buffer. + * When setting such a ring buffer for streaming decompression, + * provides the minimum size of this ring buffer + * to be compatible with any source respecting maxBlockSize condition. + * @return : minimum ring buffer size, + * or 0 if there is an error (invalid maxBlockSize). + */ +LZ4LIB_API int LZ4_decoderRingBufferSize(int maxBlockSize); +#define LZ4_DECODER_RING_BUFFER_SIZE(maxBlockSize) (65536 + 14 + (maxBlockSize)) /* for static allocation; maxBlockSize presumed valid */ + +/*! LZ4_decompress_safe_continue() : + * This decoding function allows decompression of consecutive blocks in "streaming" mode. + * The difference with the usual independent blocks is that + * new blocks are allowed to find references into former blocks. + * A block is an unsplittable entity, and must be presented entirely to the decompression function. + * LZ4_decompress_safe_continue() only accepts one block at a time. + * It's modeled after `LZ4_decompress_safe()` and behaves similarly. + * + * @LZ4_streamDecode : decompression state, tracking the position in memory of past data + * @compressedSize : exact complete size of one compressed block. + * @dstCapacity : size of destination buffer (which must be already allocated), + * must be an upper bound of decompressed size. + * @return : number of bytes decompressed into destination buffer (necessarily <= dstCapacity) + * If destination buffer is not large enough, decoding will stop and output an error code (negative value). + * If the source stream is detected malformed, the function will stop decoding and return a negative result. + * + * The last 64KB of previously decoded data *must* remain available and unmodified + * at the memory position where they were previously decoded. + * If less than 64KB of data has been decoded, all the data must be present. + * + * Special : if decompression side sets a ring buffer, it must respect one of the following conditions : + * - Decompression buffer size is _at least_ LZ4_decoderRingBufferSize(maxBlockSize). + * maxBlockSize is the maximum size of any single block. It can have any value > 16 bytes. + * In which case, encoding and decoding buffers do not need to be synchronized. + * Actually, data can be produced by any source compliant with LZ4 format specification, and respecting maxBlockSize. + * - Synchronized mode : + * Decompression buffer size is _exactly_ the same as compression buffer size, + * and follows exactly same update rule (block boundaries at same positions), + * and decoding function is provided with exact decompressed size of each block (exception for last block of the stream), + * _then_ decoding & encoding ring buffer can have any size, including small ones ( < 64 KB). + * - Decompression buffer is larger than encoding buffer, by a minimum of maxBlockSize more bytes. + * In which case, encoding and decoding buffers do not need to be synchronized, + * and encoding ring buffer can have any size, including small ones ( < 64 KB). + * + * Whenever these conditions are not possible, + * save the last 64KB of decoded data into a safe buffer where it can't be modified during decompression, + * then indicate where this data is saved using LZ4_setStreamDecode(), before decompressing next block. */ -int LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int compressedSize, int maxDecompressedSize); -int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* source, char* dest, int originalSize); +LZ4LIB_API int +LZ4_decompress_safe_continue (LZ4_streamDecode_t* LZ4_streamDecode, + const char* src, char* dst, + int srcSize, int dstCapacity); -/* -Advanced decoding functions : -*_usingDict() : - These decoding functions work the same as - a combination of LZ4_setStreamDecode() followed by LZ4_decompress_x_continue() - They are stand-alone. They don't need nor update an LZ4_streamDecode_t structure. -*/ -int LZ4_decompress_safe_usingDict (const char* source, char* dest, int compressedSize, int maxDecompressedSize, const char* dictStart, int dictSize); -int LZ4_decompress_fast_usingDict (const char* source, char* dest, int originalSize, const char* dictStart, int dictSize); +/*! LZ4_decompress_safe_usingDict() : + * Works the same as + * a combination of LZ4_setStreamDecode() followed by LZ4_decompress_safe_continue() + * However, it's stateless: it doesn't need any LZ4_streamDecode_t state. + * Dictionary is presumed stable : it must remain accessible and unmodified during decompression. + * Performance tip : Decompression speed can be substantially increased + * when dst == dictStart + dictSize. + */ +LZ4LIB_API int +LZ4_decompress_safe_usingDict(const char* src, char* dst, + int srcSize, int dstCapacity, + const char* dictStart, int dictSize); + +/*! LZ4_decompress_safe_partial_usingDict() : + * Behaves the same as LZ4_decompress_safe_partial() + * with the added ability to specify a memory segment for past data. + * Performance tip : Decompression speed can be substantially increased + * when dst == dictStart + dictSize. + */ +LZ4LIB_API int +LZ4_decompress_safe_partial_usingDict(const char* src, char* dst, + int compressedSize, + int targetOutputSize, int maxOutputSize, + const char* dictStart, int dictSize); + +#endif /* LZ4_H_2983827168210 */ + + +/*^************************************* + * !!!!!! STATIC LINKING ONLY !!!!!! + ***************************************/ + +/*-**************************************************************************** + * Experimental section + * + * Symbols declared in this section must be considered unstable. Their + * signatures or semantics may change, or they may be removed altogether in the + * future. They are therefore only safe to depend on when the caller is + * statically linked against the library. + * + * To protect against unsafe usage, not only are the declarations guarded, + * the definitions are hidden by default + * when building LZ4 as a shared/dynamic library. + * + * In order to access these declarations, + * define LZ4_STATIC_LINKING_ONLY in your application + * before including LZ4's headers. + * + * In order to make their implementations accessible dynamically, you must + * define LZ4_PUBLISH_STATIC_FUNCTIONS when building the LZ4 library. + ******************************************************************************/ + +#ifdef LZ4_STATIC_LINKING_ONLY + +#ifndef LZ4_STATIC_3504398509 +#define LZ4_STATIC_3504398509 + +#ifdef LZ4_PUBLISH_STATIC_FUNCTIONS +# define LZ4LIB_STATIC_API LZ4LIB_API +#else +# define LZ4LIB_STATIC_API +#endif + + +/*! LZ4_compress_fast_extState_fastReset() : + * A variant of LZ4_compress_fast_extState(). + * + * Using this variant avoids an expensive initialization step. + * It is only safe to call if the state buffer is known to be correctly initialized already + * (see above comment on LZ4_resetStream_fast() for a definition of "correctly initialized"). + * From a high level, the difference is that + * this function initializes the provided state with a call to something like LZ4_resetStream_fast() + * while LZ4_compress_fast_extState() starts with a call to LZ4_resetStream(). + */ +LZ4LIB_STATIC_API int LZ4_compress_fast_extState_fastReset (void* state, const char* src, char* dst, int srcSize, int dstCapacity, int acceleration); + +/*! LZ4_compress_destSize_extState() : + * Same as LZ4_compress_destSize(), but using an externally allocated state. + * Also: exposes @acceleration + */ +int LZ4_compress_destSize_extState(void* state, const char* src, char* dst, int* srcSizePtr, int targetDstSize, int acceleration); + +/*! LZ4_attach_dictionary() : + * This is an experimental API that allows + * efficient use of a static dictionary many times. + * + * Rather than re-loading the dictionary buffer into a working context before + * each compression, or copying a pre-loaded dictionary's LZ4_stream_t into a + * working LZ4_stream_t, this function introduces a no-copy setup mechanism, + * in which the working stream references the dictionary stream in-place. + * + * Several assumptions are made about the state of the dictionary stream. + * Currently, only streams which have been prepared by LZ4_loadDict() should + * be expected to work. + * + * Alternatively, the provided dictionaryStream may be NULL, + * in which case any existing dictionary stream is unset. + * + * If a dictionary is provided, it replaces any pre-existing stream history. + * The dictionary contents are the only history that can be referenced and + * logically immediately precede the data compressed in the first subsequent + * compression call. + * + * The dictionary will only remain attached to the working stream through the + * first compression call, at the end of which it is cleared. The dictionary + * stream (and source buffer) must remain in-place / accessible / unchanged + * through the completion of the first compression call on the stream. + */ +LZ4LIB_STATIC_API void +LZ4_attach_dictionary(LZ4_stream_t* workingStream, + const LZ4_stream_t* dictionaryStream); + + +/*! In-place compression and decompression + * + * It's possible to have input and output sharing the same buffer, + * for highly constrained memory environments. + * In both cases, it requires input to lay at the end of the buffer, + * and decompression to start at beginning of the buffer. + * Buffer size must feature some margin, hence be larger than final size. + * + * |<------------------------buffer--------------------------------->| + * |<-----------compressed data--------->| + * |<-----------decompressed size------------------>| + * |<----margin---->| + * + * This technique is more useful for decompression, + * since decompressed size is typically larger, + * and margin is short. + * + * In-place decompression will work inside any buffer + * which size is >= LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize). + * This presumes that decompressedSize > compressedSize. + * Otherwise, it means compression actually expanded data, + * and it would be more efficient to store such data with a flag indicating it's not compressed. + * This can happen when data is not compressible (already compressed, or encrypted). + * + * For in-place compression, margin is larger, as it must be able to cope with both + * history preservation, requiring input data to remain unmodified up to LZ4_DISTANCE_MAX, + * and data expansion, which can happen when input is not compressible. + * As a consequence, buffer size requirements are much higher, + * and memory savings offered by in-place compression are more limited. + * + * There are ways to limit this cost for compression : + * - Reduce history size, by modifying LZ4_DISTANCE_MAX. + * Note that it is a compile-time constant, so all compressions will apply this limit. + * Lower values will reduce compression ratio, except when input_size < LZ4_DISTANCE_MAX, + * so it's a reasonable trick when inputs are known to be small. + * - Require the compressor to deliver a "maximum compressed size". + * This is the `dstCapacity` parameter in `LZ4_compress*()`. + * When this size is < LZ4_COMPRESSBOUND(inputSize), then compression can fail, + * in which case, the return code will be 0 (zero). + * The caller must be ready for these cases to happen, + * and typically design a backup scheme to send data uncompressed. + * The combination of both techniques can significantly reduce + * the amount of margin required for in-place compression. + * + * In-place compression can work in any buffer + * which size is >= (maxCompressedSize) + * with maxCompressedSize == LZ4_COMPRESSBOUND(srcSize) for guaranteed compression success. + * LZ4_COMPRESS_INPLACE_BUFFER_SIZE() depends on both maxCompressedSize and LZ4_DISTANCE_MAX, + * so it's possible to reduce memory requirements by playing with them. + */ + +#define LZ4_DECOMPRESS_INPLACE_MARGIN(compressedSize) (((compressedSize) >> 8) + 32) +#define LZ4_DECOMPRESS_INPLACE_BUFFER_SIZE(decompressedSize) ((decompressedSize) + LZ4_DECOMPRESS_INPLACE_MARGIN(decompressedSize)) /**< note: presumes that compressedSize < decompressedSize. note2: margin is overestimated a bit, since it could use compressedSize instead */ + +#ifndef LZ4_DISTANCE_MAX /* history window size; can be user-defined at compile time */ +# define LZ4_DISTANCE_MAX 65535 /* set to maximum value by default */ +#endif + +#define LZ4_COMPRESS_INPLACE_MARGIN (LZ4_DISTANCE_MAX + 32) /* LZ4_DISTANCE_MAX can be safely replaced by srcSize when it's smaller */ +#define LZ4_COMPRESS_INPLACE_BUFFER_SIZE(maxCompressedSize) ((maxCompressedSize) + LZ4_COMPRESS_INPLACE_MARGIN) /**< maxCompressedSize is generally LZ4_COMPRESSBOUND(inputSize), but can be set to any lower value, with the risk that compression can fail (return code 0(zero)) */ + +#endif /* LZ4_STATIC_3504398509 */ +#endif /* LZ4_STATIC_LINKING_ONLY */ -/************************************** +#ifndef LZ4_H_98237428734687 +#define LZ4_H_98237428734687 + +/*-************************************************************ + * Private Definitions + ************************************************************** + * Do not use these definitions directly. + * They are only exposed to allow static allocation of `LZ4_stream_t` and `LZ4_streamDecode_t`. + * Accessing members will expose user code to API and/or ABI break in future versions of the library. + **************************************************************/ +#define LZ4_HASHLOG (LZ4_MEMORY_USAGE-2) +#define LZ4_HASHTABLESIZE (1 << LZ4_MEMORY_USAGE) +#define LZ4_HASH_SIZE_U32 (1 << LZ4_HASHLOG) /* required as macro for static allocation */ + +#if defined(__cplusplus) || (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 199901L) /* C99 */) +# include + typedef int8_t LZ4_i8; + typedef uint8_t LZ4_byte; + typedef uint16_t LZ4_u16; + typedef uint32_t LZ4_u32; +#else + typedef signed char LZ4_i8; + typedef unsigned char LZ4_byte; + typedef unsigned short LZ4_u16; + typedef unsigned int LZ4_u32; +#endif + +/*! LZ4_stream_t : + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_stream_t object. +**/ + +typedef struct LZ4_stream_t_internal LZ4_stream_t_internal; +struct LZ4_stream_t_internal { + LZ4_u32 hashTable[LZ4_HASH_SIZE_U32]; + const LZ4_byte* dictionary; + const LZ4_stream_t_internal* dictCtx; + LZ4_u32 currentOffset; + LZ4_u32 tableType; + LZ4_u32 dictSize; + /* Implicit padding to ensure structure is aligned */ +}; + +#define LZ4_STREAM_MINSIZE ((1UL << (LZ4_MEMORY_USAGE)) + 32) /* static size, for inter-version compatibility */ +union LZ4_stream_u { + char minStateSize[LZ4_STREAM_MINSIZE]; + LZ4_stream_t_internal internal_donotuse; +}; /* previously typedef'd to LZ4_stream_t */ + + +/*! LZ4_initStream() : v1.9.0+ + * An LZ4_stream_t structure must be initialized at least once. + * This is automatically done when invoking LZ4_createStream(), + * but it's not when the structure is simply declared on stack (for example). + * + * Use LZ4_initStream() to properly initialize a newly declared LZ4_stream_t. + * It can also initialize any arbitrary buffer of sufficient size, + * and will @return a pointer of proper type upon initialization. + * + * Note : initialization fails if size and alignment conditions are not respected. + * In which case, the function will @return NULL. + * Note2: An LZ4_stream_t structure guarantees correct alignment and size. + * Note3: Before v1.9.0, use LZ4_resetStream() instead +**/ +LZ4LIB_API LZ4_stream_t* LZ4_initStream (void* stateBuffer, size_t size); + + +/*! LZ4_streamDecode_t : + * Never ever use below internal definitions directly ! + * These definitions are not API/ABI safe, and may change in future versions. + * If you need static allocation, declare or allocate an LZ4_streamDecode_t object. +**/ +typedef struct { + const LZ4_byte* externalDict; + const LZ4_byte* prefixEnd; + size_t extDictSize; + size_t prefixSize; +} LZ4_streamDecode_t_internal; + +#define LZ4_STREAMDECODE_MINSIZE 32 +union LZ4_streamDecode_u { + char minStateSize[LZ4_STREAMDECODE_MINSIZE]; + LZ4_streamDecode_t_internal internal_donotuse; +} ; /* previously typedef'd to LZ4_streamDecode_t */ + + + +/*-************************************ * Obsolete Functions **************************************/ -/* Deprecate Warnings */ -/* Should these warnings messages be a problem, - it is generally possible to disable them, - with -Wno-deprecated-declarations for gcc - or _CRT_SECURE_NO_WARNINGS in Visual for example. - You can also define LZ4_DEPRECATE_WARNING_DEFBLOCK. */ -#ifndef LZ4_DEPRECATE_WARNING_DEFBLOCK -# define LZ4_DEPRECATE_WARNING_DEFBLOCK -# define LZ4_GCC_VERSION (__GNUC__ * 100 + __GNUC_MINOR__) -# if (LZ4_GCC_VERSION >= 405) || defined(__clang__) -# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) -# elif (LZ4_GCC_VERSION >= 301) -# define LZ4_DEPRECATED(message) __attribute__((deprecated)) + +/*! Deprecation warnings + * + * Deprecated functions make the compiler generate a warning when invoked. + * This is meant to invite users to update their source code. + * Should deprecation warnings be a problem, it is generally possible to disable them, + * typically with -Wno-deprecated-declarations for gcc + * or _CRT_SECURE_NO_WARNINGS in Visual. + * + * Another method is to define LZ4_DISABLE_DEPRECATE_WARNINGS + * before including the header file. + */ +#ifdef LZ4_DISABLE_DEPRECATE_WARNINGS +# define LZ4_DEPRECATED(message) /* disable deprecation warnings */ +#else +# if defined (__cplusplus) && (__cplusplus >= 201402) /* C++14 or greater */ +# define LZ4_DEPRECATED(message) [[deprecated(message)]] # elif defined(_MSC_VER) # define LZ4_DEPRECATED(message) __declspec(deprecated(message)) +# elif defined(__clang__) || (defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 45)) +# define LZ4_DEPRECATED(message) __attribute__((deprecated(message))) +# elif defined(__GNUC__) && (__GNUC__ * 10 + __GNUC_MINOR__ >= 31) +# define LZ4_DEPRECATED(message) __attribute__((deprecated)) # else -# pragma message("WARNING: You need to implement LZ4_DEPRECATED for this compiler") -# define LZ4_DEPRECATED(message) +# pragma message("WARNING: LZ4_DEPRECATED needs custom implementation for this compiler") +# define LZ4_DEPRECATED(message) /* disabled */ # endif -#endif /* LZ4_DEPRECATE_WARNING_DEFBLOCK */ +#endif /* LZ4_DISABLE_DEPRECATE_WARNINGS */ -/* Obsolete compression functions */ -/* These functions are planned to start generate warnings by r131 approximately */ -int LZ4_compress (const char* source, char* dest, int sourceSize); -int LZ4_compress_limitedOutput (const char* source, char* dest, int sourceSize, int maxOutputSize); -int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); -int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); -int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); -int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); +/*! Obsolete compression functions (since v1.7.3) */ +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress (const char* src, char* dest, int srcSize); +LZ4_DEPRECATED("use LZ4_compress_default() instead") LZ4LIB_API int LZ4_compress_limitedOutput (const char* src, char* dest, int srcSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_withState (void* state, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_extState() instead") LZ4LIB_API int LZ4_compress_limitedOutput_withState (void* state, const char* source, char* dest, int inputSize, int maxOutputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize); +LZ4_DEPRECATED("use LZ4_compress_fast_continue() instead") LZ4LIB_API int LZ4_compress_limitedOutput_continue (LZ4_stream_t* LZ4_streamPtr, const char* source, char* dest, int inputSize, int maxOutputSize); -/* Obsolete decompression functions */ -/* These function names are completely deprecated and must no longer be used. - They are only provided here for compatibility with older programs. - - LZ4_uncompress is the same as LZ4_decompress_fast - - LZ4_uncompress_unknownOutputSize is the same as LZ4_decompress_safe - These function prototypes are now disabled; uncomment them only if you really need them. - It is highly recommended to stop using these prototypes and migrate to maintained ones */ -/* int LZ4_uncompress (const char* source, char* dest, int outputSize); */ -/* int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); */ +/*! Obsolete decompression functions (since v1.8.0) */ +LZ4_DEPRECATED("use LZ4_decompress_fast() instead") LZ4LIB_API int LZ4_uncompress (const char* source, char* dest, int outputSize); +LZ4_DEPRECATED("use LZ4_decompress_safe() instead") LZ4LIB_API int LZ4_uncompress_unknownOutputSize (const char* source, char* dest, int isize, int maxOutputSize); -/* Obsolete streaming functions; use new streaming interface whenever possible */ -LZ4_DEPRECATED("use LZ4_createStream() instead") void* LZ4_create (char* inputBuffer); -LZ4_DEPRECATED("use LZ4_createStream() instead") int LZ4_sizeofStreamState(void); -LZ4_DEPRECATED("use LZ4_resetStream() instead") int LZ4_resetStreamState(void* state, char* inputBuffer); -LZ4_DEPRECATED("use LZ4_saveDict() instead") char* LZ4_slideInputBuffer (void* state); +/* Obsolete streaming functions (since v1.7.0) + * degraded functionality; do not use! + * + * In order to perform streaming compression, these functions depended on data + * that is no longer tracked in the state. They have been preserved as well as + * possible: using them will still produce a correct output. However, they don't + * actually retain any history between compression calls. The compression ratio + * achieved will therefore be no better than compressing each chunk + * independently. + */ +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API void* LZ4_create (char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_createStream() instead") LZ4LIB_API int LZ4_sizeofStreamState(void); +LZ4_DEPRECATED("Use LZ4_resetStream() instead") LZ4LIB_API int LZ4_resetStreamState(void* state, char* inputBuffer); +LZ4_DEPRECATED("Use LZ4_saveDict() instead") LZ4LIB_API char* LZ4_slideInputBuffer (void* state); -/* Obsolete streaming decoding functions */ -LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); -LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); +/*! Obsolete streaming decoding functions (since v1.7.0) */ +LZ4_DEPRECATED("use LZ4_decompress_safe_usingDict() instead") LZ4LIB_API int LZ4_decompress_safe_withPrefix64k (const char* src, char* dst, int compressedSize, int maxDstSize); +LZ4_DEPRECATED("use LZ4_decompress_fast_usingDict() instead") LZ4LIB_API int LZ4_decompress_fast_withPrefix64k (const char* src, char* dst, int originalSize); + +/*! Obsolete LZ4_decompress_fast variants (since v1.9.0) : + * These functions used to be faster than LZ4_decompress_safe(), + * but this is no longer the case. They are now slower. + * This is because LZ4_decompress_fast() doesn't know the input size, + * and therefore must progress more cautiously into the input buffer to not read beyond the end of block. + * On top of that `LZ4_decompress_fast()` is not protected vs malformed or malicious inputs, making it a security liability. + * As a consequence, LZ4_decompress_fast() is strongly discouraged, and deprecated. + * + * The last remaining LZ4_decompress_fast() specificity is that + * it can decompress a block without knowing its compressed size. + * Such functionality can be achieved in a more secure manner + * by employing LZ4_decompress_safe_partial(). + * + * Parameters: + * originalSize : is the uncompressed size to regenerate. + * `dst` must be already allocated, its size must be >= 'originalSize' bytes. + * @return : number of bytes read from source buffer (== compressed size). + * The function expects to finish at block's end exactly. + * If the source stream is detected malformed, the function stops decoding and returns a negative result. + * note : LZ4_decompress_fast*() requires originalSize. Thanks to this information, it never writes past the output buffer. + * However, since it doesn't know its 'src' size, it may read an unknown amount of input, past input buffer bounds. + * Also, since match offsets are not validated, match reads from 'src' may underflow too. + * These issues never happen if input (compressed) data is correct. + * But they may happen if input data is invalid (error or intentional tampering). + * As a consequence, use these functions in trusted environments with trusted data **only**. + */ +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_partial() instead") +LZ4LIB_API int LZ4_decompress_fast (const char* src, char* dst, int originalSize); +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider migrating towards LZ4_decompress_safe_continue() instead. " + "Note that the contract will change (requires block's compressed size, instead of decompressed size)") +LZ4LIB_API int LZ4_decompress_fast_continue (LZ4_streamDecode_t* LZ4_streamDecode, const char* src, char* dst, int originalSize); +LZ4_DEPRECATED("This function is deprecated and unsafe. Consider using LZ4_decompress_safe_partial_usingDict() instead") +LZ4LIB_API int LZ4_decompress_fast_usingDict (const char* src, char* dst, int originalSize, const char* dictStart, int dictSize); + +/*! LZ4_resetStream() : + * An LZ4_stream_t structure must be initialized at least once. + * This is done with LZ4_initStream(), or LZ4_resetStream(). + * Consider switching to LZ4_initStream(), + * invoking LZ4_resetStream() will trigger deprecation warnings in the future. + */ +LZ4LIB_API void LZ4_resetStream (LZ4_stream_t* streamPtr); + + +#endif /* LZ4_H_98237428734687 */ #if defined (__cplusplus) diff --git a/include/verilated_fst_c.cpp b/include/verilated_fst_c.cpp index ffc78ec99..05422641f 100644 --- a/include/verilated_fst_c.cpp +++ b/include/verilated_fst_c.cpp @@ -29,6 +29,7 @@ // GTKWave configuration #define HAVE_LIBPTHREAD #define FST_WRITER_PARALLEL +#define LZ4_DISABLE_DEPRECATE_WARNINGS // Include the GTKWave implementation directly #define FST_CONFIG_INCLUDE "fst_config.h" From 2989e54eaa6dba94818be0561f1f131982b6ebf5 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Sun, 21 Jan 2024 16:18:48 -0500 Subject: [PATCH 050/116] Add unsupported warning on property iff (#4848) --- src/verilog.y | 10 +++++++++- test_regress/t/t_assert_iff_clk_unsup.out | 6 ++++++ test_regress/t/t_assert_iff_clk_unsup.pl | 20 ++++++++++++++++++++ test_regress/t/t_assert_iff_clk_unsup.v | 22 ++++++++++++++++++++++ 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 test_regress/t/t_assert_iff_clk_unsup.out create mode 100755 test_regress/t/t_assert_iff_clk_unsup.pl create mode 100644 test_regress/t/t_assert_iff_clk_unsup.v diff --git a/src/verilog.y b/src/verilog.y index ad0b9bc61..364288d6e 100644 --- a/src/verilog.y +++ b/src/verilog.y @@ -3360,7 +3360,8 @@ senitem: // IEEE: part of event_expression, non-'OR' ',' ; senitemVar: - idClassSel { $$ = new AstSenItem{$1->fileline(), VEdgeType::ET_CHANGED, $1}; } + idClassSel + { $$ = new AstSenItem{$1->fileline(), VEdgeType::ET_CHANGED, $1}; } ; senitemEdge: // IEEE: part of event_expression @@ -6064,6 +6065,13 @@ property_spec: // IEEE: property_spec '@' '(' senitemEdge ')' yDISABLE yIFF '(' expr ')' pexpr { $$ = new AstPropSpec{$1, $3, $8, $10}; } | '@' '(' senitemEdge ')' pexpr { $$ = new AstPropSpec{$1, $3, nullptr, $5}; } + // // Disable applied after the event occurs, + // // so no existing AST can represent this + | yDISABLE yIFF '(' expr ')' '@' '(' senitemEdge ')' pexpr + { $$ = new AstPropSpec{$1, $8, nullptr, new AstLogOr{$1, $4, $10}}; + BBUNSUP($1, "Unsupported: property '(disable iff (...) @ (...)'\n" + + $1->warnMore() + + "... Suggest use property '(@(...) disable iff (...))'"); } //UNSUP remove above | yDISABLE yIFF '(' expr ')' pexpr { $$ = new AstPropSpec{$4->fileline(), nullptr, $4, $6}; } | pexpr { $$ = new AstPropSpec{$1->fileline(), nullptr, nullptr, $1}; } diff --git a/test_regress/t/t_assert_iff_clk_unsup.out b/test_regress/t/t_assert_iff_clk_unsup.out new file mode 100644 index 000000000..2a75cd94e --- /dev/null +++ b/test_regress/t/t_assert_iff_clk_unsup.out @@ -0,0 +1,6 @@ +%Error-UNSUPPORTED: t/t_assert_iff_clk_unsup.v:20:21: Unsupported: property '(disable iff (...) @ (...)' + : ... Suggest use property '(@(...) disable iff (...))' + 20 | assert property (disable iff (cyc < 5) @(posedge clk) cyc >= 5); + | ^~~~~~~ + ... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest +%Error: Exiting due to diff --git a/test_regress/t/t_assert_iff_clk_unsup.pl b/test_regress/t/t_assert_iff_clk_unsup.pl new file mode 100755 index 000000000..1e3627720 --- /dev/null +++ b/test_regress/t/t_assert_iff_clk_unsup.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 2022 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + expect_filename => $Self->{golden_filename}, + verilator_flags2 => ['--assert'], + fails => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_assert_iff_clk_unsup.v b/test_regress/t/t_assert_iff_clk_unsup.v new file mode 100644 index 000000000..d1d3bd072 --- /dev/null +++ b/test_regress/t/t_assert_iff_clk_unsup.v @@ -0,0 +1,22 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2022 by Antmicro Ltd. +// SPDX-License-Identifier: CC0-1.0 + +module t (/*AUTOARG*/ + clk + ); + + input clk; + int cyc = 0; + logic val = 0; + + always @(posedge clk) begin + cyc <= cyc + 1; + val = ~val; + end + + assert property (disable iff (cyc < 5) @(posedge clk) cyc >= 5); + +endmodule From f0d010d9c5a79bc39ee2544752e23ccbceb38227 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Mon, 22 Jan 2024 23:32:00 -0400 Subject: [PATCH 051/116] Github: Update actions (#4852) --- .github/workflows/build.yml | 8 ++++---- .github/workflows/contributor.yml | 2 +- .github/workflows/coverage.yml | 2 +- .github/workflows/docker.yml | 2 +- .github/workflows/format.yml | 2 +- .github/workflows/msbuild.yml | 4 ++-- 6 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 653197c85..0d0bc997b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -54,12 +54,12 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo - name: Cache $CCACHE_DIR - uses: actions/cache@v3 + uses: actions/cache@v4 env: CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache with: @@ -125,7 +125,7 @@ jobs: run: tar -x -z -f ${{ env.VERILATOR_ARCHIVE }} - name: Cache $CCACHE_DIR - uses: actions/cache@v3 + uses: actions/cache@v4 env: CACHE_KEY: ${{ env.CACHE_BASE_KEY }}-ccache with: @@ -150,7 +150,7 @@ jobs: CI_RUNS_ON: ubuntu-22.04 steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo diff --git a/.github/workflows/contributor.yml b/.github/workflows/contributor.yml index e40acd32d..7904a333b 100644 --- a/.github/workflows/contributor.yml +++ b/.github/workflows/contributor.yml @@ -13,5 +13,5 @@ jobs: name: "'docs/CONTRIBUTORS' was signed" runs-on: ubuntu-22.04 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - run: test_regress/t/t_dist_contributors.pl diff --git a/.github/workflows/coverage.yml b/.github/workflows/coverage.yml index 8bba01198..c5135a802 100644 --- a/.github/workflows/coverage.yml +++ b/.github/workflows/coverage.yml @@ -30,7 +30,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: path: repo diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 759421e35..7a55fa921 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -35,7 +35,7 @@ jobs: steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Extract context variables run: | diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml index df69546d4..6a498715d 100644 --- a/.github/workflows/format.yml +++ b/.github/workflows/format.yml @@ -18,7 +18,7 @@ jobs: CI_COMMIT: ${{ github.sha }} steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: token: ${{ secrets.GITHUB_TOKEN }} - name: Install packages for build diff --git a/.github/workflows/msbuild.yml b/.github/workflows/msbuild.yml index fe148ad6e..adc8fd082 100644 --- a/.github/workflows/msbuild.yml +++ b/.github/workflows/msbuild.yml @@ -32,11 +32,11 @@ jobs: name: run on windows runs-on: windows-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 with: path: repo - name: Cache $CCACHE_DIR - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ${{ env.CCACHE_DIR }} key: msbuild-msvc-cmake From 6c0c88cfc4bed2250bcee5d3bccdee4023fd8e0c Mon Sep 17 00:00:00 2001 From: Paul Swirhun <63216497+paul-demo@users.noreply.github.com> Date: Tue, 23 Jan 2024 10:05:27 -0800 Subject: [PATCH 052/116] Fix unsafe write in wide array insertion (#4850) (#4855) --- docs/CONTRIBUTORS | 1 + include/verilated_funcs.h | 10 ++- test_regress/t/t_math_insert_bound.pl | 21 ++++++ test_regress/t/t_math_insert_bound.v | 100 ++++++++++++++++++++++++++ 4 files changed, 129 insertions(+), 3 deletions(-) create mode 100755 test_regress/t/t_math_insert_bound.pl create mode 100644 test_regress/t/t_math_insert_bound.v diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 3ca519cd0..271c3898c 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -134,6 +134,7 @@ Nathan Kohagen Nathan Myers Oleh Maksymenko Patrick Stewart +Paul Swirhun Paul Wright Pawel Sagan Pengcheng Xu diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index 39d97f83d..fbb5aef37 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1266,6 +1266,7 @@ static inline void _vl_insert_QQ(QData& lhsr, QData ld, int hbit, int lbit, int } static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit, int rbits = 0) VL_MT_SAFE { + // Insert value ld into iowp at bit slice [hbit:lbit]. iowp is rbits wide. const int hoffset = VL_BITBIT_E(hbit); const int loffset = VL_BITBIT_E(lbit); const int roffset = VL_BITBIT_E(rbits); @@ -1276,7 +1277,7 @@ static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit, if (hoffset == VL_SIZEBITS_E && loffset == 0) { // Fast and common case, word based insertion - iowp[VL_BITWORD_E(lbit)] = ld & cleanmask; + iowp[lword] = ld & cleanmask; } else { const EData lde = static_cast(ld); if (hword == lword) { // know < EData bits because above checks it @@ -1289,8 +1290,11 @@ static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit, const EData linsmask = (VL_MASK_E((VL_EDATASIZE - 1) - loffset + 1)) << loffset; const int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword iowp[lword] = (iowp[lword] & ~linsmask) | ((lde << loffset) & linsmask); - iowp[hword] - = (iowp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask)); + // Prevent unsafe write where lword was final writable location and hword is out-of-bounds. + if (VL_LIKELY(!(hword == rword && roffset == 0))) { + iowp[hword] + = (iowp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask)); + } } } } diff --git a/test_regress/t/t_math_insert_bound.pl b/test_regress/t/t_math_insert_bound.pl new file mode 100755 index 000000000..e64ab41be --- /dev/null +++ b/test_regress/t/t_math_insert_bound.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 2024 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_math_insert_bound.v b/test_regress/t/t_math_insert_bound.v new file mode 100644 index 000000000..5ddb940d4 --- /dev/null +++ b/test_regress/t/t_math_insert_bound.v @@ -0,0 +1,100 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Paul Swirhun. +// SPDX-License-Identifier: CC0-1.0 + +// Demonstrates the bug in https://github.com/verilator/verilator/issues/4850 +// +// Specifically, _vl_insert_WI() writes to lword and hword when lword != hword +// may be unsafe, because (for example), lword was the highest valid place to +// perform a write and hword is out-of-bounds (and will in fact clobber other +// state in the generated C++ struct!). + + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + integer cyc = 13; + + // These need to be generated/consumed in this testbench so that + // they do not get pruned away when verilated + logic insert = '0; + logic [3:0] used, free; + logic [95:0] data; + + always_ff @(posedge clk) begin + insert <= '1; + cyc <= cyc - 1; + +`ifdef TEST_VERBOSE + $write("used [4'd%2d], free [4'd%2d], data = [96'h%012x]\n", used, free, data); +`endif + + if (used + free != 12) begin + $write("used [4'd%2d] + free [4'd%2d] != 4'd12\n", used, free); + $stop(); + end + if (used == 0) begin + $write("used [4'd%2d] was clobbered (should always be nonzero).\n", used); + $stop(); + end + if (cyc == 0) begin + if (used == 12 && free == 0 && data == 96'hFF) begin + $write("*-* All Finished *-*\n"); + $finish; + end else begin + $write("Test Failed! used/free/data had unexpected final value(s).\n"); + $stop(); + end + end + end + + dut dut_i( + .clk(clk), + .insert(insert), + .used(used), + .free(free), + .data(data) + ); + +endmodule + +module dut( + input logic clk, + input logic insert, + output logic [3:0] used, + output logic [3:0] free, + output logic [95:0] data + ); + + // This declaration order matters -- the fact that d_data is *before* d_used/d_free + // means that with the existing bug, writes to d_data that extend beyond its length + // will overwrite other fields in the state struct -- basically an "unsafe writes" + // problem because the existing code wrote beyond the end of the array d_data. + logic [11:0][7:0] d_data = '1, d_data_next; + logic [3:0] d_used = 4'd1, d_free = 4'd11, d_used_next; + assign used = d_used; + assign free = d_free; + assign data = d_data; + + always_ff @(posedge clk) begin + d_data <= d_data_next; + d_used <= d_used_next; + d_free <= 12 - d_used_next; + end + + always_comb begin + d_data_next = d_data; + d_used_next = d_used; + + if ((insert == 1'b1) && (d_free >= {3'b0, insert})) begin + // This write to d_data would clobber d_used before the issue was fixed + d_data_next[d_used+:4] = 32'd0; + d_used_next += 4'd1; + end + end +endmodule From 0b8daf4ae42b5ea9e4185d818475e6b9d23d2fc7 Mon Sep 17 00:00:00 2001 From: github action Date: Tue, 23 Jan 2024 18:06:10 +0000 Subject: [PATCH 053/116] Apply 'make format' --- include/verilated_funcs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/include/verilated_funcs.h b/include/verilated_funcs.h index fbb5aef37..0e4207e3f 100644 --- a/include/verilated_funcs.h +++ b/include/verilated_funcs.h @@ -1290,7 +1290,8 @@ static inline void _vl_insert_WI(WDataOutP iowp, IData ld, int hbit, int lbit, const EData linsmask = (VL_MASK_E((VL_EDATASIZE - 1) - loffset + 1)) << loffset; const int nbitsonright = VL_EDATASIZE - loffset; // bits that end up in lword iowp[lword] = (iowp[lword] & ~linsmask) | ((lde << loffset) & linsmask); - // Prevent unsafe write where lword was final writable location and hword is out-of-bounds. + // Prevent unsafe write where lword was final writable location and hword is + // out-of-bounds. if (VL_LIKELY(!(hword == rword && roffset == 0))) { iowp[hword] = (iowp[hword] & ~hinsmask) | ((lde >> nbitsonright) & (hinsmask & cleanmask)); From 21e85f87bc9e0426ec9dcb1622644ec523d51868 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 Jan 2024 19:36:11 -0500 Subject: [PATCH 054/116] Fix compilation error on multi-inherited interface class usage (#4819). --- Changes | 1 + src/V3AstNodeOther.h | 15 +++++------ src/V3AstNodes.cpp | 1 + src/V3Class.cpp | 27 +++++++++++++++++++ src/V3EmitCFunc.h | 43 ++++++++++++++++++++++--------- src/V3EmitCHeaders.cpp | 9 +++++-- src/V3Task.cpp | 8 +----- test_regress/t/t_class_imp2.pl | 21 +++++++++++++++ test_regress/t/t_class_imp2.v | 47 ++++++++++++++++++++++++++++++++++ 9 files changed, 143 insertions(+), 29 deletions(-) create mode 100755 test_regress/t/t_class_imp2.pl create mode 100644 test_regress/t/t_class_imp2.v diff --git a/Changes b/Changes index 26be978b1..5dd935a56 100644 --- a/Changes +++ b/Changes @@ -29,6 +29,7 @@ Verilator 5.021 devel * Fix delays using wrong timeunit when modules inlined (#4806). [Paul Wright] * Fix warnings in verilated_sc_trace.h for Clang. (#4807) (#4827). [Anthony Donlon] * Fix null pointer dereference (#4810) (#4825). [Adrian Sampson] +* Fix compilation error on multi-inherited interface class usage (#4819). * Fix maybe-uninitialized compiler warning (#4820) (#4822). [Larry Doolittle] * Fix mis-splitting of dump control functions (#4821). [Fan Shupei] * Fix wrong utimes() parameter (#4829). [Szymon Gizler] diff --git a/src/V3AstNodeOther.h b/src/V3AstNodeOther.h index 2ca075540..cdb1e39b9 100644 --- a/src/V3AstNodeOther.h +++ b/src/V3AstNodeOther.h @@ -593,7 +593,6 @@ class AstCFunc final : public AstNode { string m_cname; // C name, for dpiExports string m_rtnType; // void, bool, or other return type string m_argTypes; // Argument types - string m_baseCtors; // Base class constructor string m_ifdef; // #ifdef symbol around this function VBoolOrUnknown m_isConst; // Function is declared const (*this not changed) bool m_isStatic : 1; // Function is static (no need for a 'this' pointer) @@ -656,8 +655,7 @@ public: bool same(const AstNode* samep) const override { const AstCFunc* const asamep = VN_DBG_AS(samep, CFunc); return ((isTrace() == asamep->isTrace()) && (rtnTypeVoid() == asamep->rtnTypeVoid()) - && (argTypes() == asamep->argTypes()) && (baseCtors() == asamep->baseCtors()) - && isLoose() == asamep->isLoose() + && (argTypes() == asamep->argTypes()) && isLoose() == asamep->isLoose() && (!(dpiImportPrototype() || dpiExportImpl()) || name() == asamep->name())); } // @@ -689,8 +687,6 @@ public: void funcPublic(bool flag) { m_funcPublic = flag; } void argTypes(const string& str) { m_argTypes = str; } string argTypes() const { return m_argTypes; } - void baseCtors(const string& str) { m_baseCtors = str; } - string baseCtors() const { return m_baseCtors; } void ifdef(const string& str) { m_ifdef = str; } string ifdef() const { return m_ifdef; } bool isConstructor() const { return m_isConstructor; } @@ -2255,8 +2251,9 @@ class AstClass final : public AstNodeModule { bool m_extended = false; // Is extension or extended by other classes bool m_interfaceClass = false; // Interface class bool m_needRNG = false; // Need RNG, uses srandom/randomize - bool m_virtual = false; // Virtual class bool m_parameterized = false; // Parameterized class + bool m_useVirtualPublic = false; // Subclasses need virtual public as uses interface class + bool m_virtual = false; // Virtual class public: AstClass(FileLine* fl, const string& name) @@ -2274,12 +2271,14 @@ public: void isExtended(bool flag) { m_extended = flag; } bool isInterfaceClass() const { return m_interfaceClass; } void isInterfaceClass(bool flag) { m_interfaceClass = flag; } + bool isParameterized() const { return m_parameterized; } + void isParameterized(bool flag) { m_parameterized = flag; } bool isVirtual() const { return m_virtual; } void isVirtual(bool flag) { m_virtual = flag; } bool needRNG() const { return m_needRNG; } void needRNG(bool flag) { m_needRNG = flag; } - bool isParameterized() const { return m_parameterized; } - void isParameterized(bool flag) { m_parameterized = flag; } + bool useVirtualPublic() const { return m_useVirtualPublic; } + void useVirtualPublic(bool flag) { m_useVirtualPublic = flag; } // Return true if this class is an extension of base class (SLOW) // Accepts nullptrs static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index 77e812c64..7b00c3bb1 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -1406,6 +1406,7 @@ void AstClass::dump(std::ostream& str) const { if (isExtended()) str << " [EXT]"; if (isInterfaceClass()) str << " [IFCCLS]"; if (isVirtual()) str << " [VIRT]"; + if (useVirtualPublic()) str << " [VIRPUB]"; } void AstClassExtends::dump(std::ostream& str) const { this->AstNode::dump(str); diff --git a/src/V3Class.cpp b/src/V3Class.cpp index 54ac0677b..c7f167ed8 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -49,12 +49,39 @@ class ClassVisitor final : public VNVisitor { // METHODS + bool recurseImplements(AstClass* nodep, bool setit) { + // Returns true to set useVirtualPublic(). + // If there's an implements of an interface class then we have + // multiple classes that point to same object, that need same + // VlClass (the diamond problem). C++ will require we use 'virtual + // public' for VlClass. So, we need the interface class, and all + // classes above, and any below using any implements to use + // 'virtual public' via useVirtualPublic(). + if (nodep->useVirtualPublic()) return true; // Short-circuit + if (nodep->isInterfaceClass()) setit = true; + for (const AstClassExtends* extp = nodep->extendsp(); extp; + extp = VN_AS(extp->nextp(), ClassExtends)) { + if (recurseImplements(extp->classp(), setit)) setit = true; + } + if (setit) { + nodep->useVirtualPublic(true); + for (const AstClassExtends* extp = nodep->extendsp(); extp; + extp = VN_AS(extp->nextp(), ClassExtends)) { + (void)recurseImplements(extp->classp(), true); + } + } + return setit; + } + + // VISITORS + void visit(AstClass* nodep) override { if (nodep->user1SetOnce()) return; // Move this class nodep->name(m_prefix + nodep->name()); nodep->unlinkFrBack(); v3Global.rootp()->addModulesp(nodep); + (void)recurseImplements(nodep, false); // Make containing package // Note origName is the same as the class origName so errors look correct AstClassPackage* const packagep diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index 7c85832c7..b68dc0c83 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -248,6 +248,32 @@ public: return nullptr; } + void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, bool& firstr) { + for (const AstClassExtends* extp = classp->extendsp(); extp; + extp = VN_AS(extp->nextp(), ClassExtends)) { + if (extp->classp()->useVirtualPublic()) { + // It's a c++ virtual class (diamond relation) + // Must get the subclasses initialized first + putConstructorSubinit(extp->classp(), cfuncp, false, firstr); + } + puts(firstr ? "" : "\n, "); + firstr = false; + puts(prefixNameProtect(extp->classp())); + if (constructorNeedsProcess(extp->classp())) { + puts("(vlProcess, vlSymsp"); + } else { + puts("(vlSymsp"); + } + if (top) { + const AstCNew* const superNewCallp = getSuperNewCallRecursep(cfuncp->stmtsp()); + UASSERT_OBJ(superNewCallp, cfuncp, "super.new call not found"); + putCommaIterateNext(superNewCallp->argsp(), true); + } + puts(")"); + top = false; + } + } + // VISITORS using EmitCConstInit::visit; void visit(AstCFunc* nodep) override { @@ -265,20 +291,13 @@ public: if (nodep->isInline()) puts("VL_INLINE_OPT "); emitCFuncHeader(nodep, m_modp, /* withScope: */ true); - if (!nodep->baseCtors().empty()) { - puts(": "); - puts(nodep->baseCtors()); + if (nodep->isConstructor()) { const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class); - // Find call to super.new to get the arguments - if (classp && constructorNeedsProcess(classp)) { - puts("(vlProcess, vlSymsp"); - } else { - puts("(vlSymsp"); + if (nodep->isConstructor() && classp && classp->extendsp()) { + puts("\n : "); + bool first = true; + putConstructorSubinit(classp, nodep, true, first /*ref*/); } - const AstCNew* const superNewCallp = getSuperNewCallRecursep(nodep->stmtsp()); - UASSERT_OBJ(superNewCallp, nodep, "super.new call not found"); - putCommaIterateNext(superNewCallp->argsp(), true); - puts(")"); } puts(" {\n"); diff --git a/src/V3EmitCHeaders.cpp b/src/V3EmitCHeaders.cpp index 795193e5a..499f1e6d4 100644 --- a/src/V3EmitCHeaders.cpp +++ b/src/V3EmitCHeaders.cpp @@ -316,9 +316,14 @@ class EmitCHeader final : public EmitCConstInit { if (!VN_IS(modp, Class)) puts("alignas(VL_CACHE_LINE_BYTES) "); puts(prefixNameProtect(modp)); if (const AstClass* const classp = VN_CAST(modp, Class)) { - puts(" : public "); + const string virtpub = classp->useVirtualPublic() ? "virtual public " : "public "; + puts(" : " + virtpub); if (classp->extendsp()) { - puts(prefixNameProtect(classp->extendsp()->classp())); + for (const AstClassExtends* extp = classp->extendsp(); extp; + extp = VN_AS(extp->nextp(), ClassExtends)) { + puts(prefixNameProtect(extp->classp())); + if (extp->nextp()) puts(", " + virtpub); + } } else { puts("VlClass"); } diff --git a/src/V3Task.cpp b/src/V3Task.cpp index 7c589b7b9..5c1708fdf 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -1223,13 +1223,7 @@ class TaskVisitor final : public VNVisitor { } cfuncp->isVirtual(nodep->isVirtual()); cfuncp->dpiPure(nodep->dpiPure()); - if (nodep->name() == "new") { - cfuncp->isConstructor(true); - AstClass* const classp = m_statep->getClassp(nodep); - if (classp->extendsp()) { - cfuncp->baseCtors(EmitCBase::prefixNameProtect(classp->extendsp()->classp())); - } - } + if (nodep->name() == "new") cfuncp->isConstructor(true); if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname()); if (!nodep->dpiImport() && !nodep->taskPublic()) { diff --git a/test_regress/t/t_class_imp2.pl b/test_regress/t/t_class_imp2.pl new file mode 100755 index 000000000..e64ab41be --- /dev/null +++ b/test_regress/t/t_class_imp2.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 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_imp2.v b/test_regress/t/t_class_imp2.v new file mode 100644 index 000000000..36d3922a5 --- /dev/null +++ b/test_regress/t/t_class_imp2.v @@ -0,0 +1,47 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/); + + interface class Courier; + pure virtual function void deliver(); + endclass + class Person implements Courier; + virtual function void deliver(); + $display("slow delivery"); + endfunction + endclass + + interface class Seats; + pure virtual function int seats(); + endclass + + class Vehicle; + endclass + + class Car extends Vehicle implements Courier, Seats; + virtual function void deliver(); + $display("fast delivery"); + endfunction + virtual function int seats(); return 4; endfunction + endclass + + class MetaCar extends Car; + endclass + + function void do_delivery(Courier courier); + courier.deliver(); + endfunction + + initial begin + MetaCar car; + car = new(); + do_delivery(car); + if (car.seats() != 4) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule From 74ec50f9330bee457bbd586586f71b8950a22dd4 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Tue, 23 Jan 2024 22:07:35 -0500 Subject: [PATCH 055/116] Support interface class diamond relationship. --- configure.ac | 1 + src/V3EmitCFunc.h | 14 ++--- src/V3LinkDot.cpp | 10 ++-- test_regress/t/t_class_diamond.pl | 21 ++++++++ test_regress/t/t_class_diamond.v | 59 +++++++++++++++++++++ test_regress/t/t_implements_collision_bad.v | 18 +++++++ 6 files changed, 112 insertions(+), 11 deletions(-) create mode 100755 test_regress/t/t_class_diamond.pl create mode 100644 test_regress/t/t_class_diamond.v diff --git a/configure.ac b/configure.ac index 1aa353ed7..9315730f4 100644 --- a/configure.ac +++ b/configure.ac @@ -474,6 +474,7 @@ AC_SUBST(CFG_LDFLAGS_VERILATED) # pthreads is harmless otherwise. CFG_LIBS="$LIBS $CFG_LIBS" _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lpthread) +_MY_LDLIBS_CHECK_OPT(CFG_LIBS, -latomic) # Check libraries for MingW _MY_LDLIBS_CHECK_OPT(CFG_LIBS, -lbcrypt) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index b68dc0c83..aedd96a91 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -248,16 +248,18 @@ public: return nullptr; } - void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, bool& firstr) { + void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, std::set &doneClassesr) { for (const AstClassExtends* extp = classp->extendsp(); extp; extp = VN_AS(extp->nextp(), ClassExtends)) { if (extp->classp()->useVirtualPublic()) { // It's a c++ virtual class (diamond relation) // Must get the subclasses initialized first - putConstructorSubinit(extp->classp(), cfuncp, false, firstr); + putConstructorSubinit(extp->classp(), cfuncp, false, doneClassesr); } - puts(firstr ? "" : "\n, "); - firstr = false; + // Diamond pattern with same base class twice? + if (doneClassesr.find(extp->classp()) != doneClassesr.end()) continue; + puts(doneClassesr.empty() ? "" : "\n , "); + doneClassesr.emplace(extp->classp()); puts(prefixNameProtect(extp->classp())); if (constructorNeedsProcess(extp->classp())) { puts("(vlProcess, vlSymsp"); @@ -295,8 +297,8 @@ public: const AstClass* const classp = VN_CAST(nodep->scopep()->modp(), Class); if (nodep->isConstructor() && classp && classp->extendsp()) { puts("\n : "); - bool first = true; - putConstructorSubinit(classp, nodep, true, first /*ref*/); + std::set doneClasses; + putConstructorSubinit(classp, nodep, true, doneClasses /*ref*/); } } puts(" {\n"); diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 2d0887306..a8f6a58a7 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -2030,7 +2030,7 @@ class LinkDotResolveVisitor final : public VNVisitor { AstNodeFTask* m_ftaskp = nullptr; // Current function/task int m_modportNum = 0; // Uniqueify modport numbers bool m_inSens = false; // True if in senitem - std::set m_ifClassImpNames; // Names imported from interface class + std::map m_ifClassImpNames; // Names imported from interface class std::set m_extendsParam; // Classes that have a parameterized super class // (except the default instances) // They are added to the set only in linkDotPrimary. @@ -2235,9 +2235,9 @@ class LinkDotResolveVisitor final : public VNVisitor { << "... Location of interface class's function\n" << interfaceSubp->warnContextSecondary()); } - if (!existsInChild - && m_ifClassImpNames.find(interfaceSubp->name()) - != m_ifClassImpNames.end()) { + const auto it = m_ifClassImpNames.find(interfaceSubp->name()); + if (!existsInChild && it != m_ifClassImpNames.end() + && it->second != interfaceSubp) { // Not exact same function from diamond implementsClassp->v3error( "Class " << implementsClassp->prettyNameQ() << " implements " << interfaceClassp->prettyNameQ() @@ -2249,7 +2249,7 @@ class LinkDotResolveVisitor final : public VNVisitor { << "... Location of interface class's function\n" << interfaceSubp->warnContextSecondary()); } - m_ifClassImpNames.emplace(interfaceSubp->name()); + m_ifClassImpNames.emplace(interfaceSubp->name(), interfaceSubp); } } } diff --git a/test_regress/t/t_class_diamond.pl b/test_regress/t/t_class_diamond.pl new file mode 100755 index 000000000..e64ab41be --- /dev/null +++ b/test_regress/t/t_class_diamond.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 2024 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_diamond.v b/test_regress/t/t_class_diamond.v new file mode 100644 index 000000000..b4af229af --- /dev/null +++ b/test_regress/t/t_class_diamond.v @@ -0,0 +1,59 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2024 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module class_tb (); +interface class Ibase; + pure virtual function int fn(); +endclass + +interface class Ic1 extends Ibase; + pure virtual function int fn1(); +endclass + +interface class Ic2 extends Ibase; + pure virtual function int fn2(); +endclass + +interface class Ic3 extends Ic1, Ic2; +endclass + +class Cls implements Ic3; + virtual function int fn(); + return 10; + endfunction + virtual function int fn1(); + return 1; + endfunction + virtual function int fn2(); + return 2; + endfunction +endclass + + initial begin + Cls cls; + Ibase ibase; + Ic1 ic1; + Ic2 ic2; + Ic3 ic3; + cls = new; + if (cls.fn() != 10) $stop; + if (cls.fn1() != 1) $stop; + if (cls.fn2() != 2) $stop; + ibase = cls; + ic1 = cls; + ic2 = cls; + ic3 = cls; + if (ibase.fn() != 10) $stop; + if (ic1.fn() != 10) $stop; + if (ic2.fn() != 10) $stop; + if (ic3.fn() != 10) $stop; + if (ic1.fn1() != 1) $stop; + if (ic2.fn2() != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_implements_collision_bad.v b/test_regress/t/t_implements_collision_bad.v index d457be661..9767d8677 100644 --- a/test_regress/t/t_implements_collision_bad.v +++ b/test_regress/t/t_implements_collision_bad.v @@ -19,6 +19,24 @@ endclass class Cls implements IclsBoth; endclass + +// This is not a collision - diamond +interface class Ibase; + pure virtual function int fn(); +endclass + +interface class Ic1 extends Ibase; + pure virtual function int fn1(); +endclass + +interface class Ic2 extends Ibase; + pure virtual function int fn2(); +endclass + +interface class Ic3 extends Ic1, Ic2; +endclass + + module t (/*AUTOARG*/); Cls c; endmodule From 3d006afaccd0448ca8c5915d1d2f1b028307a650 Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 24 Jan 2024 03:08:39 +0000 Subject: [PATCH 056/116] Apply 'make format' --- src/V3EmitCFunc.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/V3EmitCFunc.h b/src/V3EmitCFunc.h index aedd96a91..791621089 100644 --- a/src/V3EmitCFunc.h +++ b/src/V3EmitCFunc.h @@ -248,7 +248,8 @@ public: return nullptr; } - void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, std::set &doneClassesr) { + void putConstructorSubinit(const AstClass* classp, AstCFunc* cfuncp, bool top, + std::set& doneClassesr) { for (const AstClassExtends* extp = classp->extendsp(); extp; extp = VN_AS(extp->nextp(), ClassExtends)) { if (extp->classp()->useVirtualPublic()) { From 31262e81f9cb9da611ac2b15c83ae9e9c804d07d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jonathan=20Schr=C3=B6ter?= <151610807+joschroeter@users.noreply.github.com> Date: Wed, 24 Jan 2024 13:45:38 +0100 Subject: [PATCH 057/116] Fix to not emit already waived warnings in waiver output (#4574) (#4818) --- docs/CONTRIBUTORS | 1 + src/V3FileLine.cpp | 2 +- test_regress/t/t_waiveroutput.out | 5 +---- test_regress/t/t_waiveroutput.pl | 16 +++++----------- test_regress/t/t_waiveroutput.v | 7 ++++++- test_regress/t/t_waiveroutput.vlt | 9 +++++++++ test_regress/t/t_waiveroutput_wall.out | 10 ++++++++++ test_regress/t/t_waiveroutput_wall.pl | 25 +++++++++++++++++++++++++ test_regress/t/t_waiveroutput_wall.vlt | 11 +++++++++++ 9 files changed, 69 insertions(+), 17 deletions(-) create mode 100644 test_regress/t/t_waiveroutput.vlt create mode 100644 test_regress/t/t_waiveroutput_wall.out create mode 100755 test_regress/t/t_waiveroutput_wall.pl create mode 100644 test_regress/t/t_waiveroutput_wall.vlt diff --git a/docs/CONTRIBUTORS b/docs/CONTRIBUTORS index 271c3898c..cf5f12e42 100644 --- a/docs/CONTRIBUTORS +++ b/docs/CONTRIBUTORS @@ -88,6 +88,7 @@ John Coiner John Demme John Wehle Jonathan Drolet +Jonathan Schröter Jordan McConnon Jose Loyola Josep Sans diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 0520b2e94..111caa7f9 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -411,7 +411,7 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) } else if (!V3Error::s().errorContexted()) { nsstr << warnContextPrimary(); } - if (!m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); + if (!warnIsOff(V3Error::s().errorCode()) && !m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); V3Error::v3errorEnd(nsstr, lstr.str()); } diff --git a/test_regress/t/t_waiveroutput.out b/test_regress/t/t_waiveroutput.out index 5e18d8676..673c0445a 100644 --- a/test_regress/t/t_waiveroutput.out +++ b/test_regress/t/t_waiveroutput.out @@ -7,7 +7,4 @@ // 2. Keep the waiver permanently if you are sure this is okay // 3. Keep the waiver temporarily to suppress the output -// lint_off -rule WIDTHTRUNC -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." - -// lint_off -rule UNUSEDSIGNAL -file "*t/t_waiveroutput.v" -match "Signal is not used: 'width_warn'" - +// No waivers needed - great! diff --git a/test_regress/t/t_waiveroutput.pl b/test_regress/t/t_waiveroutput.pl index 9559ffed7..c995f2cde 100755 --- a/test_regress/t/t_waiveroutput.pl +++ b/test_regress/t/t_waiveroutput.pl @@ -10,22 +10,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(vlt => 1); -my $out_filename = "$Self->{obj_dir}/$Self->{name}_waiver_gen.vlt"; -my $waiver_filename = "$Self->{obj_dir}/$Self->{name}_waiver.vlt"; +my $out_filename = "$Self->{obj_dir}/$Self->{name}_waiver_gen.out"; +my $waiver_filename = "t/$Self->{name}.vlt"; + +top_filename("t/t_waiveroutput.v"); compile( - v_flags2 => ['--waiver-output', $out_filename], - fails => 1, + v_flags2 => [$waiver_filename, '--waiver-output', $out_filename], ); files_identical("$out_filename", $Self->{golden_filename}); -file_sed($out_filename, $waiver_filename, - sub { s/\/\/ lint_off/lint_off/g; }); - -compile( - v_flags2 => [$waiver_filename], - ); - ok(1); 1; diff --git a/test_regress/t/t_waiveroutput.v b/test_regress/t/t_waiveroutput.v index c84e9dec4..f3441479c 100644 --- a/test_regress/t/t_waiveroutput.v +++ b/test_regress/t/t_waiveroutput.v @@ -5,6 +5,11 @@ // SPDX-License-Identifier: CC0-1.0 module t_waiveroutput; + reg width_warn = 2'b11; // Width warning - must be line 8 - reg width_warn = 2'b11; // Width warning - must be line 18 + // verilator lint_off UNUSEDSIGNAL + // verilator lint_off WIDTHTRUNC + reg width_warn2 = 2'b11; + // verilator lint_on UNUSEDSIGNAL + // verilator lint_on WIDTHTRUNC endmodule diff --git a/test_regress/t/t_waiveroutput.vlt b/test_regress/t/t_waiveroutput.vlt new file mode 100644 index 000000000..5771d85dc --- /dev/null +++ b/test_regress/t/t_waiveroutput.vlt @@ -0,0 +1,9 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +lint_off -rule WIDTH -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." diff --git a/test_regress/t/t_waiveroutput_wall.out b/test_regress/t/t_waiveroutput_wall.out new file mode 100644 index 000000000..673c0445a --- /dev/null +++ b/test_regress/t/t_waiveroutput_wall.out @@ -0,0 +1,10 @@ +// DESCRIPTION: Verilator output: Waivers generated with --waiver-output + +`verilator_config + +// Below you find suggested waivers. You have three options: +// 1. Fix the reason for the linter warning +// 2. Keep the waiver permanently if you are sure this is okay +// 3. Keep the waiver temporarily to suppress the output + +// No waivers needed - great! diff --git a/test_regress/t/t_waiveroutput_wall.pl b/test_regress/t/t_waiveroutput_wall.pl new file mode 100755 index 000000000..ff30db361 --- /dev/null +++ b/test_regress/t/t_waiveroutput_wall.pl @@ -0,0 +1,25 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2012 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); + +my $out_filename = "$Self->{obj_dir}/$Self->{name}_waiver_gen.out"; +my $waiver_filename = "t/$Self->{name}.vlt"; + +top_filename("t/t_waiveroutput.v"); + +compile( + v_flags2 => ['-Wall', $waiver_filename, '--waiver-output', $out_filename], + ); + +files_identical("$out_filename", $Self->{golden_filename}); + +ok(1); +1; diff --git a/test_regress/t/t_waiveroutput_wall.vlt b/test_regress/t/t_waiveroutput_wall.vlt new file mode 100644 index 000000000..54c5798f2 --- /dev/null +++ b/test_regress/t/t_waiveroutput_wall.vlt @@ -0,0 +1,11 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`verilator_config + +lint_off -rule WIDTH -file "*t/t_waiveroutput.v" -match "Operator ASSIGN expects 1 bits on the Assign RHS, but Assign RHS's CONST '2'h3' generates 2 bits." + +lint_off -rule UNUSED -file "*t/t_waiveroutput.v" -match "Signal is not used: 'width_warn'" From 8a7f36c34b2a04a73aa2b472eb502d02d28c9a4a Mon Sep 17 00:00:00 2001 From: github action Date: Wed, 24 Jan 2024 12:46:22 +0000 Subject: [PATCH 058/116] Apply 'make format' --- src/V3FileLine.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 111caa7f9..d3ab82d47 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -411,7 +411,8 @@ void FileLine::v3errorEnd(std::ostringstream& sstr, const string& extra) } else if (!V3Error::s().errorContexted()) { nsstr << warnContextPrimary(); } - if (!warnIsOff(V3Error::s().errorCode()) && !m_waive) V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); + if (!warnIsOff(V3Error::s().errorCode()) && !m_waive) + V3Waiver::addEntry(V3Error::s().errorCode(), filename(), sstr.str()); V3Error::v3errorEnd(nsstr, lstr.str()); } From 23836ee8d00a4da961be6c761f7610a4cee74f36 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Jan 2024 17:55:23 -0500 Subject: [PATCH 059/116] Document gprof steps better. Add t_prof_timing test to show GCC bug (#4858). --- docs/guide/simulating.rst | 16 ++++++---- test_regress/t/t_prof.pl | 12 +++---- test_regress/t/t_prof.v | 10 ++++-- test_regress/t/t_prof_timing.pl | 55 +++++++++++++++++++++++++++++++++ test_regress/t/t_profc.pl | 2 +- test_regress/t/t_profcfunc.pl | 4 +-- 6 files changed, 82 insertions(+), 17 deletions(-) create mode 100755 test_regress/t/t_prof_timing.pl diff --git a/docs/guide/simulating.rst b/docs/guide/simulating.rst index e196444dd..c93decc04 100644 --- a/docs/guide/simulating.rst +++ b/docs/guide/simulating.rst @@ -279,13 +279,17 @@ profiled C++ code functions. To use profiling: -#. Use Verilator's :vlopt:`--prof-cfuncs`. +#. Make sure the Verilog code will call `$finish` at the end of simulation + (otherwise the C library may not correctly create the `gmon.out` file in + the later steps below). +#. Run Verilator, adding the :vlopt:`--prof-cfuncs` option. #. Build and run the simulation model. -#. The model will create gmon.out. -#. Run :command:`gprof` to see where in the C++ code the time is spent. -#. Run the gprof output through the :command:`verilator_profcfunc` program, - and it will tell you what Verilog line numbers on which most of the time - is being spent. +#. The model will create `gmon.out`. +#. Run :command:`gprof gmon.out > gprof.log` to see where in the C++ code + the time is spent. +#. Run :command:`verilator_profcfunc gprof.log > profcfunc.log` to take the + gprof output and translate into output showing the Verilog line numbers + on which most of the time is being spent. .. _Execution Profiling: diff --git a/test_regress/t/t_prof.pl b/test_regress/t/t_prof.pl index 2d276ba37..7150c0c0c 100755 --- a/test_regress/t/t_prof.pl +++ b/test_regress/t/t_prof.pl @@ -21,7 +21,7 @@ ok(1); sub dotest { compile( - verilator_flags2 => ["--stats --prof-cfuncs"], + verilator_flags2 => ["--stats --prof-cfuncs +define+T_PROF"], ); unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); @@ -36,15 +36,15 @@ sub dotest { $gmon_path or error("Profiler did not create a gmon.out"); (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; - run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.out"], + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.log"], check_finished => 0); - run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"], + run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.log > profcfuncs.log"], check_finished => 0); - file_grep("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/); - file_grep("$Self->{obj_dir}/cfuncs.out", qr/VLib + VL_POWSS_QQQ/); - file_grep("$Self->{obj_dir}/cfuncs.out", qr/VBlock + t_prof:/); + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/Overall summary by/); + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/VLib + VL_POWSS_QQQ/); + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/VBlock + t_prof:/); } 1; diff --git a/test_regress/t/t_prof.v b/test_regress/t/t_prof.v index ee63a2f6b..30002a14f 100644 --- a/test_regress/t/t_prof.v +++ b/test_regress/t/t_prof.v @@ -4,11 +4,17 @@ // any use, without warranty, 2021 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -module t(/*AUTOARG*/ - // Inputs +module t( +`ifdef T_PROF clk +`endif ); +`ifdef T_PROF input clk; +`else + bit clk; + initial forever begin #5; clk = !clk; end +`endif integer cyc = 0; wire [63:0] result; diff --git a/test_regress/t/t_prof_timing.pl b/test_regress/t/t_prof_timing.pl new file mode 100755 index 000000000..45df95a36 --- /dev/null +++ b/test_regress/t/t_prof_timing.pl @@ -0,0 +1,55 @@ +#!/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); + +top_filename("t/t_prof.v"); + +# TODO below might no longer be required as configure checks for -pg +if ($ENV{VERILATOR_TEST_NO_GPROF}) { + skip("Skipping due to VERILATOR_TEST_NO_GPROF"); +} else { + dotest(); +} + +ok(1); + +sub dotest { + compile( + verilator_flags2 => ["--stats --prof-cfuncs --binary"], + ); + + unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); + setenv('GMON_OUT_PREFIX', "$Self->{obj_dir}/gmon.out"); + + execute( + check_finished => 1, + ); + + my $gmon_path; + $gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*"); + $gmon_path or error("Profiler did not create a gmon.out"); + (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; + + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.log"], + check_finished => 0); + + run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.log > profcfuncs.log"], + check_finished => 0); + + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/Overall summary by/); +# Appears that GCC 11.4 has a bug whereby it doesn't trace function calls +# within coroutines; CLang seems to work correctly. +# file_grep("$Self->{obj_dir}/profcfuncs.log", qr/VLib + VL_POWSS_QQQ/); + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/VLib + VL_WRITEF/); + file_grep("$Self->{obj_dir}/profcfuncs.log", qr/VBlock + t_prof:/); +} + +1; diff --git a/test_regress/t/t_profc.pl b/test_regress/t/t_profc.pl index e972b9a9e..453114d26 100755 --- a/test_regress/t/t_profc.pl +++ b/test_regress/t/t_profc.pl @@ -31,7 +31,7 @@ sub dotest { $gmon_path or error("Profiler did not create a gmon.out"); (my $gmon_base = $gmon_path) =~ s!.*[/\\]!!; - run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.out"], + run(cmd => ["cd $Self->{obj_dir} && gprof $Self->{vm_prefix} $gmon_base > gprof.log"], check_finished => 0); } diff --git a/test_regress/t/t_profcfunc.pl b/test_regress/t/t_profcfunc.pl index 8e0470809..ec29d69ff 100755 --- a/test_regress/t/t_profcfunc.pl +++ b/test_regress/t/t_profcfunc.pl @@ -10,10 +10,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(dist => 1); -run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc $Self->{t_dir}/t_profcfunc.gprof > cfuncs.out"], +run(cmd => ["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc $Self->{t_dir}/t_profcfunc.gprof > profcfuncs.log"], check_finished => 0); -files_identical("$Self->{obj_dir}/cfuncs.out", $Self->{golden_filename}); +files_identical("$Self->{obj_dir}/profcfuncs.log", $Self->{golden_filename}); ok(1); From 771cb5f60bae7d2c6eac7213f0c293fdfc02c046 Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Jan 2024 18:48:27 -0500 Subject: [PATCH 060/116] Tests: Fix last commit when no coroutines. --- test_regress/t/t_prof_timing.pl | 2 ++ 1 file changed, 2 insertions(+) diff --git a/test_regress/t/t_prof_timing.pl b/test_regress/t/t_prof_timing.pl index 45df95a36..6bc05c186 100755 --- a/test_regress/t/t_prof_timing.pl +++ b/test_regress/t/t_prof_timing.pl @@ -15,6 +15,8 @@ top_filename("t/t_prof.v"); # TODO below might no longer be required as configure checks for -pg if ($ENV{VERILATOR_TEST_NO_GPROF}) { skip("Skipping due to VERILATOR_TEST_NO_GPROF"); +} elsif (!$Self->have_coroutines) { + skip("No coroutine support"); } else { dotest(); } From c8a40e0b528a4fdba3ed24804470c7c0dc40971d Mon Sep 17 00:00:00 2001 From: Wilson Snyder Date: Wed, 24 Jan 2024 19:28:46 -0500 Subject: [PATCH 061/116] Commentary; Tests: Check summary options match guide options --- bin/verilator | 9 +- bin/verilator_coverage | 12 +-- test_regress/t/t_dist_docs_summary.pl | 119 ++++++++++++++++++++++++++ 3 files changed, 131 insertions(+), 9 deletions(-) create mode 100755 test_regress/t/t_dist_docs_summary.pl diff --git a/bin/verilator b/bin/verilator index 56e4008b3..fd2ad8024 100755 --- a/bin/verilator +++ b/bin/verilator @@ -307,7 +307,6 @@ detailed descriptions of these arguments. --build-dep-bin Override build dependency Verilator binary --build-jobs Parallelism for --build --cc Create C++ output - --cdc Clock domain crossing analysis -CFLAGS C++ compiler arguments for makefile --clk Mark specified signal as clock --no-clk Prevent marking specified signal as clock @@ -334,6 +333,7 @@ detailed descriptions of these arguments. --dump-graph Enable dumping V3Graphs to .dot files --dump-tree Enable dumping Ast .tree files --dump-tree-addrids Use short identifiers instead of addresses + --dump-tree-dot Enable dumping Ast .tree.dot debug files --dump- Enable dumping everything in source file --dumpi-dfg Enable dumping DfgGraphs to .dot files at level --dumpi-graph Enable dumping V3Graphs to .dot files at level @@ -347,6 +347,8 @@ detailed descriptions of these arguments. -f Parse arguments from a file -FI Force include of a file --flatten Force inlining of all modules, tasks and functions + --future0