diff --git a/.clang-tidy b/.clang-tidy index f5079ed0e..f043d8cda 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,4 +1,4 @@ -Checks: 'clang-diagnostic-*,clang-analyzer-*,*,-modernize*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-default-arguments,-fuchsia-overloaded-operator,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance' +Checks: '*,-hicpp*,-android-cloexec-fopen,-cert-dcl50-cpp,-cert-env33-c,-cert-err34-c,-cert-err58-cpp,-clang-analyzer-core.UndefinedBinaryOperatorResult,-clang-analyzer-security*,-cppcoreguidelines-avoid-magic-numbers,-cppcoreguidelines-no-malloc,-cppcoreguidelines-owning-memory,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-array-to-pointer-decay,-cppcoreguidelines-pro-bounds-constant-array-index,-cppcoreguidelines-pro-bounds-pointer-arithmetic,-cppcoreguidelines-pro-type-const-cast,-cppcoreguidelines-pro-type-reinterpret-cast,-cppcoreguidelines-pro-type-static-cast-downcast,-cppcoreguidelines-pro-type-union-access,-cppcoreguidelines-pro-type-vararg,-cppcoreguidelines-special-member-functions,-fuchsia-*,-google-default-arguments,-google-readability-todo,-google-runtime-references,-llvm-header-guard,-llvm-include-order,-misc-string-integer-assignment,-misc-string-literal-with-embedded-nul,-modernize-use-auto,-modernize-use-trailing-return-type,-readability-braces-around-statements,-readability-container-size-empty,-readability-delete-null-pointer,-readability-else-after-return,-readability-implicit-bool-conversion,-readability-named-parameter,-readability-static-accessed-through-instance' WarningsAsErrors: '' HeaderFilterRegex: '' FormatStyle: none diff --git a/Changes b/Changes index 98a47d3a3..3e06d6263 100644 --- a/Changes +++ b/Changes @@ -2,9 +2,35 @@ Revision history for Verilator The contributors that suggested a given feature are shown in []. Thanks! + +* Verilator 4.106 2020-12-02 + +** Change -sv option to select 1800-2017 instead of 1800-2005. + +*** Check for proper 'local' and 'protected' (#2228). + +*** Support $random and $urandom seeds. + +*** Support $monitor and $strobe. + +*** Support complex function arguments. + +*** Support 'super'. + +*** Support 'with item.index'. + +**** Fix the default GNU Make executable name on FreeBSD (#2553). [Yuri Victorovich] + +**** Fix trace signal names getting hashed (#2643). [Barbara Gigerl] + +**** Fix unpacked array parameters near functions (#2639). [Anderson Ignacio da Silva] + +**** Fix access to non-overridden base class variable (#2654). [Tobias Rosenkranz] + + * Verilator 4.104 2020-11-14 -*** Support queue and associative array 'with' statements. (#2616) +*** Support queue and associative array 'with' statements (#2616). *** Support queue slicing (#2326). diff --git a/Makefile.in b/Makefile.in index 6e2dc2ec7..7d2a929e2 100644 --- a/Makefile.in +++ b/Makefile.in @@ -445,12 +445,13 @@ CLANGTIDY = clang-tidy CLANGTIDY_FLAGS = -config='' -checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables' CLANGTIDY_DEP = $(subst .h,.h.tidy,$(CPPCHECK_H)) \ $(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP)) +CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_THREADED=1 -DVL_CPPCHECK=1 clang-tidy: $(CLANGTIDY_DEP) %.cpp.tidy: %.cpp - $(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@ + $(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@ %.h.tidy: %.h - $(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) | 2>&1 tee $@ + $(CLANGTIDY) $(CLANGTIDY_FLAGS) $< -- $(CLANGTIDY_DEFS) $(CPPCHECK_INC) | 2>&1 tee $@ analyzer-src: -rm -rf src/obj_dbg diff --git a/bin/verilator b/bin/verilator index 213d90e34..2df1ec7aa 100755 --- a/bin/verilator +++ b/bin/verilator @@ -1461,7 +1461,7 @@ future version of Verilator no longer always packs unpacked structures. =item -sv Specifies SystemVerilog language features should be enabled; equivalent to -"--language 1800-2005". This option is selected by default, it exists for +"--language 1800-2017". This option is selected by default, it exists for compatibility with other simulators. =item +systemverilogext+I @@ -1996,14 +1996,15 @@ section below for descriptions of some of the files that were created. (Verilator included a default compile rule and link rule, since we used --exe and passed a .cpp file on the Verilator command line. Verilator also -then used C to build a final executable. You can also write your own -compile rules, and run make yourself as we'll show in the SYSTEMC section.) +then used C to build a final executable, since we used --build. You +can also write your own compile rules, and run make yourself as we'll show +in the SYSTEMC section. -And now we run it +And now we run it: obj_dir/Vour -And we get as output +And we get as output: Hello World - our.v:2: Verilog $finish @@ -4106,17 +4107,12 @@ $setup, $setuphold, $skew, $timeskew, $width All specify blocks and timing checks are ignored. -=item $monitor, $strobe - -Monitor and strobe are not supported, convert to always_comb $display or -similar. - =item $random, $urandom, $urandom_range -$random and $urandom do not support the optional argument to set the seed. -Use +verilator+seed argument to set the seed. There is one random seed per -C thread, not per module for $random, nor per object for random stability -of $urandom/$urandom_range. +Use +verilator+seed argument to set the seed if there is no $random or +$urandom optional argument to set the seed. There is one random seed per C +thread, not per module for $random, nor per object for random stability of +$urandom/$urandom_range. =item $readmemb, $readmemh diff --git a/bin/verilator_gantt b/bin/verilator_gantt index cc7f0fbba..1de46b104 100755 --- a/bin/verilator_gantt +++ b/bin/verilator_gantt @@ -60,6 +60,7 @@ sub process { my $filename = shift; read_data($filename); + read_cpuinfo(); report(); } @@ -70,7 +71,7 @@ sub read_data { %Global = (rdtsc_cycle_time => 0); - my $fh = IO::File->new ($filename) or die "%Error: $! $filename,"; + my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,"; while (my $line = $fh->getline) { if ($line =~ m/VLPROF mtask\s(\d+)\sstart\s(\d+)\send\s(\d+)\selapsed\s(\d+)\spredict_time\s(\d+)\scpu\s(\d+)\son thread (\d+)/) { my $mtask = $1; @@ -113,6 +114,27 @@ sub read_data { } } +sub read_cpuinfo { + my $filename = "/proc/cpuinfo"; + my $fh = IO::File->new("<$filename") or return; + my $cpu; + while (my $line = $fh->getline) { + chomp $line; + if ($line =~ m/^processor\s*:\s*(\d+)\s*$/) { + $cpu = $1; + } + if ($cpu && $line =~ m/^([a-z_ ]+)\s*:\s*(.*)$/) { + my ($term, $value) = ($1, $2); + $term =~ s/\s+$//; + $term =~ s/\s+/_/; + $value =~ s/\s+$//; + $Global{cpuinfo}{$cpu}{$term} = $value; + } + } +} + +####################################################################### + sub report { print "Verilator Gantt report\n"; @@ -162,9 +184,9 @@ sub report { printf " Total eval time = %d rdtsc ticks\n", $Global{last_end}; printf " Longest mtask time = %d rdtsc ticks\n", $long_mtask_time; printf " All-thread mtask time = %d rdtsc ticks\n", $mt_mtask_time; - my $long_efficiency = $long_mtask_time/($Global{last_end}); + my $long_efficiency = $long_mtask_time/($Global{last_end} || 1); printf " Longest-thread efficiency = %0.1f%%\n", $long_efficiency*100; - my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads); + my $mt_efficiency = $mt_mtask_time/($Global{last_end}*$nthreads || 1); printf " All-thread efficiency = %0.1f%%\n", $mt_efficiency*100; printf " All-thread speedup = %0.1f\n", $mt_efficiency*$nthreads; if ($Global{rdtsc_cycle_time} > 0) { @@ -210,13 +232,58 @@ sub report { printf " mean = %0.3f\n", $mean; printf " stddev = %0.3f\n", $stddev; printf " e ^ stddev = %0.3f\n", exp($stddev); - print "\n"; + + report_cpus(); if ($nthreads > $ncpus) { + print "\n"; print "%Warning: There were fewer CPUs ($ncpus) then threads ($nthreads).\n"; print " : See docs on use of numactl.\n"; + } else { + if ($Global{cpu_socket_cores_warning}) { + print "\n"; + print "%Warning: Multiple threads scheduled on same hyperthreaded core.\n"; + print " : See docs on use of numactl.\n"; + } + if ($Global{cpu_sockets_warning}) { + print "\n"; + print "%Warning: Threads scheduled on multiple sockets.\n"; + print " : See docs on use of numactl.\n"; + } + } + print "\n"; +} + +sub report_cpus { + print "\nCPUs:\n"; + # Test - show all cores + # for (my $i=0; $i<73; ++$i) { $Global{cpus}{$i} ||= {cpu_time => 0}; } + + $Global{cpu_sockets} ||= {}; + $Global{cpu_socket_cores} ||= {}; + + foreach my $cpu (sort {$a <=> $b} keys %{$Global{cpus}}) { + printf " cpu %d: ", $cpu; + printf "cpu_time=%d", $Global{cpus}{$cpu}{cpu_time}; + + my $socket = $Global{cpuinfo}{$cpu}{physical_id}; + $Global{cpu_sockets}{$socket}++ if defined $socket; + printf " socket=%d", $socket if defined $socket; + + my $core = $Global{cpuinfo}{$cpu}{core_id}; + $Global{cpu_socket_cores}{$socket."__".$core}++ if defined $socket && defined $core; + printf " core=%d", $core if defined $core; + + my $model = $Global{cpuinfo}{$cpu}{model_name}; + printf " %s", $model if defined $model; print "\n"; } + + $Global{cpu_sockets_warning} = 1 + if (scalar keys %{$Global{cpu_sockets}} > 1); + foreach my $scn (values %{$Global{cpu_socket_cores}}) { + $Global{cpu_socket_cores_warning} = 1 if $scn > 1; + } } sub report_graph { @@ -230,6 +297,7 @@ sub report_graph { } # One more step so we can fit more labels $time_per = int($time_per/2); + $time_per ||= 1; } my ($graph, $conflicts) = _make_graph($time_per); diff --git a/ci/docker/buildenv/Dockerfile b/ci/docker/buildenv/Dockerfile index f3008bb97..6f9dd3539 100644 --- a/ci/docker/buildenv/Dockerfile +++ b/ci/docker/buildenv/Dockerfile @@ -40,7 +40,7 @@ RUN apt-get update \ WORKDIR /tmp -RUN cpan install -fi Unix::Processors Parallel::Forker Bit::Vector +RUN cpan install -fi Unix::Processors Parallel::Forker RUN git clone https://github.com/veripool/vcddiff.git && \ make -C vcddiff && \ diff --git a/ci/travis-install.bash b/ci/travis-install.bash index 27adf42ec..9178e66b5 100755 --- a/ci/travis-install.bash +++ b/ci/travis-install.bash @@ -94,7 +94,6 @@ elif [ "$TRAVIS_BUILD_STAGE_NAME" = "test" ]; then if [ "$TRAVIS_DIST" != "trusty" ]; then TRAVIS_CPAN_REPO=https://cpan.org fi - # Not listing Bit::Vector as slow to install, and only skips one test yes yes | sudo cpan -M $TRAVIS_CPAN_REPO -fi Unix::Processors Parallel::Forker install-vcddiff else diff --git a/configure.ac b/configure.ac index 6b165fcc0..563c93a29 100644 --- a/configure.ac +++ b/configure.ac @@ -7,7 +7,7 @@ #AC_INIT([Verilator],[#.### YYYY-MM-DD]) #AC_INIT([Verilator],[#.### devel]) -AC_INIT([Verilator],[4.104 2020-11-14], +AC_INIT([Verilator],[4.106 2020-12-02], [https://verilator.org], [verilator],[https://verilator.org]) # When releasing, also update header of Changes file diff --git a/docs/install.adoc b/docs/install.adoc index dfe5c0e75..65ae632f3 100644 --- a/docs/install.adoc +++ b/docs/install.adoc @@ -102,7 +102,6 @@ Those developing Verilator itself may also want these (see internals.adoc): cpan install Pod::Perldoc cpan install Unix::Processors cpan install Parallel::Forker - cpan install Bit::Vector ==== Install SystemC diff --git a/docs/internals.adoc b/docs/internals.adoc index fdf08a899..aab4d8099 100644 --- a/docs/internals.adoc +++ b/docs/internals.adoc @@ -628,8 +628,6 @@ https://github.com/veripool/vcddiff * Cmake for build paths that use it. -* Bit::Vector to test vgen.pl - === Controlling the Test Driver Test drivers are written in PERL. All invoke the main test driver script, @@ -959,9 +957,9 @@ Then, when the watch fires, to break at every following change to that node: To print a node: pn nodep - # or: call nodep->dumpGdb() # aliased to "pn" in src/.gdbinit + # or: call dumpGdb(nodep) # aliased to "pn" in src/.gdbinit pnt nodep - # or: call nodep->dumpTreeGdb() # aliased to "pnt" in src/.gdbinit + # or: call dumpTreeGdb(nodep) # aliased to "pnt" in src/.gdbinit When GDB halts, it is useful to understand that the backtrace will commonly show the iterator functions between each invocation of `visit` in the diff --git a/include/verilated.cpp b/include/verilated.cpp index d976d45a5..101054439 100644 --- a/include/verilated.cpp +++ b/include/verilated.cpp @@ -61,7 +61,7 @@ typedef union { // Global variables // Slow path variables -VerilatedMutex Verilated::m_mutex; +VerilatedMutex Verilated::s_mutex; // Keep below together in one cache line Verilated::Serialized Verilated::s_s; @@ -75,7 +75,7 @@ VerilatedImp::VerilatedImpU VerilatedImp::s_s; struct VerilatedImpInitializer { VerilatedImpInitializer() { VerilatedImp::setup(); } ~VerilatedImpInitializer() { VerilatedImp::teardown(); } -} g_VerilatedImpInitializer; +} s_VerilatedImpInitializer; //=========================================================================== // User definable functions @@ -256,6 +256,7 @@ Verilated::Serialized::Serialized() { s_errorLimit = 1; s_randReset = 0; s_randSeed = 0; + s_randSeedEpoch = 1; s_timeunit = VL_TIME_UNIT; // Initial value until overriden by _Vconfigure s_timeprecision = VL_TIME_PRECISION; // Initial value until overriden by _Vconfigure } @@ -279,6 +280,8 @@ void* Verilated::serialized2Ptr() VL_MT_UNSAFE { return &VerilatedImp::s_s.v.m_s static vluint32_t vl_sys_rand32() VL_MT_UNSAFE { // Return random 32-bits using system library. // Used only to construct seed for Verilator's PNRG. + static VerilatedMutex s_mutex; + const VerilatedLockGuard lock(s_mutex); // Otherwise rand is unsafe #if defined(_WIN32) && !defined(__CYGWIN__) // Windows doesn't have lrand48(), although Cygwin does. return (rand() << 16) ^ rand(); @@ -288,29 +291,18 @@ static vluint32_t vl_sys_rand32() VL_MT_UNSAFE { } vluint64_t vl_rand64() VL_MT_SAFE { - static VerilatedMutex s_mutex; - static VL_THREAD_LOCAL bool t_seeded = false; + static VL_THREAD_LOCAL vluint32_t t_seedEpoch = 0; static VL_THREAD_LOCAL vluint64_t t_state[2]; - if (VL_UNLIKELY(!t_seeded)) { - t_seeded = true; - { - const VerilatedLockGuard lock(s_mutex); - if (Verilated::randSeed() != 0) { - t_state[0] = ((static_cast(Verilated::randSeed()) << 32) - ^ (static_cast(Verilated::randSeed()))); - t_state[1] = ((static_cast(Verilated::randSeed()) << 32) - ^ (static_cast(Verilated::randSeed()))); - } else { - t_state[0] = ((static_cast(vl_sys_rand32()) << 32) - ^ (static_cast(vl_sys_rand32()))); - t_state[1] = ((static_cast(vl_sys_rand32()) << 32) - ^ (static_cast(vl_sys_rand32()))); - } - // Fix state as algorithm is slow to randomize if many zeros - // This causes a loss of ~ 1 bit of seed entropy, no big deal - if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0]; - if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1]; - } + // For speed, we use a thread-local epoch number to know when to reseed + if (VL_UNLIKELY(t_seedEpoch != Verilated::randSeedEpoch())) { + // Set epoch before state, in case races with new seeding + t_seedEpoch = Verilated::randSeedEpoch(); + t_state[0] = Verilated::randSeedDefault64(); + t_state[1] = t_state[0]; + // Fix state as algorithm is slow to randomize if many zeros + // This causes a loss of ~ 1 bit of seed entropy, no big deal + if (VL_COUNTONES_I(t_state[0]) < 10) t_state[0] = ~t_state[0]; + if (VL_COUNTONES_I(t_state[1]) < 10) t_state[1] = ~t_state[1]; } // Xoroshiro128+ algorithm vluint64_t result = t_state[0] + t_state[1]; @@ -334,6 +326,11 @@ WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE { } // LCOV_EXCL_STOP +IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE { + Verilated::randSeed(static_cast(seed)); + return VL_RANDOM_I(obits); +} + IData VL_RAND_RESET_I(int obits) VL_MT_SAFE { if (Verilated::randReset() == 0) return 0; IData data = ~0; @@ -688,7 +685,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA // Note uses a single buffer internally; presumes only one usage per printf // Note also assumes variables < 64 are not wide, this assumption is // sometimes not true in low-level routines written here in verilated.cpp - static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH]; + static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH]; const char* pctp = nullptr; // Most recent %##.##g format bool inPct = false; bool widthSet = false; @@ -766,11 +763,11 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA if (lbits) {} // UNUSED - always 64 if (fmt == '^') { // Realtime if (!widthSet) width = VerilatedImp::timeFormatWidth(); - output += _vl_vsformat_time(tmp, d, left, width); + output += _vl_vsformat_time(t_tmp, d, left, width); } else { std::string fmts(pctp, pos - pctp + 1); - sprintf(tmp, fmts.c_str(), d); - output += tmp; + sprintf(t_tmp, fmts.c_str(), d); + output += t_tmp; } break; } @@ -814,9 +811,9 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA int digits = 0; std::string append; if (lbits <= VL_QUADSIZE) { - digits = sprintf(tmp, "%" VL_PRI64 "d", + digits = sprintf(t_tmp, "%" VL_PRI64 "d", static_cast(VL_EXTENDS_QQ(lbits, lbits, ld))); - append = tmp; + append = t_tmp; } else { if (VL_SIGN_E(lbits, lwp[VL_WORDS_I(lbits) - 1])) { WData neg[VL_VALUE_STRING_MAX_WIDTH / 4 + 2]; @@ -843,8 +840,8 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA int digits = 0; std::string append; if (lbits <= VL_QUADSIZE) { - digits = sprintf(tmp, "%" VL_PRI64 "u", ld); - append = tmp; + digits = sprintf(t_tmp, "%" VL_PRI64 "u", ld); + append = t_tmp; } else { append = VL_DECIMAL_NW(lbits, lwp); digits = append.length(); @@ -863,7 +860,7 @@ void _vl_vsformat(std::string& output, const char* formatp, va_list ap) VL_MT_SA } case 't': { // Time if (!widthSet) width = VerilatedImp::timeFormatWidth(); - output += _vl_vsformat_time(tmp, static_cast(ld), left, width); + output += _vl_vsformat_time(t_tmp, static_cast(ld), left, width); break; } case 'b': @@ -1037,7 +1034,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf // Read a Verilog $sscanf/$fscanf style format into the output list // The format must be pre-processed (and lower cased) by Verilator // Arguments are in "width, arg-value (or WDataIn* if wide)" form - static VL_THREAD_LOCAL char tmp[VL_VALUE_STRING_MAX_WIDTH]; + static VL_THREAD_LOCAL char t_tmp[VL_VALUE_STRING_MAX_WIDTH]; int floc = fbits - 1; IData got = 0; bool inPct = false; @@ -1045,7 +1042,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf const char* pos = formatp; for (; *pos && !_vl_vsss_eof(fp, floc); ++pos) { // VL_DBG_MSGF("_vlscan fmt='"<(strlen(tmp))) - 1; + int lpos = (static_cast(strlen(t_tmp))) - 1; int lsb = 0; for (int i = 0; i < obits && lpos >= 0; --lpos) { - _vl_vsss_setbit(owp, obits, lsb, 8, tmp[lpos]); + _vl_vsss_setbit(owp, obits, lsb, 8, t_tmp[lpos]); lsb += 8; } } @@ -1115,10 +1112,10 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf } case 'd': { // Signed decimal _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); - if (!tmp[0]) goto done; + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_"); + if (!t_tmp[0]) goto done; vlsint64_t ld = 0; - sscanf(tmp, "%30" VL_PRI64 "d", &ld); + sscanf(t_tmp, "%30" VL_PRI64 "d", &ld); VL_SET_WQ(owp, ld); break; } @@ -1126,46 +1123,47 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf case 'e': case 'g': { // Real number _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "+-.0123456789eE"); - if (!tmp[0]) goto done; + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "+-.0123456789eE"); + if (!t_tmp[0]) goto done; // cppcheck-suppress unusedStructMember // It's used union { double r; vlsint64_t ld; } u; - u.r = strtod(tmp, nullptr); + u.r = strtod(t_tmp, nullptr); VL_SET_WQ(owp, u.ld); break; } case 't': // FALLTHRU // Time case '#': { // Unsigned decimal _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789+-xXzZ?_"); - if (!tmp[0]) goto done; + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "0123456789+-xXzZ?_"); + if (!t_tmp[0]) goto done; QData ld = 0; - sscanf(tmp, "%30" VL_PRI64 "u", &ld); + sscanf(t_tmp, "%30" VL_PRI64 "u", &ld); VL_SET_WQ(owp, ld); break; } case 'b': { _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01xXzZ?_"); - if (!tmp[0]) goto done; - _vl_vsss_based(owp, obits, 1, tmp, 0, strlen(tmp)); + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01xXzZ?_"); + if (!t_tmp[0]) goto done; + _vl_vsss_based(owp, obits, 1, t_tmp, 0, strlen(t_tmp)); break; } case 'o': { _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "01234567xXzZ?_"); - if (!tmp[0]) goto done; - _vl_vsss_based(owp, obits, 3, tmp, 0, strlen(tmp)); + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "01234567xXzZ?_"); + if (!t_tmp[0]) goto done; + _vl_vsss_based(owp, obits, 3, t_tmp, 0, strlen(t_tmp)); break; } case 'x': { _vl_vsss_skipspace(fp, floc, fromp, fstr); - _vl_vsss_read_str(fp, floc, fromp, fstr, tmp, "0123456789abcdefABCDEFxXzZ?_"); - if (!tmp[0]) goto done; - _vl_vsss_based(owp, obits, 4, tmp, 0, strlen(tmp)); + _vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, + "0123456789abcdefABCDEFxXzZ?_"); + if (!t_tmp[0]) goto done; + _vl_vsss_based(owp, obits, 4, t_tmp, 0, strlen(t_tmp)); break; } case 'u': { @@ -1208,7 +1206,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf if (obits == 0) { // Due to inIgnore } else if (obits == -1) { // string std::string* p = va_arg(ap, std::string*); - *p = tmp; + *p = t_tmp; } else if (obits <= VL_BYTESIZE) { CData* p = va_arg(ap, CData*); *p = owp[0]; @@ -1332,58 +1330,58 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE { void VL_FFLUSH_ALL() VL_MT_SAFE { fflush(stdout); } void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - _VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str()); + _VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str()); } void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - _VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str()); + _VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str()); } void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - _VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str()); + _VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str()); } void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - _VL_STRING_TO_VINT(obits, &destr, output.length(), output.c_str()); + _VL_STRING_TO_VINT(obits, &destr, t_output.length(), t_output.c_str()); } void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - _VL_STRING_TO_VINT(obits, destp, output.length(), output.c_str()); + _VL_STRING_TO_VINT(obits, destp, t_output.length(), t_output.c_str()); } void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, ...) VL_MT_SAFE { @@ -1396,38 +1394,38 @@ void VL_SFORMAT_X(int obits_ignored, std::string& output, const char* formatp, . } std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - return output; + return t_output; } void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE { - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - VL_PRINTF_MT("%s", output.c_str()); + VL_PRINTF_MT("%s", t_output.c_str()); } void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE { // While threadsafe, each thread can only access different file handles - static VL_THREAD_LOCAL std::string output; // static only for speed - output = ""; + static VL_THREAD_LOCAL std::string t_output; // static only for speed + t_output = ""; va_list ap; va_start(ap, formatp); - _vl_vsformat(output, formatp, ap); + _vl_vsformat(t_output, formatp, ap); va_end(ap); - VerilatedImp::fdWrite(fpi, output); + VerilatedImp::fdWrite(fpi, t_output); } IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE { @@ -1648,12 +1646,12 @@ IData VL_VALUEPLUSARGS_INN(int, const std::string& ld, std::string& rdr) VL_MT_S const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE { const std::string& match = VerilatedImp::argPlusMatch(prefixp); - static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH]; + static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH]; if (match.empty()) return nullptr; - outstr[0] = '\0'; - strncat(outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+" + t_outstr[0] = '\0'; + strncat(t_outstr, match.c_str() + strlen(prefixp) + 1, // +1 to skip the "+" VL_VALUE_STRING_MAX_WIDTH - 1); - return outstr; + return t_outstr; } //=========================================================================== @@ -1759,31 +1757,31 @@ const char* vl_dumpctl_filenamep(bool setit, const std::string& filename) VL_MT_ static const char* memhFormat(int nBits) { assert((nBits >= 1) && (nBits <= 32)); - static VL_THREAD_LOCAL char buf[32]; + static VL_THREAD_LOCAL char t_buf[32]; switch ((nBits - 1) / 4) { - case 0: VL_SNPRINTF(buf, 32, "%%01x"); break; - case 1: VL_SNPRINTF(buf, 32, "%%02x"); break; - case 2: VL_SNPRINTF(buf, 32, "%%03x"); break; - case 3: VL_SNPRINTF(buf, 32, "%%04x"); break; - case 4: VL_SNPRINTF(buf, 32, "%%05x"); break; - case 5: VL_SNPRINTF(buf, 32, "%%06x"); break; - case 6: VL_SNPRINTF(buf, 32, "%%07x"); break; - case 7: VL_SNPRINTF(buf, 32, "%%08x"); break; + case 0: VL_SNPRINTF(t_buf, 32, "%%01x"); break; + case 1: VL_SNPRINTF(t_buf, 32, "%%02x"); break; + case 2: VL_SNPRINTF(t_buf, 32, "%%03x"); break; + case 3: VL_SNPRINTF(t_buf, 32, "%%04x"); break; + case 4: VL_SNPRINTF(t_buf, 32, "%%05x"); break; + case 5: VL_SNPRINTF(t_buf, 32, "%%06x"); break; + case 6: VL_SNPRINTF(t_buf, 32, "%%07x"); break; + case 7: VL_SNPRINTF(t_buf, 32, "%%08x"); break; default: assert(false); break; // LCOV_EXCL_LINE } - return buf; + return t_buf; } static const char* formatBinary(int nBits, vluint32_t bits) { assert((nBits >= 1) && (nBits <= 32)); - static VL_THREAD_LOCAL char buf[64]; + static VL_THREAD_LOCAL char t_buf[64]; for (int i = 0; i < nBits; i++) { bool isOne = bits & (1 << (nBits - 1 - i)); - buf[i] = (isOne ? '1' : '0'); + t_buf[i] = (isOne ? '1' : '0'); } - buf[nBits] = '\0'; - return buf; + t_buf[nBits] = '\0'; + return t_buf; } VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData start, QData end) @@ -2202,11 +2200,8 @@ void VL_TIMEFORMAT_IINI(int units, int precision, const std::string& suffix, //=========================================================================== // Verilated:: Methods -Verilated::ThreadLocal::ThreadLocal() {} -Verilated::ThreadLocal::~ThreadLocal() {} - void Verilated::debug(int level) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_debug = level; if (level) { #ifdef VL_DEBUG @@ -2220,49 +2215,65 @@ void Verilated::debug(int level) VL_MT_SAFE { } } void Verilated::randReset(int val) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_randReset = val; } void Verilated::randSeed(int val) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_randSeed = val; + vluint64_t newEpoch = s_s.s_randSeedEpoch + 1; + if (VL_UNLIKELY(newEpoch == 0)) newEpoch = 1; + // Obververs must see new epoch AFTER seed updated +#ifdef VL_THREADED + std::atomic_signal_fence(std::memory_order_release); +#endif + s_s.s_randSeedEpoch = newEpoch; +} +vluint64_t Verilated::randSeedDefault64() VL_MT_SAFE { + if (Verilated::randSeed() != 0) { + return ((static_cast(Verilated::randSeed()) << 32) + ^ (static_cast(Verilated::randSeed()))); + } else { + return ((static_cast(vl_sys_rand32()) << 32) + ^ (static_cast(vl_sys_rand32()))); + } } void Verilated::calcUnusedSigs(bool flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_calcUnusedSigs = flag; } void Verilated::errorCount(int val) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_errorCount = val; } void Verilated::errorCountInc() VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); ++s_s.s_errorCount; } void Verilated::errorLimit(int val) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_errorLimit = val; } void Verilated::gotFinish(bool flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_gotFinish = flag; } void Verilated::assertOn(bool flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_assertOn = flag; } void Verilated::fatalOnVpiError(bool flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_fatalOnVpiError = flag; } void Verilated::timeunit(int value) VL_MT_SAFE { if (value < 0) value = -value; // Stored as 0..15 - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_timeunit = value; } void Verilated::timeprecision(int value) VL_MT_SAFE { if (value < 0) value = -value; // Stored as 0..15 - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_s.s_timeprecision = value; #ifdef SYSTEMC_VERSION sc_time sc_res = sc_get_time_resolution(); @@ -2293,15 +2304,15 @@ void Verilated::timeprecision(int value) VL_MT_SAFE { #endif } void Verilated::profThreadsStart(vluint64_t flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_ns.s_profThreadsStart = flag; } void Verilated::profThreadsWindow(vluint64_t flag) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); s_ns.s_profThreadsWindow = flag; } void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); + const VerilatedLockGuard lock(s_mutex); if (s_ns.s_profThreadsFilenamep) free(const_cast(s_ns.s_profThreadsFilenamep)); s_ns.s_profThreadsFilenamep = strdup(flagp); } @@ -2309,18 +2320,18 @@ void Verilated::profThreadsFilenamep(const char* flagp) VL_MT_SAFE { const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE { // Returns new'ed data // Used by symbol table creation to make module names - static VL_THREAD_LOCAL char* strp = nullptr; - static VL_THREAD_LOCAL size_t len = 0; + static VL_THREAD_LOCAL char* t_strp = nullptr; + static VL_THREAD_LOCAL size_t t_len = 0; size_t newlen = strlen(n1) + strlen(n2) + strlen(delimiter) + 1; - if (!strp || newlen > len) { - if (strp) delete[] strp; - strp = new char[newlen]; - len = newlen; + if (!t_strp || newlen > t_len) { + if (t_strp) delete[] t_strp; + t_strp = new char[newlen]; + t_len = newlen; } - strcpy(strp, n1); - if (*n1) strcat(strp, delimiter); - strcat(strp, n2); - return strp; + strcpy(t_strp, n1); + if (*n1) strcat(t_strp, delimiter); + strcat(t_strp, n2); + return t_strp; } //========================================================================= @@ -2329,8 +2340,8 @@ const char* Verilated::catName(const char* n1, const char* n2, const char* delim // Keeping these out of class Verilated to avoid having to include // in verilated.h (for compilation speed) typedef std::list> VoidPCbList; -static VoidPCbList g_flushCbs; -static VoidPCbList g_exitCbs; +static VoidPCbList s_flushCbs; +static VoidPCbList s_exitCbs; static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) { std::pair pair(cb, datap); @@ -2346,16 +2357,16 @@ static void runCallbacks(VoidPCbList& cbs) VL_MT_SAFE { } void Verilated::addFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - addCb(cb, datap, g_flushCbs); + const VerilatedLockGuard lock(s_mutex); + addCb(cb, datap, s_flushCbs); } void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - removeCb(cb, datap, g_flushCbs); + const VerilatedLockGuard lock(s_mutex); + removeCb(cb, datap, s_flushCbs); } void Verilated::runFlushCallbacks() VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - runCallbacks(g_flushCbs); + const VerilatedLockGuard lock(s_mutex); + runCallbacks(s_flushCbs); fflush(stderr); fflush(stdout); // When running internal code coverage (gcc --coverage, as opposed to @@ -2365,16 +2376,16 @@ void Verilated::runFlushCallbacks() VL_MT_SAFE { } void Verilated::addExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - addCb(cb, datap, g_exitCbs); + const VerilatedLockGuard lock(s_mutex); + addCb(cb, datap, s_exitCbs); } void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - removeCb(cb, datap, g_exitCbs); + const VerilatedLockGuard lock(s_mutex); + removeCb(cb, datap, s_exitCbs); } void Verilated::runExitCallbacks() VL_MT_SAFE { - const VerilatedLockGuard lock(m_mutex); - runCallbacks(g_exitCbs); + const VerilatedLockGuard lock(s_mutex); + runCallbacks(s_exitCbs); } const char* Verilated::productName() VL_PURE { return VERILATOR_PRODUCT; } @@ -2389,11 +2400,11 @@ void Verilated::commandArgs(int argc, const char** argv) VL_MT_SAFE { const char* Verilated::commandArgsPlusMatch(const char* prefixp) VL_MT_SAFE { const std::string& match = VerilatedImp::argPlusMatch(prefixp); - static VL_THREAD_LOCAL char outstr[VL_VALUE_STRING_MAX_WIDTH]; + static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH]; if (match.empty()) return ""; - outstr[0] = '\0'; - strncat(outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1); - return outstr; + t_outstr[0] = '\0'; + strncat(t_outstr, match.c_str(), VL_VALUE_STRING_MAX_WIDTH - 1); + return t_outstr; } void Verilated::nullPointerError(const char* filename, int linenum) VL_MT_SAFE { @@ -2648,8 +2659,6 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const //====================================================================== // VerilatedScope:: Methods -VerilatedScope::VerilatedScope() {} - VerilatedScope::~VerilatedScope() { // Memory cleanup - not called during normal operation VerilatedImp::scopeErase(this); diff --git a/include/verilated.h b/include/verilated.h index 9d339d8db..d8e8badb0 100644 --- a/include/verilated.h +++ b/include/verilated.h @@ -129,12 +129,12 @@ extern vluint32_t VL_THREAD_ID() VL_MT_SAFE; #define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before relaxing /// Mutex, wrapped to allow -fthread_safety checks -class VL_CAPABILITY("mutex") VerilatedMutex { +class VL_CAPABILITY("mutex") VerilatedMutex final { private: std::mutex m_mutex; // Mutex public: - VerilatedMutex() {} - ~VerilatedMutex() {} + VerilatedMutex() = default; + ~VerilatedMutex() = default; const VerilatedMutex& operator!() const { return *this; } // For -fthread_safety /// Acquire/lock mutex void lock() VL_ACQUIRE() { @@ -155,7 +155,7 @@ public: }; /// Lock guard for mutex (ala std::unique_lock), wrapped to allow -fthread_safety checks -class VL_SCOPED_CAPABILITY VerilatedLockGuard { +class VL_SCOPED_CAPABILITY VerilatedLockGuard final { VL_UNCOPYABLE(VerilatedLockGuard); private: @@ -174,19 +174,19 @@ public: #else // !VL_THREADED /// Empty non-threaded mutex to avoid #ifdefs in consuming code -class VerilatedMutex { +class VerilatedMutex final { public: void lock() {} void unlock() {} }; /// Empty non-threaded lock guard to avoid #ifdefs in consuming code -class VerilatedLockGuard { +class VerilatedLockGuard final { VL_UNCOPYABLE(VerilatedLockGuard); public: explicit VerilatedLockGuard(VerilatedMutex&) {} - ~VerilatedLockGuard() {} + ~VerilatedLockGuard() = default; void lock() {} void unlock() {} }; @@ -194,7 +194,7 @@ public: #endif // VL_THREADED /// Remember the calling thread at construction time, and make sure later calls use same thread -class VerilatedAssertOneThread { +class VerilatedAssertOneThread final { // MEMBERS #if defined(VL_THREADED) && defined(VL_DEBUG) vluint32_t m_threadid; /// Thread that is legal @@ -230,7 +230,7 @@ public: class VerilatedScope; -class VerilatedModule { +class VerilatedModule VL_NOT_FINAL { VL_UNCOPYABLE(VerilatedModule); private: @@ -269,7 +269,8 @@ public: #define VL_CELL(instname, type) ///< Declare a cell, ala SP_CELL /// Declare a module, ala SC_MODULE -#define VL_MODULE(modname) class modname : public VerilatedModule +#define VL_MODULE(modname) class modname VL_NOT_FINAL : public VerilatedModule +// Not class final in VL_MODULE, as users might be abstracting our models (--hierarchical) /// Constructor, ala SC_CTOR #define VL_CTOR(modname) modname(const char* __VCname = "") @@ -298,7 +299,7 @@ public: //=========================================================================== /// Verilator symbol table base class -class VerilatedSyms { +class VerilatedSyms VL_NOT_FINAL { public: // But for internal use only #ifdef VL_THREADED VerilatedEvalMsgQueue* __Vm_evalMsgQp; @@ -311,7 +312,7 @@ public: // But for internal use only /// Verilator global class information class /// This class is initialized by main thread only. Reading post-init is thread safe. -class VerilatedScope { +class VerilatedScope final { public: typedef enum : vluint8_t { SCOPE_MODULE, @@ -330,7 +331,7 @@ private: Type m_type = SCOPE_OTHER; ///< Type of the scope public: // But internals only - called from VerilatedModule's - VerilatedScope(); + VerilatedScope() = default; ~VerilatedScope(); void configure(VerilatedSyms* symsp, const char* prefixp, const char* suffixp, const char* identifier, vlsint8_t timeunit, const Type& type) VL_MT_UNSAFE; @@ -359,7 +360,7 @@ public: // But internals only - called from VerilatedModule's Type type() const { return m_type; } }; -class VerilatedHierarchy { +class VerilatedHierarchy final { public: static void add(VerilatedScope* fromp, VerilatedScope* top); }; @@ -367,10 +368,10 @@ public: //=========================================================================== /// Verilator global static information class -class Verilated { +class Verilated final { // MEMBERS // Slow path variables - static VerilatedMutex m_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED + static VerilatedMutex s_mutex; ///< Mutex for s_s/s_ns members, when VL_THREADED static struct Serialized { // All these members serialized/deserialized // Fast path @@ -386,8 +387,9 @@ class Verilated { int s_errorLimit; ///< Stop on error number int s_randReset; ///< Random reset: 0=all 0s, 1=all 1s, 2=random int s_randSeed; ///< Random seed: 0=random + int s_randSeedEpoch; ///< Number incrementing on each reseed, 0=illegal Serialized(); - ~Serialized() {} + ~Serialized() = default; } s_s; static struct NonSerialized { // Non-serialized information @@ -407,8 +409,8 @@ class Verilated { VerilatedMutex m_argMutex; ///< Mutex for s_args members, when VL_THREADED int argc = 0; const char** argv = nullptr; - CommandArgValues() {} - ~CommandArgValues() {} + CommandArgValues() = default; + ~CommandArgValues() = default; } s_args; // Not covered by mutex, as per-thread @@ -422,8 +424,8 @@ class Verilated { const char* t_dpiFilename = nullptr; ///< DPI context filename int t_dpiLineno = 0; ///< DPI context line number - ThreadLocal(); - ~ThreadLocal(); + ThreadLocal() = default; + ~ThreadLocal() = default; } t_s; private: @@ -442,6 +444,9 @@ public: static int randReset() VL_MT_SAFE { return s_s.s_randReset; } ///< Return randReset value static void randSeed(int val) VL_MT_SAFE; static int randSeed() VL_MT_SAFE { return s_s.s_randSeed; } ///< Return randSeed value + static vluint32_t randSeedEpoch() VL_MT_SAFE { return s_s.s_randSeedEpoch; } + /// Random seed extended to 64 bits, and defaulted if user seed==0 + static vluint64_t randSeedDefault64() VL_MT_SAFE; /// Enable debug of internal verilated code static void debug(int level) VL_MT_SAFE; @@ -452,7 +457,7 @@ public: static inline int debug() VL_MT_SAFE { return s_s.s_debug; } #else /// Return constant 0 debug level, so C++'s optimizer rips up - static inline int debug() VL_PURE { return 0; } + static constexpr int debug() VL_PURE { return 0; } #endif /// Enable calculation of unused signals static void calcUnusedSigs(bool flag) VL_MT_SAFE; @@ -567,8 +572,8 @@ public: static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; } static int exportFuncNum(const char* namep) VL_MT_SAFE; - static size_t serialized1Size() VL_PURE { return sizeof(s_s); } - static void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // Unsafe, for Serialize only + static constexpr size_t serialized1Size() VL_PURE { return sizeof(s_s); } + static constexpr void* serialized1Ptr() VL_MT_UNSAFE { return &s_s; } // For Serialize only static size_t serialized2Size() VL_PURE; static void* serialized2Ptr() VL_MT_UNSAFE; #ifdef VL_THREADED @@ -648,6 +653,7 @@ extern vluint64_t vl_rand64() VL_MT_SAFE; inline IData VL_RANDOM_I(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_I(obits); } inline QData VL_RANDOM_Q(int obits) VL_MT_SAFE { return vl_rand64() & VL_MASK_Q(obits); } extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp); ///< Randomize a signal +extern IData VL_RANDOM_SEEDED_II(int obits, IData seed) VL_MT_SAFE; inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) { vluint64_t rnd = vl_rand64(); if (VL_LIKELY(hi > lo)) { @@ -753,9 +759,9 @@ static inline void* VL_CVT_Q_VP(QData lhs) VL_PURE { u.q = lhs; return u.fp; } -/// Return QData from void* -static inline QData VL_CVT_VP_Q(void* fp) VL_PURE { - union { void* fp; QData q; } u; +/// Return QData from const void* +static inline QData VL_CVT_VP_Q(const void* fp) VL_PURE { + union { const void* fp; QData q; } u; u.q = 0; u.fp = fp; return u.q; diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp index 753e550cb..45f111cd9 100644 --- a/include/verilated_cov.cpp +++ b/include/verilated_cov.cpp @@ -29,7 +29,7 @@ // VerilatedCovImpBase /// Implementation base class for constants -struct VerilatedCovImpBase { +struct VerilatedCovImpBase VL_NOT_FINAL { // TYPES enum { MAX_KEYS = 33 }; /// Maximum user arguments + filename+lineno enum { KEY_UNDEF = 0 }; /// Magic key # for unspecified values @@ -39,7 +39,7 @@ struct VerilatedCovImpBase { // VerilatedCovImpItem /// Implementation class for a VerilatedCov item -class VerilatedCovImpItem : VerilatedCovImpBase { +class VerilatedCovImpItem VL_NOT_FINAL : VerilatedCovImpBase { public: // But only local to this file // MEMBERS int m_keys[MAX_KEYS]; ///< Key @@ -52,7 +52,7 @@ public: // But only local to this file m_vals[i] = 0; } } - virtual ~VerilatedCovImpItem() {} + virtual ~VerilatedCovImpItem() = default; virtual vluint64_t count() const = 0; virtual void zero() const = 0; }; @@ -63,7 +63,7 @@ public: // But only local to this file /// This isn't in the header file for auto-magic conversion because it /// inlines to too much code and makes compilation too slow. -template class VerilatedCoverItemSpec : public VerilatedCovImpItem { +template class VerilatedCoverItemSpec final : public VerilatedCovImpItem { private: // MEMBERS T* m_countp; ///< Count value @@ -78,7 +78,7 @@ public: : m_countp{countp} { *m_countp = 0; } - virtual ~VerilatedCoverItemSpec() override {} + virtual ~VerilatedCoverItemSpec() override = default; }; //============================================================================= @@ -87,7 +87,7 @@ public: /// All value and keys are indexed into a unique number. Thus we can greatly reduce /// the storage requirements for otherwise identical keys. -class VerilatedCovImp : VerilatedCovImpBase { +class VerilatedCovImp final : VerilatedCovImpBase { private: // TYPES typedef std::map ValueIndexMap; @@ -99,13 +99,14 @@ private: 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 ItemList m_items VL_GUARDED_BY(m_mutex); ///< List of all items + int m_nextIndex VL_GUARDED_BY(m_mutex) = (KEY_UNDEF + 1); ///< Next insert value VerilatedCovImpItem* m_insertp VL_GUARDED_BY(m_mutex) = nullptr; ///< Item about to insert const char* m_insertFilenamep VL_GUARDED_BY(m_mutex) = nullptr; ///< Filename about to insert int m_insertLineno VL_GUARDED_BY(m_mutex) = 0; ///< Line number about to insert // CONSTRUCTORS - VerilatedCovImp() {} + VerilatedCovImp() = default; VL_UNCOPYABLE(VerilatedCovImp); public: @@ -118,14 +119,13 @@ public: private: // PRIVATE METHODS int valueIndex(const std::string& value) VL_REQUIRES(m_mutex) { - static int nextIndex = KEY_UNDEF + 1; const auto iter = m_valueIndexes.find(value); if (iter != m_valueIndexes.end()) return iter->second; - nextIndex++; - assert(nextIndex > 0); // Didn't rollover - m_valueIndexes.insert(std::make_pair(value, nextIndex)); - m_indexValues.insert(std::make_pair(nextIndex, value)); - return nextIndex; + m_nextIndex++; + assert(m_nextIndex > 0); // Didn't rollover + m_valueIndexes.insert(std::make_pair(value, m_nextIndex)); + m_indexValues.insert(std::make_pair(m_nextIndex, value)); + return m_nextIndex; } static std::string dequote(const std::string& text) VL_PURE { // Quote any special characters @@ -235,6 +235,7 @@ private: m_items.clear(); m_indexValues.clear(); m_valueIndexes.clear(); + m_nextIndex = KEY_UNDEF + 1; } public: @@ -399,7 +400,7 @@ public: os << i.first; if (!i.second.first.empty()) os << keyValueFormatter(VL_CIK_HIER, i.second.first); os << "' " << i.second.second; - os << std::endl; + os << '\n'; } } }; diff --git a/include/verilated_cov.h b/include/verilated_cov.h index aef8eda67..331eed6c8 100644 --- a/include/verilated_cov.h +++ b/include/verilated_cov.h @@ -88,7 +88,7 @@ template std::string vlCovCvtToStr(const T& t) VL_PURE { /// Global class with methods affecting all coverage data. /// All public methods in this class are thread safe. -class VerilatedCov { +class VerilatedCov final { VL_UNCOPYABLE(VerilatedCov); public: diff --git a/include/verilated_cov_key.h b/include/verilated_cov_key.h index d4788d435..9a184a518 100644 --- a/include/verilated_cov_key.h +++ b/include/verilated_cov_key.h @@ -102,7 +102,7 @@ VLCOVGEN_ITEM("name=>'weight', short=>'w', group=>0, default=>undef, descr /// Verilator coverage global class. /// This class is thread safe. -class VerilatedCovKey { +class VerilatedCovKey final { public: static std::string shortKey(const std::string& key) VL_PURE { // VLCOVGEN_SHORT_AUTO_EDIT_BEGIN diff --git a/include/verilated_fst_c.h b/include/verilated_fst_c.h index f4aaf08ec..a4c4a779c 100644 --- a/include/verilated_fst_c.h +++ b/include/verilated_fst_c.h @@ -35,7 +35,7 @@ /// Base class to create a Verilator FST dump /// This is an internally used class - see VerilatedFstC for what to call from applications -class VerilatedFst : public VerilatedTrace { +class VerilatedFst final : public VerilatedTrace { private: // Give the superclass access to private bits (to avoid virtual functions) friend class VerilatedTrace; @@ -128,7 +128,7 @@ template <> void VerilatedTrace::set_time_resolution(const std::st /// Also derived for use in SystemC simulations. /// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE -class VerilatedFstC { +class VerilatedFstC final { VerilatedFst m_sptrace; ///< Trace file being created // CONSTRUCTORS diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h index 0c4d2eb83..0fd47d274 100644 --- a/include/verilated_heavy.h +++ b/include/verilated_heavy.h @@ -32,6 +32,7 @@ #include #include #include +#include //=================================================================== // String formatters (required by below containers) @@ -46,7 +47,7 @@ extern std::string VL_TO_STRING_W(int words, WDataInP obj); //=================================================================== // Shuffle RNG -class VlURNG { +class VlURNG final { public: typedef size_t result_type; static constexpr size_t min() { return 0; } @@ -57,7 +58,7 @@ public: //=================================================================== // Readmem/Writemem operation classes -class VlReadMem { +class VlReadMem final { bool m_hex; // Hex format int m_bits; // Bit width of values const std::string& m_filename; // Filename @@ -74,7 +75,7 @@ public: void setData(void* valuep, const std::string& rhs); }; -class VlWriteMem { +class VlWriteMem final { bool m_hex; // Hex format int m_bits; // Bit width of values FILE* m_fp; // File handle for filename @@ -93,7 +94,7 @@ public: // // Bound here is the maximum size() allowed, e.g. 1 + SystemVerilog bound // For dynamic arrays it is always zero -template class VlQueue { +template class VlQueue final { private: // TYPES typedef std::deque Deque; @@ -108,10 +109,13 @@ private: public: // CONSTRUCTORS - VlQueue() { - // m_defaultValue isn't defaulted. Caller's constructor must do it. - } - ~VlQueue() {} + // m_defaultValue isn't defaulted. Caller's constructor must do it. + VlQueue() = default; + ~VlQueue() = default; + VlQueue(const VlQueue&) = default; + VlQueue(VlQueue&&) = default; + VlQueue& operator=(const VlQueue&) = default; + VlQueue& operator=(VlQueue&&) = default; // Standard copy constructor works. Verilog: assoca = assocb // Also must allow conversion from a different T_MaxSize queue @@ -150,6 +154,7 @@ public: // METHODS T_Value& atDefault() { return m_defaultValue; } + const T_Value& atDefault() const { return m_defaultValue; } const Deque& privateDeque() const { return m_deque; } // Size. Verilog: function int size(), or int num() @@ -247,20 +252,24 @@ public: void sort() { std::sort(m_deque.begin(), m_deque.end()); } template void sort(Func with_func) { // with_func returns arbitrary type to use for the sort comparison - std::sort(m_deque.begin(), m_deque.end(), - [=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); }); + std::sort(m_deque.begin(), m_deque.end(), [=](const T_Value& a, const T_Value& b) { + // index number is meaninless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); } void rsort() { std::sort(m_deque.rbegin(), m_deque.rend()); } template void rsort(Func with_func) { // with_func returns arbitrary type to use for the sort comparison - std::sort(m_deque.rbegin(), m_deque.rend(), - [=](const T_Value& a, const T_Value& b) { return with_func(a) < with_func(b); }); + std::sort(m_deque.rbegin(), m_deque.rend(), [=](const T_Value& a, const T_Value& b) { + // index number is meaninless with sort, as it changes + return with_func(0, a) < with_func(0, b); + }); } void reverse() { std::reverse(m_deque.begin(), m_deque.end()); } void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG()); } VlQueue unique() const { VlQueue out; - std::set saw; + std::unordered_set saw; for (const auto& i : m_deque) { auto it = saw.find(i); if (it == saw.end()) { @@ -273,7 +282,7 @@ public: VlQueue unique_index() const { VlQueue out; IData index = 0; - std::set saw; + std::unordered_set saw; for (const auto& i : m_deque) { auto it = saw.find(i); if (it == saw.end()) { @@ -286,39 +295,54 @@ public: } template VlQueue find(Func with_func) const { VlQueue out; - for (const auto& i : m_deque) - if (with_func(i)) out.push_back(i); + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) out.push_back(i); + ++index; + } return out; } template VlQueue find_index(Func with_func) const { VlQueue out; IData index = 0; for (const auto& i : m_deque) { - if (with_func(i)) out.push_back(index); + if (with_func(index, i)) out.push_back(index); ++index; } return out; } template VlQueue find_first(Func with_func) const { - const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); - if (it == m_deque.end()) return VlQueue{}; - return VlQueue::cons(*it); + // Can't use std::find_if as need index number + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) return VlQueue::cons(i); + ++index; + } + return VlQueue{}; } template VlQueue find_first_index(Func with_func) const { - const auto it = std::find_if(m_deque.begin(), m_deque.end(), with_func); - if (it == m_deque.end()) return VlQueue{}; - return VlQueue::cons(std::distance(m_deque.begin(), it)); + IData index = 0; + for (const auto& i : m_deque) { + if (with_func(index, i)) return VlQueue::cons(index); + ++index; + } + return VlQueue{}; } template VlQueue find_last(Func with_func) const { - const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); - if (it == m_deque.rend()) return VlQueue{}; - return VlQueue::cons(*it); + IData index = m_deque.size() - 1; + for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { + if (with_func(index, *it)) return VlQueue::cons(*it); + --index; + } + return VlQueue{}; } template VlQueue find_last_index(Func with_func) const { - const auto it = std::find_if(m_deque.rbegin(), m_deque.rend(), with_func); - if (it == m_deque.rend()) return VlQueue{}; - // Return index must be relative to beginning - return VlQueue::cons(m_deque.size() - 1 - std::distance(m_deque.rbegin(), it)); + IData index = m_deque.size() - 1; + for (auto it = m_deque.rbegin(); it != m_deque.rend(); ++it) { + if (with_func(index, *it)) return VlQueue::cons(index); + --index; + } + return VlQueue{}; } // Reduction operators @@ -340,7 +364,8 @@ public: } template T_Value r_sum(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out += with_func(i); + IData index = 0; + for (const auto& i : m_deque) out += with_func(index++, i); return out; } T_Value r_product() const { @@ -354,9 +379,11 @@ public: template T_Value r_product(Func with_func) const { if (m_deque.empty()) return T_Value(0); auto it = m_deque.begin(); - T_Value out{with_func(*it)}; + IData index = 0; + T_Value out{with_func(index, *it)}; ++it; - for (; it != m_deque.end(); ++it) out *= with_func(*it); + ++index; + for (; it != m_deque.end(); ++it) out *= with_func(index++, *it); return out; } T_Value r_and() const { @@ -370,9 +397,11 @@ public: template T_Value r_and(Func with_func) const { if (m_deque.empty()) return T_Value(0); auto it = m_deque.begin(); - T_Value out{with_func(*it)}; + IData index = 0; + T_Value out{with_func(index, *it)}; ++it; - for (; it != m_deque.end(); ++it) out &= with_func(*it); + ++index; + for (; it != m_deque.end(); ++it) out &= with_func(index, *it); return out; } T_Value r_or() const { @@ -382,7 +411,8 @@ public: } template T_Value r_or(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out |= with_func(i); + IData index = 0; + for (const auto& i : m_deque) out |= with_func(index++, i); return out; } T_Value r_xor() const { @@ -392,7 +422,8 @@ public: } template T_Value r_xor(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_deque) out ^= with_func(i); + IData index = 0; + for (const auto& i : m_deque) out ^= with_func(index++, i); return out; } @@ -421,13 +452,18 @@ template std::string VL_TO_STRING(const VlQueue& obj) { // This is only used when we need an upper-level container and so can't // simply use a C style array (which is just a pointer). -template class VlWide { +template class VlWide final { WData m_storage[T_Words]; public: // cppcheck-suppress uninitVar - VlWide() {} - ~VlWide() {} + VlWide() = default; + ~VlWide() = default; + VlWide(const VlWide&) = default; + VlWide(VlWide&&) = default; + VlWide& operator=(const VlWide&) = default; + VlWide& operator=(VlWide&&) = default; + // METHODS const WData& at(size_t index) const { return m_storage[index]; } WData& at(size_t index) { return m_storage[index]; } WData* data() { return &m_storage[0]; } @@ -452,7 +488,7 @@ template std::string VL_TO_STRING(const VlWide& o // There are no multithreaded locks on this; the base variable must // be protected by other means // -template class VlAssocArray { +template class VlAssocArray final { private: // TYPES typedef std::map Map; @@ -467,14 +503,17 @@ private: public: // CONSTRUCTORS - VlAssocArray() { - // m_defaultValue isn't defaulted. Caller's constructor must do it. - } - ~VlAssocArray() {} - // Standard copy constructor works. Verilog: assoca = assocb + // m_defaultValue isn't defaulted. Caller's constructor must do it. + VlAssocArray() = default; + ~VlAssocArray() = default; + VlAssocArray(const VlAssocArray&) = default; + VlAssocArray(VlAssocArray&&) = default; + VlAssocArray& operator=(const VlAssocArray&) = default; + VlAssocArray& operator=(VlAssocArray&&) = default; // METHODS T_Value& atDefault() { return m_defaultValue; } + const T_Value& atDefault() const { return m_defaultValue; } // Size of array. Verilog: function int size(), or int num() int size() const { return m_map.size(); } @@ -578,19 +617,19 @@ public: template VlQueue find(Func with_func) const { VlQueue out; for (const auto& i : m_map) - if (with_func(i.second)) out.push_back(i.second); + if (with_func(i.first, i.second)) out.push_back(i.second); return out; } template VlQueue find_index(Func with_func) const { VlQueue out; for (const auto& i : m_map) - if (with_func(i.second)) out.push_back(i.first); + if (with_func(i.first, i.second)) out.push_back(i.first); return out; } template VlQueue find_first(Func with_func) const { const auto it = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.end()) return VlQueue{}; return VlQueue::cons(it->second); @@ -598,7 +637,7 @@ public: template VlQueue find_first_index(Func with_func) const { const auto it = std::find_if(m_map.begin(), m_map.end(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.end()) return VlQueue{}; return VlQueue::cons(it->first); @@ -606,7 +645,7 @@ public: template VlQueue find_last(Func with_func) const { const auto it = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.rend()) return VlQueue{}; return VlQueue::cons(it->second); @@ -614,7 +653,7 @@ public: template VlQueue find_last_index(Func with_func) const { const auto it = std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair& i) { - return with_func(i.second); + return with_func(i.first, i.second); }); if (it == m_map.rend()) return VlQueue{}; return VlQueue::cons(it->first); @@ -647,7 +686,7 @@ public: } template T_Value r_sum(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out += with_func(i.second); + for (const auto& i : m_map) out += with_func(i.first, i.second); return out; } T_Value r_product() const { @@ -661,9 +700,9 @@ public: template T_Value r_product(Func with_func) const { if (m_map.empty()) return T_Value(0); auto it = m_map.begin(); - T_Value out{with_func(it->second)}; + T_Value out{with_func(it->first, it->second)}; ++it; - for (; it != m_map.end(); ++it) out *= with_func(it->second); + for (; it != m_map.end(); ++it) out *= with_func(it->first, it->second); return out; } T_Value r_and() const { @@ -677,9 +716,9 @@ public: template T_Value r_and(Func with_func) const { if (m_map.empty()) return T_Value(0); auto it = m_map.begin(); - T_Value out{with_func(it->second)}; + T_Value out{with_func(it->first, it->second)}; ++it; - for (; it != m_map.end(); ++it) out &= with_func(it->second); + for (; it != m_map.end(); ++it) out &= with_func(it->first, it->second); return out; } T_Value r_or() const { @@ -689,7 +728,7 @@ public: } template T_Value r_or(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out |= with_func(i.second); + for (const auto& i : m_map) out |= with_func(i.first, i.second); return out; } T_Value r_xor() const { @@ -699,7 +738,7 @@ public: } template T_Value r_xor(Func with_func) const { T_Value out(0); // Type must have assignment operator - for (const auto& i : m_map) out ^= with_func(i.second); + for (const auto& i : m_map) out ^= with_func(i.first, i.second); return out; } @@ -773,6 +812,7 @@ inline std::string VL_CVT_PACK_STR_NQ(QData lhs) VL_PURE { return VL_CVT_PACK_STR_NW(VL_WQ_WORDS_E, lw); } inline std::string VL_CVT_PACK_STR_NN(const std::string& lhs) VL_PURE { return lhs; } +inline std::string& VL_CVT_PACK_STR_NN(std::string& lhs) VL_PURE { return lhs; } inline std::string VL_CVT_PACK_STR_NI(IData lhs) VL_PURE { WData lw[VL_WQ_WORDS_E]; VL_SET_WI(lw, lhs); diff --git a/include/verilated_imp.h b/include/verilated_imp.h index a84aa13ba..ba0993570 100644 --- a/include/verilated_imp.h +++ b/include/verilated_imp.h @@ -46,7 +46,7 @@ class VerilatedScope; #ifdef VL_THREADED /// Message, enqueued on an mtask, and consumed on the main eval thread -class VerilatedMsg { +class VerilatedMsg final { public: // TYPES struct Cmp { @@ -64,7 +64,11 @@ public: VerilatedMsg(const std::function& cb) : m_mtaskId{Verilated::mtaskId()} , m_cb{cb} {} - ~VerilatedMsg() {} + ~VerilatedMsg() = default; + VerilatedMsg(const VerilatedMsg&) = default; + VerilatedMsg(VerilatedMsg&&) = default; + VerilatedMsg& operator=(const VerilatedMsg&) = default; + VerilatedMsg& operator=(VerilatedMsg&&) = default; // METHODS vluint32_t mtaskId() const { return m_mtaskId; } /// Execute the lambda function @@ -74,7 +78,7 @@ public: /// Each thread has a queue it pushes to /// This assumes no thread starts pushing the next tick until the previous has drained. /// If more aggressiveness is needed, a double-buffered scheme might work well. -class VerilatedEvalMsgQueue { +class VerilatedEvalMsgQueue final { typedef std::multiset VerilatedThreadQueue; std::atomic m_depth; ///< Current depth of queue (see comments below) @@ -87,7 +91,7 @@ public: : m_depth{0} { assert(atomic_is_lock_free(&m_depth)); } - ~VerilatedEvalMsgQueue() {} + ~VerilatedEvalMsgQueue() = default; private: VL_UNCOPYABLE(VerilatedEvalMsgQueue); @@ -126,7 +130,7 @@ public: }; /// Each thread has a local queue to build up messages until the end of the eval() call -class VerilatedThreadMsgQueue { +class VerilatedThreadMsgQueue final { std::queue m_queue; public: @@ -170,7 +174,7 @@ public: #endif // VL_THREADED // FILE* list constructed from a file-descriptor -class VerilatedFpList { +class VerilatedFpList final { FILE* m_fp[31]; std::size_t m_sz = 0; @@ -189,7 +193,7 @@ public: //====================================================================== // VerilatedImp -class VerilatedImpData { +class VerilatedImpData final { // Whole class is internal use only - Global information shared between verilated*.cpp files. protected: friend class Verilated; @@ -207,8 +211,8 @@ protected: int m_timeFormatPrecision = 0; // $timeformat number of decimal places int m_timeFormatWidth = 20; // $timeformat character width enum { UNITS_NONE = 99 }; // Default based on precision - Serialized() {} - ~Serialized() {} + Serialized() = default; + ~Serialized() = default; } m_ser; VerilatedMutex m_sergMutex; ///< Protect m_ser @@ -260,7 +264,7 @@ protected: } }; -class VerilatedImp { +class VerilatedImp final { // Whole class is internal use only - Global information shared between verilated*.cpp files. protected: friend class Verilated; @@ -268,15 +272,15 @@ protected: // MEMBERS union VerilatedImpU { ///< Enclose in an union to call ctor/dtor manually VerilatedImpData v; - VerilatedImpU() {} - ~VerilatedImpU() {} + VerilatedImpU() {} // Can't be = default; + ~VerilatedImpU() {} // Can't be = default; }; static VerilatedImpU s_s; ///< Static Singleton; One and only static this public: // But only for verilated*.cpp // CONSTRUCTORS - VerilatedImp() {} - ~VerilatedImp() {} + VerilatedImp() = default; + ~VerilatedImp() = default; static void setup(); static void teardown(); diff --git a/include/verilated_save.h b/include/verilated_save.h index adc65fa8d..bb40d86fc 100644 --- a/include/verilated_save.h +++ b/include/verilated_save.h @@ -28,7 +28,7 @@ // VerilatedSerialize - convert structures to a stream representation // This class is not thread safe, it must be called by a single thread -class VerilatedSerialize { +class VerilatedSerialize VL_NOT_FINAL { protected: // MEMBERS // For speed, keep m_cp as the first member of this structure @@ -38,8 +38,8 @@ protected: std::string m_filename; ///< Filename, for error messages VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread - inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation - inline static size_t bufferInsertSize() { return 16 * 1024; } + static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation + static constexpr size_t bufferInsertSize() { return 16 * 1024; } void header() VL_MT_UNSAFE_ONE; void trailer() VL_MT_UNSAFE_ONE; @@ -87,7 +87,7 @@ private: // VerilatedDeserial - load structures from a stream representation // This class is not thread safe, it must be called by a single thread -class VerilatedDeserialize { +class VerilatedDeserialize VL_NOT_FINAL { protected: // MEMBERS // For speed, keep m_cp as the first member of this structure @@ -98,8 +98,8 @@ protected: std::string m_filename; ///< Filename, for error messages VerilatedAssertOneThread m_assertOne; ///< Assert only called from single thread - inline static size_t bufferSize() { return 256 * 1024; } // See below for slack calculation - inline static size_t bufferInsertSize() { return 16 * 1024; } + static constexpr size_t bufferSize() { return 256 * 1024; } // See below for slack calculation + static constexpr size_t bufferInsertSize() { return 16 * 1024; } virtual void fill() = 0; void header() VL_MT_UNSAFE_ONE; @@ -154,13 +154,13 @@ private: // VerilatedSave - serialize to a file // This class is not thread safe, it must be called by a single thread -class VerilatedSave : public VerilatedSerialize { +class VerilatedSave final : public VerilatedSerialize { private: int m_fd = -1; ///< File descriptor we're writing to public: // CONSTRUCTORS - VerilatedSave() {} + VerilatedSave() = default; virtual ~VerilatedSave() override { close(); } // METHODS /// Open the file; call isOpen() to see if errors @@ -174,13 +174,13 @@ public: // VerilatedRestore - deserialize from a file // This class is not thread safe, it must be called by a single thread -class VerilatedRestore : public VerilatedDeserialize { +class VerilatedRestore final : public VerilatedDeserialize { private: int m_fd = -1; ///< File descriptor we're writing to public: // CONSTRUCTORS - VerilatedRestore() {} + VerilatedRestore() = default; virtual ~VerilatedRestore() override { close(); } // METHODS diff --git a/include/verilated_sc.h b/include/verilated_sc.h index b250d224b..a807b8302 100644 --- a/include/verilated_sc.h +++ b/include/verilated_sc.h @@ -34,7 +34,7 @@ // This class is thread safe (though most of SystemC is not). #define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv)) -class VlScBvExposer : public sc_bv_base { +class VlScBvExposer final : public sc_bv_base { public: static const vluint32_t* sp_datap(const sc_bv_base& base) VL_MT_SAFE { return static_cast(&base)->sp_datatp(); diff --git a/include/verilated_sym_props.h b/include/verilated_sym_props.h index ca2689108..2df07855e 100644 --- a/include/verilated_sym_props.h +++ b/include/verilated_sym_props.h @@ -36,16 +36,14 @@ /// Thread safety: Assume is constructed only with model, then any number of readers // See also V3Ast::VNumRange -class VerilatedRange { - int m_left; - int m_right; +class VerilatedRange final { + int m_left = 0; + int m_right = 0; protected: friend class VerilatedVarProps; friend class VerilatedScope; - VerilatedRange() - : m_left{0} - , m_right{0} {} + VerilatedRange() = default; VerilatedRange(int left, int right) : m_left{left} , m_right{right} {} @@ -55,7 +53,7 @@ protected: } public: - ~VerilatedRange() {} + ~VerilatedRange() = default; int left() const { return m_left; } int right() const { return m_right; } int low() const { return (m_left < m_right) ? m_left : m_right; } @@ -70,7 +68,7 @@ public: /// Verilator variable /// Thread safety: Assume is constructed only with model, then any number of readers -class VerilatedVarProps { +class VerilatedVarProps VL_NOT_FINAL { // TYPES enum { MAGIC = 0xddc4f829 }; // MEMBERS @@ -138,7 +136,7 @@ public: } public: - ~VerilatedVarProps() {} + ~VerilatedVarProps() = default; // METHODS bool magicOk() const { return m_magic == MAGIC; } VerilatedVarType vltype() const { return m_vltype; } @@ -189,7 +187,7 @@ public: //=========================================================================== /// Verilator DPI open array variable -class VerilatedDpiOpenVar { +class VerilatedDpiOpenVar final { // MEMBERS const VerilatedVarProps* m_propsp; // Variable properties void* m_datap; // Location of data (local to thread always, so safe) @@ -201,7 +199,7 @@ public: VerilatedDpiOpenVar(const VerilatedVarProps* propsp, const void* datap) : m_propsp{propsp} , m_datap{const_cast(datap)} {} - ~VerilatedDpiOpenVar() {} + ~VerilatedDpiOpenVar() = default; // METHODS void* datap() const { return m_datap; } // METHODS - from VerilatedVarProps @@ -227,7 +225,7 @@ public: /// Verilator variable /// Thread safety: Assume is constructed only with model, then any number of readers -class VerilatedVar : public VerilatedVarProps { +class VerilatedVar final : public VerilatedVarProps { // MEMBERS void* m_datap; // Location of data const char* m_namep; // Name - slowpath @@ -243,7 +241,7 @@ protected: , m_isParam{isParam} {} public: - ~VerilatedVar() {} + ~VerilatedVar() = default; // ACCESSORS void* datap() const { return m_datap; } const VerilatedRange& range() const { return packed(); } // Deprecated diff --git a/include/verilated_syms.h b/include/verilated_syms.h index e364a18cf..29fdfcb90 100644 --- a/include/verilated_syms.h +++ b/include/verilated_syms.h @@ -31,6 +31,7 @@ #include "verilated_sym_props.h" #include +#include #include //====================================================================== @@ -42,26 +43,27 @@ struct VerilatedCStrCmp { }; /// Map of sorted scope names to find associated scope class -class VerilatedScopeNameMap +class VerilatedScopeNameMap final : public std::map { public: - VerilatedScopeNameMap() {} - ~VerilatedScopeNameMap() {} + VerilatedScopeNameMap() = default; + ~VerilatedScopeNameMap() = default; }; /// Map of sorted variable names to find associated variable class -class VerilatedVarNameMap : public std::map { +class VerilatedVarNameMap final : public std::map { public: - VerilatedVarNameMap() {} - ~VerilatedVarNameMap() {} + VerilatedVarNameMap() = default; + ~VerilatedVarNameMap() = default; }; typedef std::vector VerilatedScopeVector; -class VerilatedHierarchyMap : public std::map { +class VerilatedHierarchyMap final + : public std::unordered_map { public: - VerilatedHierarchyMap() {} - ~VerilatedHierarchyMap() {} + VerilatedHierarchyMap() = default; + ~VerilatedHierarchyMap() = default; }; #endif // Guard diff --git a/include/verilated_threads.h b/include/verilated_threads.h index 1ff8de64e..4b6678c92 100644 --- a/include/verilated_threads.h +++ b/include/verilated_threads.h @@ -52,7 +52,7 @@ typedef void* VlThrSymTab; typedef void (*VlExecFnp)(bool, VlThrSymTab); /// Track dependencies for a single MTask. -class VlMTaskVertex { +class VlMTaskVertex final { // MEMBERS static std::atomic s_yields; // Statistics @@ -82,7 +82,7 @@ public: // that must notify this MTaskVertex before it will become ready // to run. explicit VlMTaskVertex(vluint32_t upstreamDepCount); - ~VlMTaskVertex() {} + ~VlMTaskVertex() = default; static vluint64_t yields() { return s_yields; } static void yieldThread() { @@ -124,7 +124,7 @@ public: }; // Profiling support -class VlProfileRec { +class VlProfileRec final { protected: friend class VlThreadPool; enum VlProfileE { TYPE_MTASK_RUN, TYPE_BARRIER }; @@ -136,7 +136,7 @@ protected: unsigned m_cpu; // Execution CPU number (at start anyways) public: class Barrier {}; - VlProfileRec() {} + VlProfileRec() = default; explicit VlProfileRec(Barrier) { m_cpu = getcpu(); } void startRecord(vluint64_t time, uint32_t mtask, uint32_t predict) { m_type = VlProfileRec::TYPE_MTASK_RUN; @@ -168,7 +168,7 @@ public: class VlThreadPool; -class VlWorkerThread { +class VlWorkerThread final { private: // TYPES struct ExecRec { @@ -247,7 +247,7 @@ public: static void startWorker(VlWorkerThread* workerp); }; -class VlThreadPool { +class VlThreadPool final { // TYPES typedef std::vector ProfileTrace; typedef std::set ProfileSet; diff --git a/include/verilated_trace.h b/include/verilated_trace.h index adffb68c3..bb4bc68b9 100644 --- a/include/verilated_trace.h +++ b/include/verilated_trace.h @@ -40,7 +40,7 @@ // Threaded tracing // A simple synchronized first in first out queue -template class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug +template class VerilatedThreadQueue final { // LCOV_EXCL_LINE // lcov bug private: VerilatedMutex m_mutex; // Protects m_queue std::condition_variable_any m_cv; @@ -83,7 +83,7 @@ public: // Commands used by thread tracing. Anonymous enum in class, as we want // it scoped, but we also want the automatic conversion to integer types. -class VerilatedTraceCommand { +class VerilatedTraceCommand final { public: // These must all fit in 4 bit at the moment, as the tracing routines // pack parameters in the top bits. @@ -110,7 +110,7 @@ public: // VerilatedTrace uses F-bounded polymorphism to access duck-typed // implementations in the format specific derived class, which must be passed // as the type parameter T_Derived -template class VerilatedTrace { +template class VerilatedTrace VL_NOT_FINAL { public: //========================================================================= // Generic tracing internals diff --git a/include/verilated_trace_imp.cpp b/include/verilated_trace_imp.cpp index ee2a31e35..840eb8be3 100644 --- a/include/verilated_trace_imp.cpp +++ b/include/verilated_trace_imp.cpp @@ -559,7 +559,7 @@ template <> void VerilatedTrace::fullDouble(vluint32_t* oldp, doub // All of these take a destination pointer where the string will be emitted, // and a value to convert. There are a couple of variants for efficiency. -inline static void cvtCDataToStr(char* dstp, CData value) { +static inline void cvtCDataToStr(char* dstp, CData value) { #ifdef VL_HAVE_SSE2 // Similar to cvtSDataToStr but only the bottom 8 byte lanes are used const __m128i a = _mm_cvtsi32_si128(value); @@ -581,7 +581,7 @@ inline static void cvtCDataToStr(char* dstp, CData value) { #endif } -inline static void cvtSDataToStr(char* dstp, SData value) { +static inline void cvtSDataToStr(char* dstp, SData value) { #ifdef VL_HAVE_SSE2 // We want each bit in the 16-bit input value to end up in a byte lane // within the 128-bit XMM register. Note that x86 is little-endian and we @@ -617,7 +617,7 @@ inline static void cvtSDataToStr(char* dstp, SData value) { #endif } -inline static void cvtIDataToStr(char* dstp, IData value) { +static inline void cvtIDataToStr(char* dstp, IData value) { #ifdef VL_HAVE_AVX2 // Similar to cvtSDataToStr but the bottom 16-bits are processed in the // top half of the YMM registerss @@ -636,7 +636,7 @@ inline static void cvtIDataToStr(char* dstp, IData value) { #endif } -inline static void cvtQDataToStr(char* dstp, QData value) { +static inline void cvtQDataToStr(char* dstp, QData value) { cvtIDataToStr(dstp, value >> 32); cvtIDataToStr(dstp + 32, value); } diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h index e5e1b334a..8424bd6e6 100644 --- a/include/verilated_vcd_c.h +++ b/include/verilated_vcd_c.h @@ -34,13 +34,13 @@ class VerilatedVcd; // VerilatedFile /// File handling routines, which can be overrode for e.g. socket I/O -class VerilatedVcdFile { +class VerilatedVcdFile final { private: int m_fd = 0; ///< File descriptor we're writing to public: // METHODS - VerilatedVcdFile() {} - virtual ~VerilatedVcdFile() {} + VerilatedVcdFile() = default; + virtual ~VerilatedVcdFile() = default; virtual bool open(const std::string& name) VL_MT_UNSAFE; virtual void close() VL_MT_UNSAFE; virtual ssize_t write(const char* bufp, ssize_t len) VL_MT_UNSAFE; @@ -51,7 +51,7 @@ public: /// Base class to create a Verilator VCD dump /// This is an internally used class - see VerilatedVcdC for what to call from applications -class VerilatedVcd : public VerilatedTrace { +class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace { private: // Give the superclass access to private bits (to avoid virtual functions) friend class VerilatedTrace; @@ -329,7 +329,7 @@ template <> void VerilatedTrace::set_time_resolution(const std::st /// Also derived for use in SystemC simulations. /// Thread safety: Unless otherwise indicated, every function is VL_MT_UNSAFE_ONE -class VerilatedVcdC { +class VerilatedVcdC VL_NOT_FINAL { VerilatedVcd m_sptrace; ///< Trace file being created // CONSTRUCTORS diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h index 15d0aae61..2836879c1 100644 --- a/include/verilated_vcd_sc.h +++ b/include/verilated_vcd_sc.h @@ -31,7 +31,7 @@ /// This class is passed to the SystemC simulation kernel, just like a /// documented SystemC trace format. -class VerilatedVcdSc : sc_trace_file, public VerilatedVcdC { +class VerilatedVcdSc final : sc_trace_file, public VerilatedVcdC { // CONSTRUCTORS VL_UNCOPYABLE(VerilatedVcdSc); diff --git a/include/verilated_vpi.cpp b/include/verilated_vpi.cpp index e1a2977a3..fe730dbfa 100644 --- a/include/verilated_vpi.cpp +++ b/include/verilated_vpi.cpp @@ -55,15 +55,15 @@ constexpr unsigned VL_VPI_LINE_SIZE = 8192; // Implementation // Base VPI handled object -class VerilatedVpio { +class VerilatedVpio VL_NOT_FINAL { // MEM MANGLEMENT static VL_THREAD_LOCAL vluint8_t* t_freeHead; public: // CONSTRUCTORS - VerilatedVpio() {} - virtual ~VerilatedVpio() {} - inline static void* operator new(size_t size) VL_MT_SAFE { + VerilatedVpio() = default; + virtual ~VerilatedVpio() = default; + static void* operator new(size_t size) VL_MT_SAFE { // We new and delete tons of vpi structures, so keep them around // To simplify our free list, we use a size large enough for all derived types // We reserve word zero for the next pointer, as that's safer in case a @@ -79,13 +79,13 @@ public: vluint8_t* newp = reinterpret_cast(::operator new(chunk + 8)); return newp + 8; } - inline static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE { + static void operator delete(void* obj, size_t /*size*/)VL_MT_SAFE { vluint8_t* oldp = (static_cast(obj)) - 8; *(reinterpret_cast(oldp)) = t_freeHead; t_freeHead = oldp; } // MEMBERS - static inline VerilatedVpio* castp(vpiHandle h) { + static VerilatedVpio* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } inline vpiHandle castVpiHandle() { return reinterpret_cast(this); } @@ -101,7 +101,7 @@ public: typedef PLI_INT32 (*VerilatedPliCb)(struct t_cb_data*); -class VerilatedVpioCb : public VerilatedVpio { +class VerilatedVpioCb final : public VerilatedVpio { t_cb_data m_cbData; s_vpi_value m_value; QData m_time; @@ -114,8 +114,8 @@ public: m_value.format = cbDatap->value ? cbDatap->value->format : vpiSuppressVal; m_cbData.value = &m_value; } - virtual ~VerilatedVpioCb() override {} - static inline VerilatedVpioCb* castp(vpiHandle h) { + virtual ~VerilatedVpioCb() override = default; + static VerilatedVpioCb* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiCallback; } @@ -125,21 +125,21 @@ public: QData time() const { return m_time; } }; -class VerilatedVpioConst : public VerilatedVpio { +class VerilatedVpioConst final : public VerilatedVpio { vlsint32_t m_num; public: explicit VerilatedVpioConst(vlsint32_t num) : m_num{num} {} - virtual ~VerilatedVpioConst() override {} - static inline VerilatedVpioConst* castp(vpiHandle h) { + virtual ~VerilatedVpioConst() override = default; + static VerilatedVpioConst* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiConstant; } vlsint32_t num() const { return m_num; } }; -class VerilatedVpioParam : public VerilatedVpio { +class VerilatedVpioParam final : public VerilatedVpio { const VerilatedVar* m_varp; const VerilatedScope* m_scopep; @@ -148,9 +148,9 @@ public: : m_varp{varp} , m_scopep{scopep} {} - virtual ~VerilatedVpioParam() override {} + virtual ~VerilatedVpioParam() override = default; - static inline VerilatedVpioParam* castp(vpiHandle h) { + static VerilatedVpioParam* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiParameter; } @@ -159,21 +159,21 @@ public: const VerilatedScope* scopep() const { return m_scopep; } virtual const char* name() const override { return m_varp->name(); } virtual const char* fullname() const override { - static VL_THREAD_LOCAL std::string out; - out = std::string(m_scopep->name()) + "." + name(); - return out.c_str(); + static VL_THREAD_LOCAL std::string t_out; + t_out = std::string(m_scopep->name()) + "." + name(); + return t_out.c_str(); } }; -class VerilatedVpioRange : public VerilatedVpio { +class VerilatedVpioRange final : public VerilatedVpio { const VerilatedRange* m_range; vlsint32_t m_iteration = 0; public: explicit VerilatedVpioRange(const VerilatedRange* range) : m_range{range} {} - virtual ~VerilatedVpioRange() override {} - static inline VerilatedVpioRange* castp(vpiHandle h) { + virtual ~VerilatedVpioRange() override = default; + static VerilatedVpioRange* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiRange; } @@ -191,15 +191,15 @@ public: } }; -class VerilatedVpioScope : public VerilatedVpio { +class VerilatedVpioScope VL_NOT_FINAL : public VerilatedVpio { protected: const VerilatedScope* m_scopep; public: explicit VerilatedVpioScope(const VerilatedScope* scopep) : m_scopep{scopep} {} - virtual ~VerilatedVpioScope() override {} - static inline VerilatedVpioScope* castp(vpiHandle h) { + virtual ~VerilatedVpioScope() override = default; + static VerilatedVpioScope* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiScope; } @@ -208,10 +208,10 @@ public: virtual const char* fullname() const override { return m_scopep->name(); } }; -class VerilatedVpioVar : public VerilatedVpio { +class VerilatedVpioVar VL_NOT_FINAL : public VerilatedVpio { const VerilatedVar* m_varp; const VerilatedScope* m_scopep; - vluint8_t* m_prevDatap; // Previous value of data, for cbValueChange + vluint8_t* m_prevDatap = nullptr; // Previous value of data, for cbValueChange union { vluint8_t u8[4]; vluint32_t u32; @@ -219,7 +219,7 @@ class VerilatedVpioVar : public VerilatedVpio { vluint32_t m_entSize; // memoized variable size protected: void* m_varDatap; // varp()->datap() adjusted for array entries - vlsint32_t m_index; + vlsint32_t m_index = 0; const VerilatedRange& get_range() const { // Determine number of dimensions and return outermost return (m_varp->dims() > 1) ? m_varp->unpacked() : m_varp->packed(); @@ -228,9 +228,7 @@ protected: public: VerilatedVpioVar(const VerilatedVar* varp, const VerilatedScope* scopep) : m_varp{varp} - , m_scopep{scopep} - , m_index{0} { - m_prevDatap = nullptr; + , m_scopep{scopep} { m_mask.u32 = VL_MASK_I(varp->packed().elements()); m_entSize = varp->entSize(); m_varDatap = varp->datap(); @@ -238,7 +236,7 @@ public: virtual ~VerilatedVpioVar() override { if (m_prevDatap) VL_DO_CLEAR(delete[] m_prevDatap, m_prevDatap = nullptr); } - static inline VerilatedVpioVar* castp(vpiHandle h) { + static VerilatedVpioVar* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } const VerilatedVar* varp() const { return m_varp; } @@ -254,9 +252,9 @@ public: virtual const VerilatedRange* rangep() const override { return &get_range(); } virtual const char* name() const override { return m_varp->name(); } virtual const char* fullname() const override { - static VL_THREAD_LOCAL std::string out; - out = std::string(m_scopep->name()) + "." + name(); - return out.c_str(); + static VL_THREAD_LOCAL std::string t_out; + t_out = std::string(m_scopep->name()) + "." + name(); + return t_out.c_str(); } void* prevDatap() const { return m_prevDatap; } void* varDatap() const { return m_varDatap; } @@ -268,7 +266,7 @@ public: } }; -class VerilatedVpioMemoryWord : public VerilatedVpioVar { +class VerilatedVpioMemoryWord final : public VerilatedVpioVar { public: VerilatedVpioMemoryWord(const VerilatedVar* varp, const VerilatedScope* scopep, vlsint32_t index, int offset) @@ -276,23 +274,23 @@ public: m_index = index; m_varDatap = (static_cast(varp->datap())) + entSize() * offset; } - virtual ~VerilatedVpioMemoryWord() override {} - static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { + virtual ~VerilatedVpioMemoryWord() override = default; + static VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiMemoryWord; } virtual vluint32_t size() const override { return varp()->packed().elements(); } virtual const VerilatedRange* rangep() const override { return &(varp()->packed()); } virtual const char* fullname() const override { - static VL_THREAD_LOCAL std::string out; + static VL_THREAD_LOCAL std::string t_out; char num[20]; sprintf(num, "%d", m_index); - out = std::string(scopep()->name()) + "." + name() + "[" + num + "]"; - return out.c_str(); + t_out = std::string(scopep()->name()) + "." + name() + "[" + num + "]"; + return t_out.c_str(); } }; -class VerilatedVpioVarIter : public VerilatedVpio { +class VerilatedVpioVarIter final : public VerilatedVpio { const VerilatedScope* m_scopep; VerilatedVarNameMap::const_iterator m_it; bool m_started = false; @@ -300,8 +298,8 @@ class VerilatedVpioVarIter : public VerilatedVpio { public: explicit VerilatedVpioVarIter(const VerilatedScope* scopep) : m_scopep{scopep} {} - virtual ~VerilatedVpioVarIter() override {} - static inline VerilatedVpioVarIter* castp(vpiHandle h) { + virtual ~VerilatedVpioVarIter() override = default; + static VerilatedVpioVarIter* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiIterator; } @@ -323,7 +321,7 @@ public: } }; -class VerilatedVpioMemoryWordIter : public VerilatedVpio { +class VerilatedVpioMemoryWordIter final : public VerilatedVpio { const vpiHandle m_handle; const VerilatedVar* m_varp; vlsint32_t m_iteration; @@ -336,8 +334,8 @@ public: , m_varp{varp} , m_iteration{varp->unpacked().right()} , m_direction{VL_LIKELY(varp->unpacked().left() > varp->unpacked().right()) ? 1 : -1} {} - virtual ~VerilatedVpioMemoryWordIter() override {} - static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { + virtual ~VerilatedVpioMemoryWordIter() override = default; + static VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiIterator; } @@ -353,7 +351,7 @@ public: } }; -class VerilatedVpioModule : public VerilatedVpioScope { +class VerilatedVpioModule final : public VerilatedVpioScope { const char* m_name; const char* m_fullname; @@ -364,7 +362,7 @@ public: if (strncmp(m_fullname, "TOP.", 4) == 0) m_fullname += 4; m_name = m_scopep->identifier(); } - static inline VerilatedVpioModule* castp(vpiHandle h) { + static VerilatedVpioModule* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiModule; } @@ -372,7 +370,7 @@ public: virtual const char* fullname() const override { return m_fullname; } }; -class VerilatedVpioModuleIter : public VerilatedVpio { +class VerilatedVpioModuleIter final : public VerilatedVpio { const std::vector* m_vec; std::vector::const_iterator m_it; @@ -381,8 +379,8 @@ public: : m_vec{&vec} { m_it = m_vec->begin(); } - virtual ~VerilatedVpioModuleIter() override {} - static inline VerilatedVpioModuleIter* castp(vpiHandle h) { + virtual ~VerilatedVpioModuleIter() override = default; + static VerilatedVpioModuleIter* castp(vpiHandle h) { return dynamic_cast(reinterpret_cast(h)); } virtual vluint32_t type() const override { return vpiIterator; } @@ -407,15 +405,11 @@ struct VerilatedVpiTimedCbsCmp { class VerilatedVpiError; -class VerilatedVpiImp { +class VerilatedVpiImp final { enum { CB_ENUM_MAX_VALUE = cbAtEndOfSimTime + 1 }; // Maxium callback reason typedef std::list VpioCbList; typedef std::set, VerilatedVpiTimedCbsCmp> VpioTimedCbs; - struct product_info { - PLI_BYTE8* product; - }; - VpioCbList m_cbObjLists[CB_ENUM_MAX_VALUE]; // Callbacks for each supported reason VpioTimedCbs m_timedCbs; // Time based callbacks VerilatedVpiError* m_errorInfop = nullptr; // Container for vpi error info @@ -424,8 +418,8 @@ class VerilatedVpiImp { static VerilatedVpiImp s_s; // Singleton public: - VerilatedVpiImp() {} - ~VerilatedVpiImp() {} + VerilatedVpiImp() = default; + ~VerilatedVpiImp() = default; static void assertOneCheck() { s_s.m_assertOne.check(); } static void cbReasonAdd(VerilatedVpioCb* vop) { if (vop->reason() == cbValueChange) { @@ -477,16 +471,21 @@ public: static bool callCbs(vluint32_t reason) VL_MT_UNSAFE_ONE { VpioCbList& cbObjList = s_s.m_cbObjLists[reason]; bool called = false; - const auto end = cbObjList.end(); // prevent looping over newly added elements - for (auto it = cbObjList.begin(); it != end;) { + if (cbObjList.empty()) return called; + const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements + for (auto it = cbObjList.begin(); true;) { + // cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist + bool was_last = it == last; if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); + if (was_last) break; continue; } VerilatedVpioCb* vop = *it++; VL_DEBUG_IF_PLI(VL_DBG_MSGF("- vpi: reason_callback %d %p\n", reason, vop);); (vop->cb_rtnp())(vop->cb_datap()); called = true; + if (was_last) break; } return called; } @@ -494,12 +493,16 @@ public: assertOneCheck(); VpioCbList& cbObjList = s_s.m_cbObjLists[cbValueChange]; bool called = false; - typedef std::set VpioVarSet; + typedef std::unordered_set VpioVarSet; VpioVarSet update; // set of objects to update after callbacks - const auto end = cbObjList.end(); // prevent looping over newly added elements - for (auto it = cbObjList.begin(); it != end;) { + if (cbObjList.empty()) return called; + const auto last = std::prev(cbObjList.end()); // prevent looping over newly added elements + for (auto it = cbObjList.begin(); true;) { + // cbReasonRemove sets to nullptr, so we know on removal the old end() will still exist + bool was_last = it == last; if (VL_UNLIKELY(!*it)) { // Deleted earlier, cleanup it = cbObjList.erase(it); + if (was_last) break; continue; } VerilatedVpioCb* vop = *it++; @@ -518,6 +521,7 @@ public: called = true; } } + if (was_last) break; } for (const auto& ip : update) { memcpy(ip->prevDatap(), ip->varDatap(), ip->entSize()); } return called; @@ -526,7 +530,7 @@ public: static VerilatedVpiError* error_info() VL_MT_UNSAFE_ONE; // getter for vpi error info }; -class VerilatedVpiError { +class VerilatedVpiError final { //// Container for vpi error info t_vpi_error_info m_errorInfo; @@ -555,7 +559,7 @@ public: m_buff[0] = '\0'; m_errorInfo.product = const_cast(Verilated::productName()); } - ~VerilatedVpiError() {} + ~VerilatedVpiError() = default; static void selfTest() VL_MT_UNSAFE_ONE; VerilatedVpiError* setMessage(PLI_INT32 level) { m_flag = true; @@ -564,14 +568,14 @@ public: } void setMessage(const std::string& file, PLI_INT32 line, const char* message, ...) { // message cannot be a const string& as va_start cannot use a reference - static VL_THREAD_LOCAL std::string filehold; + static VL_THREAD_LOCAL std::string t_filehold; va_list args; va_start(args, message); VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args); va_end(args); m_errorInfo.state = vpiPLI; - filehold = file; - setError((PLI_BYTE8*)m_buff, nullptr, const_cast(filehold.c_str()), line); + t_filehold = file; + setError((PLI_BYTE8*)m_buff, nullptr, const_cast(t_filehold.c_str()), line); } p_vpi_error_info getError() { if (m_flag) return &m_errorInfo; @@ -1415,34 +1419,34 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep, const char* fullname) { if (!vl_check_format(varp, valuep, fullname, true)) return; // Maximum required size is for binary string, one byte per bit plus null termination - static VL_THREAD_LOCAL char outStr[1 + VL_MULS_MAX_WORDS * 32]; + static VL_THREAD_LOCAL char t_outStr[1 + VL_MULS_MAX_WORDS * 32]; // cppcheck-suppress variableScope - static VL_THREAD_LOCAL int outStrSz = sizeof(outStr) - 1; + static VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1; // We used to presume vpiValue.format = vpiIntVal or if single bit vpiScalarVal // This may cause backward compatibility issues with older code. if (valuep->format == vpiVectorVal) { // Vector pointer must come from our memory pool // It only needs to persist until the next vpi_get_value - static VL_THREAD_LOCAL t_vpi_vecval out[VL_MULS_MAX_WORDS * 2]; - valuep->value.vector = out; + static VL_THREAD_LOCAL t_vpi_vecval t_out[VL_MULS_MAX_WORDS * 2]; + valuep->value.vector = t_out; if (varp->vltype() == VLVT_UINT8) { - out[0].aval = *(reinterpret_cast(varDatap)); - out[0].bval = 0; + t_out[0].aval = *(reinterpret_cast(varDatap)); + t_out[0].bval = 0; return; } else if (varp->vltype() == VLVT_UINT16) { - out[0].aval = *(reinterpret_cast(varDatap)); - out[0].bval = 0; + t_out[0].aval = *(reinterpret_cast(varDatap)); + t_out[0].bval = 0; return; } else if (varp->vltype() == VLVT_UINT32) { - out[0].aval = *(reinterpret_cast(varDatap)); - out[0].bval = 0; + t_out[0].aval = *(reinterpret_cast(varDatap)); + t_out[0].bval = 0; return; } else if (varp->vltype() == VLVT_UINT64) { QData data = *(reinterpret_cast(varDatap)); - out[1].aval = static_cast(data >> 32ULL); - out[1].bval = 0; - out[0].aval = static_cast(data); - out[0].bval = 0; + t_out[1].aval = static_cast(data >> 32ULL); + t_out[1].bval = 0; + t_out[0].aval = static_cast(data); + t_out[0].bval = 0; return; } else if (varp->vltype() == VLVT_WDATA) { int words = VL_WORDS_I(varp->packed().elements()); @@ -1453,47 +1457,47 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep, } WDataInP datap = (reinterpret_cast(varDatap)); for (int i = 0; i < words; ++i) { - out[i].aval = datap[i]; - out[i].bval = 0; + t_out[i].aval = datap[i]; + t_out[i].bval = 0; } return; } } else if (valuep->format == vpiBinStrVal) { - valuep->value.str = outStr; + valuep->value.str = t_outStr; int bits = varp->packed().elements(); CData* datap = (reinterpret_cast(varDatap)); int i; - if (bits > outStrSz) { + if (bits > t_outStrSz) { // limit maximum size of output to size of buffer to prevent overrun. - bits = outStrSz; + bits = t_outStrSz; _VL_VPI_WARNING( __FILE__, __LINE__, "%s: Truncating string value of %s for %s" " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz, VL_MULS_MAX_WORDS, bits); } for (i = 0; i < bits; ++i) { char val = (datap[i >> 3] >> (i & 7)) & 1; - outStr[bits - i - 1] = val ? '1' : '0'; + t_outStr[bits - i - 1] = val ? '1' : '0'; } - outStr[i] = '\0'; + t_outStr[i] = '\0'; return; } else if (valuep->format == vpiOctStrVal) { - valuep->value.str = outStr; + valuep->value.str = t_outStr; int chars = (varp->packed().elements() + 2) / 3; int bytes = VL_BYTES_I(varp->packed().elements()); CData* datap = (reinterpret_cast(varDatap)); int i; - if (chars > outStrSz) { + if (chars > t_outStrSz) { // limit maximum size of output to size of buffer to prevent overrun. _VL_VPI_WARNING( __FILE__, __LINE__, "%s: Truncating string value of %s for %s" " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz, VL_MULS_MAX_WORDS, chars); - chars = outStrSz; + chars = t_outStrSz; } for (i = 0; i < chars; ++i) { div_t idx = div(i * 3, 8); @@ -1514,44 +1518,44 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep, val &= (1 << rem) - 1; } } - outStr[chars - i - 1] = '0' + (val & 7); + t_outStr[chars - i - 1] = '0' + (val & 7); } - outStr[i] = '\0'; + t_outStr[i] = '\0'; return; } else if (valuep->format == vpiDecStrVal) { - valuep->value.str = outStr; + valuep->value.str = t_outStr; // outStrSz does not include nullptr termination so add one if (varp->vltype() == VLVT_UINT8) { - VL_SNPRINTF(outStr, outStrSz + 1, "%hhu", + VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hhu", static_cast(*(reinterpret_cast(varDatap)))); return; } else if (varp->vltype() == VLVT_UINT16) { - VL_SNPRINTF(outStr, outStrSz + 1, "%hu", + VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu", static_cast(*(reinterpret_cast(varDatap)))); return; } else if (varp->vltype() == VLVT_UINT32) { - VL_SNPRINTF(outStr, outStrSz + 1, "%u", + VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u", static_cast(*(reinterpret_cast(varDatap)))); return; } else if (varp->vltype() == VLVT_UINT64) { - VL_SNPRINTF(outStr, outStrSz + 1, "%llu", + VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu", static_cast(*(reinterpret_cast(varDatap)))); return; } } else if (valuep->format == vpiHexStrVal) { - valuep->value.str = outStr; + valuep->value.str = t_outStr; int chars = (varp->packed().elements() + 3) >> 2; CData* datap = (reinterpret_cast(varDatap)); int i; - if (chars > outStrSz) { + if (chars > t_outStrSz) { // limit maximum size of output to size of buffer to prevent overrun. _VL_VPI_WARNING( __FILE__, __LINE__, "%s: Truncating string value of %s for %s" " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, t_outStrSz, VL_MULS_MAX_WORDS, chars); - chars = outStrSz; + chars = t_outStrSz; } for (i = 0; i < chars; ++i) { char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15; @@ -1564,35 +1568,35 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep, val &= (1 << rem) - 1; } } - outStr[chars - i - 1] = "0123456789abcdef"[static_cast(val)]; + t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast(val)]; } - outStr[i] = '\0'; + t_outStr[i] = '\0'; return; } else if (valuep->format == vpiStringVal) { if (varp->vltype() == VLVT_STRING) { valuep->value.str = reinterpret_cast(varDatap); return; } else { - valuep->value.str = outStr; + valuep->value.str = t_outStr; int bytes = VL_BYTES_I(varp->packed().elements()); CData* datap = (reinterpret_cast(varDatap)); int i; - if (bytes > outStrSz) { + if (bytes > t_outStrSz) { // limit maximum size of output to size of buffer to prevent overrun. _VL_VPI_WARNING( __FILE__, __LINE__, "%s: Truncating string value of %s for %s" " as buffer size (%d, VL_MULS_MAX_WORDS=%d) is less than required (%d)", - VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, outStrSz, - VL_MULS_MAX_WORDS, bytes); - bytes = outStrSz; + VL_FUNC, VerilatedVpiError::strFromVpiVal(valuep->format), fullname, + t_outStrSz, VL_MULS_MAX_WORDS, bytes); + bytes = t_outStrSz; } for (i = 0; i < bytes; ++i) { char val = datap[bytes - i - 1]; // other simulators replace [leading?] zero chars with spaces, replicate here. - outStr[i] = val ? val : ' '; + t_outStr[i] = val ? val : ' '; } - outStr[i] = '\0'; + t_outStr[i] = '\0'; return; } } else if (valuep->format == vpiIntVal) { diff --git a/include/verilated_vpi.h b/include/verilated_vpi.h index 4ecfc55ca..eebb3736b 100644 --- a/include/verilated_vpi.h +++ b/include/verilated_vpi.h @@ -33,7 +33,7 @@ //====================================================================== -class VerilatedVpi { +class VerilatedVpi final { public: /// Call timed callbacks /// Users should call this from their main loops diff --git a/include/verilatedos.h b/include/verilatedos.h index 7ba4ff55c..abe297843 100644 --- a/include/verilatedos.h +++ b/include/verilatedos.h @@ -374,7 +374,10 @@ typedef unsigned long long vluint64_t; ///< 64-bit unsigned type //========================================================================= // Class definition helpers -// Used to declare a class as uncopyable; put after a private: +/// Used to indicate a base class, e.g. cannot label "class final" +#define VL_NOT_FINAL + +/// Used to declare a class as uncopyable; put after a private: #define VL_UNCOPYABLE(Type) \ Type(const Type& other) = delete; \ Type& operator=(const Type&) = delete diff --git a/nodist/code_coverage b/nodist/code_coverage index 869027ecf..598d5b94a 100755 --- a/nodist/code_coverage +++ b/nodist/code_coverage @@ -83,28 +83,28 @@ sub test { require "./nodist/code_coverage.dat"; if ($Opt_Stages{1}) { - travis_fold_start("configure"); + ci_fold_start("configure"); print "Stage 1: configure (coverage on)\n"; run("make distclean || true"); run("autoconf"); # Exceptions can pollute the branch coverage data run("./configure --enable-longtests CXX='g++ --coverage -fno-exceptions -DVL_GCOV'"); - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{2}) { - travis_fold_start("build"); + ci_fold_start("build"); print "Stage 2: build\n"; my $nproc = Unix::Processors->new->max_online; run("make -k -j $nproc VERILATOR_NO_OPT_BUILD=1"); # The optimized versions will not collect good coverage, overwrite them run("cp bin/verilator_bin_dbg bin/verilator_bin"); run("cp bin/verilator_coverage_bin_dbg bin/verilator_coverage_bin"); - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{3}) { - travis_fold_start("test"); + ci_fold_start("test"); print "Stage 3: make tests (with coverage on)\n"; if ($#Opt_Tests < 0) { run("make examples VERILATOR_NO_OPT_BUILD=1") @@ -121,12 +121,12 @@ sub test { run($test); } } - travis_fold_end(); + ci_fold_end(); } my $cc_dir = "nodist/obj_dir/coverage"; if ($Opt_Stages{4}) { - travis_fold_start("gcno"); + ci_fold_start("gcno"); print "Stage 4: Create gcno files under $cc_dir\n"; mkpath($cc_dir); mkpath("$cc_dir/info"); @@ -165,11 +165,11 @@ sub test { } } } - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{5} && $Opt_Fastcov) { - travis_fold_start("fastcov"); + ci_fold_start("fastcov"); # Must run in root directory to find all files mkpath($cc_dir); #run("${RealBin}/fastcov.py -b -c src/obj_dbg -X". @@ -178,11 +178,11 @@ sub test { run("${RealBin}/fastcov.py -b -c src/obj_dbg -X --lcov". " --exclude /usr --exclude test_regress" ." -o ${cc_dir}/app_total.info"); - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{5} && !$Opt_Fastcov) { - travis_fold_start("infos"); + ci_fold_start("infos"); print "Stage 5: make infos\n"; my $dats = `find . -print | grep .gcda`; my %dirs; @@ -199,20 +199,20 @@ sub test { })->run; } $Fork->wait_all; - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{6}) { - travis_fold_start("clone"); + ci_fold_start("clone"); # No control file to override single lines, so replicate the sources # Also lets us see the insertion markers in the HTML source res print "Stage 6: Clone sources under $cc_dir\n"; clone_sources($cc_dir); - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{8} && !$Opt_Fastcov) { - travis_fold_start("copy"); + ci_fold_start("copy"); print "Stage 8: Copy .gcno files\n"; my $dats = `find . -print | grep .gcno`; foreach my $dat (sort (split '\n', $dats)) { @@ -221,11 +221,11 @@ sub test { #print "cp $dat, $outdat);\n"; cp($dat, $outdat); } - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{10} && !$Opt_Fastcov) { - travis_fold_start("combine"); + ci_fold_start("combine"); print "Stage 10: Combine data files\n"; { run("cd $cc_dir ; lcov -c -i -d src/obj_dbg -o app_base.info"); @@ -243,11 +243,11 @@ sub test { } } } - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{11}) { - travis_fold_start("dirs"); + ci_fold_start("dirs"); print "Stage 11: Cleanup paths\n"; if ($Opt_Fastcov) { cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info"); @@ -255,11 +255,11 @@ sub test { } else { cleanup_abs_paths_info($cc_dir, "$cc_dir/app_total.info", "$cc_dir/app_total.info"); } - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{12}) { - travis_fold_start("filter"); + ci_fold_start("filter"); print "Stage 12: Filter processed source files\n"; my $inc = ''; foreach my $glob (@Source_Globs) { @@ -282,24 +282,24 @@ sub test { } else { run("cd $cc_dir ; lcov --remove app_total.info $exc -o app_total_f.info"); } - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{17}) { - travis_fold_start("report"); + ci_fold_start("report"); print "Stage 17: Create HTML\n"; run("cd $cc_dir ; genhtml app_total_f.info --demangle-cpp" ." --rc lcov_branch_coverage=1 --rc genhtml_hi_limit=100 --output-directory html"); - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{18}) { - travis_fold_start("upload"); + ci_fold_start("upload"); print "Stage 18: Upload\n"; my $cmd = "bash <(curl -s https://codecov.io/bash) -f $cc_dir/app_total.info"; print "print: Not running: export CODECOV_TOKEN=\n"; print "print: Not running: $cmd\n"; - travis_fold_end(); + ci_fold_end(); } if ($Opt_Stages{19}) { @@ -425,13 +425,13 @@ sub run { ($status == 0) or die "%Error: Command Failed $command, $status, stopped"; } -our $_Travis_Action; -sub travis_fold_start { - $_Travis_Action = shift; - print "travis_fold:start:$_Travis_Action\n"; +our $_Ci_Action; +sub ci_fold_start { + $_Ci_Action = shift; + print "travis_fold:start:$_Ci_Action\n"; } -sub travis_fold_end { - print "travis_fold:end:$_Travis_Action\n"; +sub ci_fold_end { + print "travis_fold:end:$_Ci_Action\n"; } ####################################################################### diff --git a/nodist/code_coverage.dat b/nodist/code_coverage.dat index f4aacd760..a3a276afa 100644 --- a/nodist/code_coverage.dat +++ b/nodist/code_coverage.dat @@ -57,6 +57,7 @@ exclude_line_regexp(qr/(\bv3fatalSrc\b # Exclude for branch coverage only exclude_branch_regexp(qr/(\bdebug\(\) |\bassert\( + |\bBROKEN_RTK\( |\bSELF_CHECK)/x); 1; diff --git a/src/.gdbinit b/src/.gdbinit index 17532d0d2..8e973680f 100644 --- a/src/.gdbinit +++ b/src/.gdbinit @@ -7,21 +7,21 @@ # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 define pn - call $arg0->dumpGdb() + call AstNode::dumpGdb($arg0) end document pn Verilator: Print single AstNode NODEP end define pnt - call $arg0->dumpTreeGdb() + call AstNode::dumpTreeGdb($arg0) end document pnt Verilator: Print AstNode NODEP's tree end define dtf - call AstNode::dumpTreeFileGdb(0) + call AstNode::dumpTreeFileGdb($arg0, 0) end document dtf Verilator: Dump AstNode tree to file diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in index 8b058c7b0..b686d5775 100644 --- a/src/Makefile_obj.in +++ b/src/Makefile_obj.in @@ -94,7 +94,6 @@ LIBS = $(CFG_LIBS) -lm CPPFLAGS += -MMD CPPFLAGS += -I. -I$(bldsrc) -I$(srcdir) -I$(incdir) -I../../include -CPPFLAGS += -DYYDEBUG # Required to get nice error messages #CPPFLAGS += -DVL_LEAK_CHECKS # If running valgrind or other hunting tool CPPFLAGS += $(COPT) CPPFLAGS += -MP # Only works on recent GCC versions diff --git a/src/V3Active.cpp b/src/V3Active.cpp index 7b0124922..50aa672c2 100644 --- a/src/V3Active.cpp +++ b/src/V3Active.cpp @@ -43,12 +43,12 @@ //###################################################################### // Collect existing active names -class ActiveBaseVisitor : public AstNVisitor { +class ActiveBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: VL_DEBUG_FUNC; // Declare debug() }; -class ActiveNamer : public ActiveBaseVisitor { +class ActiveNamer final : public ActiveBaseVisitor { private: // STATE AstScope* m_scopep = nullptr; // Current scope to add statement to @@ -130,15 +130,15 @@ public: } // CONSTRUCTORS - ActiveNamer() {} - virtual ~ActiveNamer() override {} + ActiveNamer() = default; + virtual ~ActiveNamer() override = default; void main(AstScope* nodep) { iterate(nodep); } }; //###################################################################### // Active AssignDly replacement functions -class ActiveDlyVisitor : public ActiveBaseVisitor { +class ActiveDlyVisitor final : public ActiveBaseVisitor { public: enum CheckType : uint8_t { CT_SEQ, CT_COMBO, CT_INITIAL, CT_LATCH }; @@ -205,13 +205,13 @@ public: , m_alwaysp{nodep} { iterate(nodep); } - virtual ~ActiveDlyVisitor() override {} + virtual ~ActiveDlyVisitor() override = default; }; //###################################################################### // Active class functions -class ActiveVisitor : public ActiveBaseVisitor { +class ActiveVisitor final : public ActiveBaseVisitor { private: // NODE STATE // Each call to V3Const::constify @@ -364,6 +364,14 @@ private: } visitAlways(nodep, nodep->sensesp(), nodep->keyword()); } + virtual void visit(AstAlwaysPostponed* nodep) override { + UINFO(4, " ALW " << nodep << endl); + if (!nodep->bodysp()) { + VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); + return; + } + visitAlways(nodep, nullptr, VAlwaysKwd::ALWAYS); + } virtual void visit(AstAlwaysPublic* nodep) override { // Move always to appropriate ACTIVE based on its sense list UINFO(4, " ALWPub " << nodep << endl); @@ -406,7 +414,7 @@ private: public: // CONSTRUCTORS explicit ActiveVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ActiveVisitor() override {} + virtual ~ActiveVisitor() override = default; }; //###################################################################### diff --git a/src/V3Active.h b/src/V3Active.h index cc0629e0b..79fff9303 100644 --- a/src/V3Active.h +++ b/src/V3Active.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Active { +class V3Active final { public: static void activeAll(AstNetlist* nodep); }; diff --git a/src/V3ActiveTop.cpp b/src/V3ActiveTop.cpp index b944618cf..3982acb29 100644 --- a/src/V3ActiveTop.cpp +++ b/src/V3ActiveTop.cpp @@ -35,7 +35,7 @@ //###################################################################### // Active class functions -class ActiveTopVisitor : public AstNVisitor { +class ActiveTopVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist @@ -128,7 +128,7 @@ private: public: // CONSTRUCTORS explicit ActiveTopVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ActiveTopVisitor() override {} + virtual ~ActiveTopVisitor() override = default; }; //###################################################################### diff --git a/src/V3ActiveTop.h b/src/V3ActiveTop.h index 27a7b18d1..9bc677ff8 100644 --- a/src/V3ActiveTop.h +++ b/src/V3ActiveTop.h @@ -25,7 +25,7 @@ //============================================================================ -class V3ActiveTop { +class V3ActiveTop final { public: static void activeTopAll(AstNetlist* nodep); }; diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp index 981d705ae..8af7193cc 100644 --- a/src/V3Assert.cpp +++ b/src/V3Assert.cpp @@ -26,7 +26,7 @@ //###################################################################### // Assert class functions -class AssertVisitor : public AstNVisitor { +class AssertVisitor final : public AstNVisitor { private: // NODE STATE/TYPES // Cleared on netlist @@ -36,7 +36,11 @@ private: // STATE AstNodeModule* m_modp = nullptr; // Last module AstBegin* m_beginp = nullptr; // Last begin + unsigned m_monitorNum = 0; // Global $monitor numbering (not per module) + AstVar* m_monitorNumVarp = nullptr; // $monitor number variable + AstVar* m_monitorOffVarp = nullptr; // $monitoroff variable unsigned m_modPastNum = 0; // Module past numbering + unsigned m_modStrobeNum = 0; // Module $strobe numbering VDouble0 m_statCover; // Statistic tracking VDouble0 m_statAsNotImm; // Statistic tracking VDouble0 m_statAsImm; // Statistic tracking @@ -62,7 +66,26 @@ private: nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline())); } } - + AstVarRef* newMonitorNumVarRefp(AstNode* nodep, VAccess access) { + if (!m_monitorNumVarp) { + m_monitorNumVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP, + "__VmonitorNum", nodep->findUInt64DType()}; + v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorNumVarp); + } + const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorNumVarp, access); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); + return varrefp; + } + AstVarRef* newMonitorOffVarRefp(AstNode* nodep, VAccess access) { + if (!m_monitorOffVarp) { + m_monitorOffVarp = new AstVar{nodep->fileline(), AstVarType::MODULETEMP, + "__VmonitorOff", nodep->findBitDType()}; + v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(m_monitorOffVarp); + } + const auto varrefp = new AstVarRef(nodep->fileline(), m_monitorOffVarp, access); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); + return varrefp; + } AstNode* newIfAssertOn(AstNode* nodep) { // Add a internal if to check assertions are on. // Don't make this a AND term, as it's unlikely to need to test this. @@ -73,7 +96,7 @@ private: // This allows syntax errors and such to be detected normally. (v3Global.opt.assertOn() ? static_cast(new AstCMath(fl, "Verilated::assertOn()", 1)) - : static_cast(new AstConst(fl, AstConst::LogicFalse()))), + : static_cast(new AstConst(fl, AstConst::BitFalse()))), nodep, nullptr); newp->user1(true); // Don't assert/cover this if return newp; @@ -207,7 +230,7 @@ private: bool allow_none = nodep->unique0Pragma(); // Empty case means no property - if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse()); // Note: if this ends with an 'else', then we don't need to validate that one of the // predicates evaluates to true. @@ -276,7 +299,7 @@ private: } } // Empty case means no property - if (!propp) propp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + if (!propp) propp = new AstConst(nodep->fileline(), AstConst::BitFalse()); bool allow_none = has_default || nodep->unique0Pragma(); AstNode* ohot @@ -342,9 +365,54 @@ private: } else if (nodep->displayType() == AstDisplayType::DT_ERROR || nodep->displayType() == AstDisplayType::DT_FATAL) { replaceDisplay(nodep, "%%Error"); + } else if (nodep->displayType() == AstDisplayType::DT_MONITOR) { + nodep->displayType(AstDisplayType::DT_DISPLAY); + const auto fl = nodep->fileline(); + const auto monNum = ++m_monitorNum; + // Where $monitor was we do "__VmonitorNum = N;" + const auto newsetp = new AstAssign{fl, newMonitorNumVarRefp(nodep, VAccess::WRITE), + new AstConst{fl, monNum}}; + nodep->replaceWith(newsetp); + // Add "always_comb if (__VmonitorOn && __VmonitorNum==N) $display(...);" + AstNode* stmtsp = nodep; + AstIf* ifp = new AstIf{ + fl, + new AstLogAnd{fl, new AstLogNot{fl, newMonitorOffVarRefp(nodep, VAccess::READ)}, + new AstEq{fl, new AstConst{fl, monNum}, + newMonitorNumVarRefp(nodep, VAccess::READ)}}, + stmtsp, nullptr}; + ifp->branchPred(VBranchPred::BP_UNLIKELY); + AstNode* newp = new AstAlwaysPostponed{fl, ifp}; + m_modp->addStmtp(newp); + } else if (nodep->displayType() == AstDisplayType::DT_STROBE) { + nodep->displayType(AstDisplayType::DT_DISPLAY); + // Need one-shot + const auto fl = nodep->fileline(); + const auto varp + = new AstVar{fl, AstVarType::MODULETEMP, "__Vstrobe" + cvtToStr(m_modStrobeNum++), + nodep->findBitDType()}; + m_modp->addStmtp(varp); + // Where $strobe was we do "__Vstrobe = '1;" + const auto newsetp = new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, + new AstConst{fl, AstConst::BitTrue{}}}; + nodep->replaceWith(newsetp); + // Add "always_comb if (__Vstrobe) begin $display(...); __Vstrobe = '0; end" + AstNode* stmtsp = nodep; + AstIf* ifp = new AstIf{fl, new AstVarRef{fl, varp, VAccess::READ}, stmtsp, nullptr}; + ifp->branchPred(VBranchPred::BP_UNLIKELY); + AstNode* newp = new AstAlwaysPostponed{fl, ifp}; + stmtsp->addNext(new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, + new AstConst{fl, AstConst::BitFalse{}}}); + m_modp->addStmtp(newp); } } - + virtual void visit(AstMonitorOff* nodep) override { + const auto newp + = new AstAssign(nodep->fileline(), newMonitorOffVarRefp(nodep, VAccess::WRITE), + new AstConst(nodep->fileline(), AstConst::BitTrue{}, nodep->off())); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + } virtual void visit(AstAssert* nodep) override { iterateChildren(nodep); newPslAssertion(nodep, nodep->failsp()); @@ -362,9 +430,11 @@ private: virtual void visit(AstNodeModule* nodep) override { VL_RESTORER(m_modp); VL_RESTORER(m_modPastNum); + VL_RESTORER(m_modStrobeNum); { m_modp = nodep; m_modPastNum = 0; + m_modStrobeNum = 0; iterateChildren(nodep); } } diff --git a/src/V3Assert.h b/src/V3Assert.h index d72625aba..934a2032d 100644 --- a/src/V3Assert.h +++ b/src/V3Assert.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Assert { +class V3Assert final { public: static void assertAll(AstNetlist* nodep); }; diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp index 50a405b13..727e0aafe 100644 --- a/src/V3AssertPre.cpp +++ b/src/V3AssertPre.cpp @@ -26,7 +26,7 @@ //###################################################################### // Assert class functions -class AssertPreVisitor : public AstNVisitor { +class AssertPreVisitor final : public AstNVisitor { // Removes clocks and other pre-optimizations // Eventually inlines calls to sequences, properties, etc. // We're not parsing the tree, or anything more complicated. @@ -103,7 +103,7 @@ private: AstNode* past = new AstPast(fl, exprp, nullptr); past->dtypeFrom(exprp); exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false))); - exprp->dtypeSetLogicBool(); + exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -122,7 +122,7 @@ private: AstNode* past = new AstPast(fl, exprp, nullptr); past->dtypeFrom(exprp); exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false)); - exprp->dtypeSetLogicBool(); + exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -135,7 +135,7 @@ private: AstNode* past = new AstPast(fl, exprp, nullptr); past->dtypeFrom(exprp); exprp = new AstEq(fl, past, exprp->cloneTree(false)); - exprp->dtypeSetLogicBool(); + exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -153,7 +153,7 @@ private: AstNode* past = new AstPast(fl, lhsp, nullptr); past->dtypeFrom(lhsp); AstNode* exprp = new AstOr(fl, new AstNot(fl, past), rhsp); - exprp->dtypeSetLogicBool(); + exprp->dtypeSetBit(); nodep->replaceWith(exprp); nodep->sentreep(newSenTree(nodep)); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -197,7 +197,7 @@ public: // Process iterate(nodep); } - virtual ~AssertPreVisitor() override {} + virtual ~AssertPreVisitor() override = default; }; //###################################################################### diff --git a/src/V3AssertPre.h b/src/V3AssertPre.h index 41eceb57c..862756748 100644 --- a/src/V3AssertPre.h +++ b/src/V3AssertPre.h @@ -25,7 +25,7 @@ //============================================================================ -class V3AssertPre { +class V3AssertPre final { public: static void assertPreAll(AstNetlist* nodep); }; diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp index f7bf4eccd..9e2b9843b 100644 --- a/src/V3Ast.cpp +++ b/src/V3Ast.cpp @@ -127,8 +127,9 @@ string AstNode::encodeName(const string& namein) { } // Shorten names // TODO long term use VName in place of "string name" - VName vname(out); - out = vname.hashedName(); + // Then we also won't need to save the table of hased values + VName vname{out}; + return vname.hashedName(); return out; } @@ -161,7 +162,8 @@ string AstNode::dedotName(const string& namein) { string AstNode::vcdName(const string& namein) { // VCD tracing expects space to separate hierarchy // Dots are reserved for dots the user put in the name - string pretty = namein; + // We earlier hashed all symbols, dehash them so user sees real name + string pretty{VName::dehash(namein)}; string::size_type pos; while ((pos = pretty.find("__DOT__")) != string::npos) pretty.replace(pos, 7, " "); while ((pos = pretty.find('.')) != string::npos) pretty.replace(pos, 1, " "); @@ -1027,28 +1029,40 @@ void AstNode::checkTree() { } // cppcheck-suppress unusedFunction // Debug only -void AstNode::dumpGdb() { // For GDB only // LCOV_EXCL_LINE - dumpGdbHeader(); // LCOV_EXCL_LINE +void AstNode::dumpGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_LINE + if (!nodep) { + cout << "" << endl; + return; + } + nodep->dumpGdbHeader(); cout << " "; - dump(cout); - cout << endl; // LCOV_EXCL_LINE -} + nodep->dump(cout); + cout << endl; +} // LCOV_EXCL_STOP // cppcheck-suppress unusedFunction // Debug only -void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_LINE - dumpPtrs(cout); // LCOV_EXCL_LINE - cout << " Fileline = " << fileline() << endl; // LCOV_EXCL_LINE -} +void AstNode::dumpGdbHeader() const { // For GDB only // LCOV_EXCL_START + dumpPtrs(cout); + cout << " Fileline = " << fileline() << endl; +} // LCOV_EXCL_STOP // cppcheck-suppress unusedFunction // Debug only -void AstNode::dumpTreeGdb() { // For GDB only // LCOV_EXCL_LINE - dumpGdbHeader(); // LCOV_EXCL_LINE - dumpTree(cout); // LCOV_EXCL_LINE -} +void AstNode::dumpTreeGdb(const AstNode* nodep) { // For GDB only // LCOV_EXCL_START + if (!nodep) { + cout << "" << endl; + return; + } + nodep->dumpGdbHeader(); + nodep->dumpTree(cout); +} // LCOV_EXCL_STOP // cppcheck-suppress unusedFunction // Debug only -void AstNode::dumpTreeFileGdb(const char* filenamep) { // For GDB only // LCOV_EXCL_LINE - string filename - = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); // LCOV_EXCL_LINE - v3Global.rootp()->dumpTreeFile(filename); // LCOV_EXCL_LINE -} +void AstNode::dumpTreeFileGdb(const AstNode* nodep, // LCOV_EXCL_START + const char* filenamep) { // For GDB only + if (!nodep) { + cout << "" << endl; + return; + } + string filename = filenamep ? filenamep : v3Global.debugFilename("debug.tree", 98); + v3Global.rootp()->dumpTreeFile(filename); +} // LCOV_EXCL_STOP // cppcheck-suppress unusedFunction // Debug only void AstNode::checkIter() const { @@ -1086,14 +1100,14 @@ void AstNode::dumpPtrs(std::ostream& os) const { void AstNode::dumpTree(std::ostream& os, const string& indent, int maxDepth) const { static int s_debugFileline = v3Global.opt.debugSrcLevel("fileline"); // --debugi-fileline 9 - os << indent << " " << this << endl; + os << indent << " " << this << '\n'; if (debug() > 8) { os << indent << " "; dumpPtrs(os); } if (s_debugFileline >= 9) { os << fileline()->warnContextSecondary(); } if (maxDepth == 1) { - if (op1p() || op2p() || op3p() || op4p()) { os << indent << "1: ...(maxDepth)" << endl; } + if (op1p() || op2p() || op3p() || op4p()) os << indent << "1: ...(maxDepth)\n"; } else { for (const AstNode* nodep = op1p(); nodep; nodep = nodep->nextp()) { nodep->dumpTree(os, indent + "1:", maxDepth - 1); @@ -1125,9 +1139,9 @@ void AstNode::dumpTreeFile(const string& filename, bool append, bool doDump, boo const std::unique_ptr logsp(V3File::new_ofstream(filename, append)); if (logsp->fail()) v3fatal("Can't write " << filename); *logsp << "Verilator Tree Dump (format 0x3900) from to " << endl; + *logsp << "> to \n"; if (editCountGbl() == editCountLast() && !(v3Global.opt.dumpTree() >= 9)) { - *logsp << endl; + *logsp << '\n'; *logsp << "No changes since last dump!\n"; } else { dumpTree(*logsp); @@ -1197,7 +1211,7 @@ void AstNode::v3errorEnd(std::ostringstream& str) const { std::ostringstream nsstr; nsstr << str.str(); if (debug()) { - nsstr << endl; + nsstr << '\n'; nsstr << "-node: "; const_cast(this)->dump(nsstr); nsstr << endl; diff --git a/src/V3Ast.h b/src/V3Ast.h index 0c37dde78..ae9402538 100644 --- a/src/V3Ast.h +++ b/src/V3Ast.h @@ -71,7 +71,7 @@ typedef std::set MTaskIdSet; // Set of mtaskIds for Var sorting //###################################################################### -class AstType { +class AstType final { public: #include "V3Ast__gen_types.h" // From ./astgen // Above include has: @@ -94,7 +94,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstType& rhs) { return o //###################################################################### -class VLifetime { +class VLifetime final { public: enum en : uint8_t { NONE, AUTOMATIC, STATIC }; enum en m_e; @@ -123,7 +123,7 @@ inline std::ostream& operator<<(std::ostream& os, const VLifetime& rhs) { //###################################################################### -class VAccess { +class VAccess final { public: enum en : uint8_t { READ, // Read/Consumed, variable not changed @@ -166,7 +166,7 @@ inline std::ostream& operator<<(std::ostream& os, const VAccess& rhs) { return o //###################################################################### -class VSigning { +class VSigning final { public: enum en : uint8_t { UNSIGNED, @@ -203,7 +203,7 @@ inline std::ostream& operator<<(std::ostream& os, const VSigning& rhs) { //###################################################################### -class AstPragmaType { +class AstPragmaType final { public: enum en : uint8_t { ILLEGAL, @@ -236,7 +236,7 @@ inline bool operator==(AstPragmaType::en lhs, const AstPragmaType& rhs) { return //###################################################################### -class AstCFuncType { +class AstCFuncType final { public: enum en : uint8_t { FT_NORMAL, @@ -269,7 +269,7 @@ inline bool operator==(AstCFuncType::en lhs, const AstCFuncType& rhs) { return l //###################################################################### -class VEdgeType { +class VEdgeType final { public: // REMEMBER to edit the strings below too enum en : uint8_t { @@ -355,7 +355,7 @@ inline bool operator==(VEdgeType::en lhs, const VEdgeType& rhs) { return lhs == //###################################################################### -class AstAttrType { +class AstAttrType final { public: // clang-format off enum en: uint8_t { @@ -436,7 +436,7 @@ inline bool operator==(AstAttrType::en lhs, const AstAttrType& rhs) { return lhs //###################################################################### -class AstBasicDTypeKwd { +class AstBasicDTypeKwd final { public: enum en : uint8_t { UNKNOWN, @@ -450,7 +450,6 @@ public: LONGINT, DOUBLE, SHORTINT, - FLOAT, TIME, // Closer to a class type, but limited usage STRING, @@ -468,18 +467,16 @@ public: enum en m_e; const char* ascii() const { static const char* const names[] = { - "%E-unk", // - "bit", "byte", "chandle", "event", "int", "integer", "logic", - "longint", "real", "shortint", "shortreal", "time", "string", "VerilatedScope*", - "char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"}; + "%E-unk", "bit", "byte", "chandle", "event", "int", "integer", + "logic", "longint", "real", "shortint", "time", "string", "VerilatedScope*", + "char*", "IData", "QData", "LOGIC_IMPLICIT", " MAX"}; return names[m_e]; } const char* dpiType() const { static const char* const names[] - = {"%E-unk", // - "svBit", "char", "void*", "char", "int", "%E-integer", - "svLogic", "long long", "double", "short", "float", "%E-time", - "const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit", + = {"%E-unk", "svBit", "char", "void*", "char", "int", + "%E-integer", "svLogic", "long long", "double", "short", "%E-time", + "const char*", "dpiScope", "const char*", "IData", "QData", "%E-logic-implicit", " MAX"}; return names[m_e]; } @@ -508,7 +505,6 @@ public: case LOGIC: return 1; // scalar, can't bit extract unless ranged case LONGINT: return 64; case DOUBLE: return 64; // opaque - case FLOAT: return 32; // opaque case SHORTINT: return 16; case TIME: return 64; case STRING: return 64; // opaque // Just the pointer, for today @@ -521,7 +517,7 @@ public: } bool isSigned() const { return m_e == BYTE || m_e == SHORTINT || m_e == INT || m_e == LONGINT || m_e == INTEGER - || m_e == DOUBLE || m_e == FLOAT; + || m_e == DOUBLE; } bool isUnsigned() const { return m_e == CHANDLE || m_e == EVENTVALUE || m_e == STRING || m_e == SCOPEPTR @@ -532,8 +528,7 @@ public: } bool isZeroInit() const { // Otherwise initializes to X return (m_e == BIT || m_e == BYTE || m_e == CHANDLE || m_e == EVENTVALUE || m_e == INT - || m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE - || m_e == FLOAT); + || m_e == LONGINT || m_e == SHORTINT || m_e == STRING || m_e == DOUBLE); } bool isIntNumeric() const { // Enum increment supported return (m_e == BIT || m_e == BYTE || m_e == INT || m_e == INTEGER || m_e == LOGIC @@ -553,8 +548,7 @@ public: || m_e == DOUBLE || m_e == SHORTINT || m_e == UINT32 || m_e == UINT64); } bool isOpaque() const { // IE not a simple number we can bit optimize - return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == DOUBLE - || m_e == FLOAT); + return (m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR || m_e == DOUBLE); } bool isDouble() const { return m_e == DOUBLE; } bool isEventValue() const { return m_e == EVENTVALUE; } @@ -572,7 +566,7 @@ inline bool operator==(AstBasicDTypeKwd::en lhs, const AstBasicDTypeKwd& rhs) { //###################################################################### -class VDirection { +class VDirection final { public: enum en : uint8_t { NONE, INPUT, OUTPUT, INOUT, REF, CONSTREF }; enum en m_e; @@ -617,7 +611,7 @@ inline std::ostream& operator<<(std::ostream& os, const VDirection& rhs) { //###################################################################### /// Boolean or unknown -class VBoolOrUnknown { +class VBoolOrUnknown final { public: enum en : uint8_t { BU_FALSE = 0, BU_TRUE = 1, BU_UNKNOWN = 2, _ENUM_END }; enum en m_e; @@ -656,7 +650,7 @@ inline std::ostream& operator<<(std::ostream& os, const VBoolOrUnknown& rhs) { //###################################################################### /// Join type -class VJoinType { +class VJoinType final { public: enum en : uint8_t { JOIN = 0, JOIN_ANY = 1, JOIN_NONE = 2 }; enum en m_e; @@ -689,7 +683,7 @@ inline std::ostream& operator<<(std::ostream& os, const VJoinType& rhs) { //###################################################################### -class AstVarType { +class AstVarType final { public: enum en : uint8_t { UNKNOWN, @@ -757,7 +751,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstVarType& rhs) { //###################################################################### -class VBranchPred { +class VBranchPred final { public: enum en : uint8_t { BP_UNKNOWN = 0, BP_LIKELY, BP_UNLIKELY, _ENUM_END }; enum en m_e; @@ -798,7 +792,7 @@ inline std::ostream& operator<<(std::ostream& os, const VBranchPred& rhs) { //###################################################################### -class VVarAttrClocker { +class VVarAttrClocker final { public: enum en : uint8_t { CLOCKER_UNKNOWN = 0, CLOCKER_YES, CLOCKER_NO, _ENUM_END }; enum en m_e; @@ -841,7 +835,7 @@ inline std::ostream& operator<<(std::ostream& os, const VVarAttrClocker& rhs) { //###################################################################### -class VAlwaysKwd { +class VAlwaysKwd final { public: enum en : uint8_t { ALWAYS, ALWAYS_FF, ALWAYS_LATCH, ALWAYS_COMB }; enum en m_e; @@ -864,7 +858,7 @@ inline bool operator==(VAlwaysKwd::en lhs, const VAlwaysKwd& rhs) { return lhs = //###################################################################### -class VCaseType { +class VCaseType final { public: enum en : uint8_t { CT_CASE, CT_CASEX, CT_CASEZ, CT_CASEINSIDE }; enum en m_e; @@ -883,14 +877,23 @@ inline bool operator==(VCaseType::en lhs, const VCaseType& rhs) { return lhs == //###################################################################### -class AstDisplayType { +class AstDisplayType final { public: - enum en : uint8_t { DT_DISPLAY, DT_WRITE, DT_INFO, DT_ERROR, DT_WARNING, DT_FATAL }; + enum en : uint8_t { + DT_DISPLAY, + DT_WRITE, + DT_MONITOR, + DT_STROBE, + DT_INFO, + DT_ERROR, + DT_WARNING, + DT_FATAL + }; enum en m_e; - inline AstDisplayType() + AstDisplayType() : m_e{DT_DISPLAY} {} // cppcheck-suppress noExplicitConstructor - inline AstDisplayType(en _e) + AstDisplayType(en _e) : m_e{_e} {} explicit inline AstDisplayType(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning @@ -899,7 +902,7 @@ public: bool needScopeTracking() const { return m_e != DT_DISPLAY && m_e != DT_WRITE; } const char* ascii() const { static const char* const names[] - = {"display", "write", "info", "error", "warning", "fatal"}; + = {"display", "write", "monitor", "strobe", "info", "error", "warning", "fatal"}; return names[m_e]; } }; @@ -915,7 +918,7 @@ inline bool operator==(AstDisplayType::en lhs, const AstDisplayType& rhs) { //###################################################################### -class VDumpCtlType { +class VDumpCtlType final { public: enum en : uint8_t { FILE, VARS, ALL, FLUSH, LIMIT, OFF, ON }; enum en m_e; @@ -941,7 +944,7 @@ inline bool operator==(VDumpCtlType::en lhs, const VDumpCtlType& rhs) { return l //###################################################################### -class VParseRefExp { +class VParseRefExp final { public: enum en : uint8_t { PX_NONE, // Used in V3LinkParse only @@ -975,10 +978,10 @@ inline std::ostream& operator<<(std::ostream& os, const VParseRefExp& rhs) { // VNumRange - Structure containing numeric range information // See also AstRange, which is a symbolic version of this -class VNumRange { +class VNumRange final { public: - int m_hi; // HI part, HI always >= LO - int m_lo; // LO + int m_hi = 0; // HI part, HI always >= LO + int m_lo = 0; // LO union { int mu_flags; struct { @@ -986,10 +989,10 @@ public: bool m_littleEndian : 1; // Bit vector is little endian }; }; - inline bool operator==(const VNumRange& rhs) const { + bool operator==(const VNumRange& rhs) const { return m_hi == rhs.m_hi && m_lo == rhs.m_lo && mu_flags == rhs.mu_flags; } - inline bool operator<(const VNumRange& rhs) const { + bool operator<(const VNumRange& rhs) const { if ((m_hi < rhs.m_hi)) return true; if (!(m_hi == rhs.m_hi)) return false; // lhs > rhs if ((m_lo < rhs.m_lo)) return true; @@ -1001,22 +1004,16 @@ public: // class LeftRight {}; VNumRange() - : m_hi{0} - , m_lo{0} - , mu_flags{0} {} + : mu_flags{0} {} VNumRange(int hi, int lo, bool littleEndian) - : m_hi{0} - , m_lo{0} - , mu_flags{0} { + : mu_flags{0} { init(hi, lo, littleEndian); } VNumRange(LeftRight, int left, int right) - : m_hi{0} - , m_lo{0} - , mu_flags{0} { + : mu_flags{0} { init((right > left) ? right : left, (right > left) ? left : right, (right > left)); } - ~VNumRange() {} + ~VNumRange() = default; // MEMBERS void init(int hi, int lo, bool littleEndian) { m_hi = hi; @@ -1054,7 +1051,7 @@ inline std::ostream& operator<<(std::ostream& os, const VNumRange& rhs) { //###################################################################### -class VUseType { +class VUseType final { public: enum en : uint8_t { IMP_INCLUDE, // Implementation (.cpp) needs an include @@ -1087,18 +1084,18 @@ inline std::ostream& operator<<(std::ostream& os, const VUseType& rhs) { //###################################################################### -class VBasicTypeKey { +class VBasicTypeKey final { public: int m_width; // From AstNodeDType: Bit width of operation int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation VSigning m_numeric; // From AstNodeDType: Node is signed AstBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword) - inline bool operator==(const VBasicTypeKey& rhs) const { + bool operator==(const VBasicTypeKey& rhs) const { return m_width == rhs.m_width && m_widthMin == rhs.m_widthMin && m_numeric == rhs.m_numeric && m_keyword == rhs.m_keyword && m_nrange == rhs.m_nrange; } - inline bool operator<(const VBasicTypeKey& rhs) const { + bool operator<(const VBasicTypeKey& rhs) const { if ((m_width < rhs.m_width)) return true; if (!(m_width == rhs.m_width)) return false; // lhs > rhs if ((m_widthMin < rhs.m_widthMin)) return true; @@ -1118,7 +1115,7 @@ public: , m_numeric{numeric} , m_keyword{kwd} , m_nrange{nrange} {} - ~VBasicTypeKey() {} + ~VBasicTypeKey() = default; }; //###################################################################### @@ -1129,7 +1126,7 @@ class WidthVP; class V3GraphVertex; class VSymEnt; -class VNUser { +class VNUser final { union { void* up; int ui; @@ -1144,14 +1141,14 @@ public: m_u.ui = i; } explicit VNUser(void* p) { m_u.up = p; } - ~VNUser() {} + ~VNUser() = default; // Casters WidthVP* c() const { return reinterpret_cast(m_u.up); } VSymEnt* toSymEnt() const { return reinterpret_cast(m_u.up); } AstNode* toNodep() const { return reinterpret_cast(m_u.up); } V3GraphVertex* toGraphVertex() const { return reinterpret_cast(m_u.up); } int toInt() const { return m_u.ui; } - static inline VNUser fromInt(int i) { return VNUser(i); } + static VNUser fromInt(int i) { return VNUser(i); } }; //###################################################################### @@ -1165,7 +1162,7 @@ public: // user2. When the member goes out of scope it will be automagically // freed up. -class AstUserInUseBase { +class AstUserInUseBase VL_NOT_FINAL { protected: static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) { // Perhaps there's still a AstUserInUse in scope for this? @@ -1196,7 +1193,7 @@ protected: // We let AstNode peek into here, because when under low optimization even // an accessor would be way too slow. // clang-format off -class AstUser1InUse : AstUserInUseBase { +class AstUser1InUse final : AstUserInUseBase { protected: friend class AstNode; static uint32_t s_userCntGbl; // Count of which usage of userp() this is @@ -1207,7 +1204,7 @@ public: static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; -class AstUser2InUse : AstUserInUseBase { +class AstUser2InUse final : AstUserInUseBase { protected: friend class AstNode; static uint32_t s_userCntGbl; // Count of which usage of userp() this is @@ -1218,7 +1215,7 @@ public: static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; -class AstUser3InUse : AstUserInUseBase { +class AstUser3InUse final : AstUserInUseBase { protected: friend class AstNode; static uint32_t s_userCntGbl; // Count of which usage of userp() this is @@ -1229,7 +1226,7 @@ public: static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; -class AstUser4InUse : AstUserInUseBase { +class AstUser4InUse final : AstUserInUseBase { protected: friend class AstNode; static uint32_t s_userCntGbl; // Count of which usage of userp() this is @@ -1240,7 +1237,7 @@ public: static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } static void check() { checkcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); } }; -class AstUser5InUse : AstUserInUseBase { +class AstUser5InUse final : AstUserInUseBase { protected: friend class AstNode; static uint32_t s_userCntGbl; // Count of which usage of userp() this is @@ -1257,7 +1254,7 @@ public: // AstNVisitor -- Allows new functions to be called on each node // type without changing the base classes. See "Modern C++ Design". -class AstNVisitor { +class AstNVisitor VL_NOT_FINAL { private: // MEMBERS std::vector m_deleteps; // Nodes to delete when doDeletes() called @@ -1304,7 +1301,7 @@ public: // AstNRelinker -- Holds the state of a unlink so a new node can be // added at the same point. -class AstNRelinker { +class AstNRelinker final { protected: friend class AstNode; enum RelinkWhatEn : uint8_t { @@ -1321,7 +1318,7 @@ protected: AstNode** m_iterpp = nullptr; public: - AstNRelinker() {} + AstNRelinker() = default; void relink(AstNode* newp); AstNode* oldp() const { return m_oldp; } void dump(std::ostream& str = std::cout) const; @@ -1334,7 +1331,7 @@ inline std::ostream& operator<<(std::ostream& os, const AstNRelinker& rhs) { //###################################################################### // V3Hash -- Node hashing for V3Combine -class V3Hash { +class V3Hash final { // A hash of a tree of nodes, consisting of 8 bits with the number of nodes in the hash // and 24 bit value hash of relevant information about the node. // A value of 0 is illegal @@ -1353,9 +1350,9 @@ public: uint32_t depth() const { return (m_both >> 24) & 255; } uint32_t hshval() const { return m_both & M24; } // OPERATORS - inline bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; } - inline bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; } - inline bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; } + bool operator==(const V3Hash& rh) const { return m_both == rh.m_both; } + bool operator!=(const V3Hash& rh) const { return m_both != rh.m_both; } + bool operator<(const V3Hash& rh) const { return m_both < rh.m_both; } // CONSTRUCTORS class Illegal {}; // for creator type-overload selection class FullValue {}; // for creator type-overload selection @@ -1387,7 +1384,7 @@ std::ostream& operator<<(std::ostream& os, const V3Hash& rhs); //###################################################################### // Callback base class to determine if node matches some formula -class VNodeMatcher { +class VNodeMatcher VL_NOT_FINAL { public: virtual bool nodeMatch(const AstNode* nodep) const { return true; } }; @@ -1401,11 +1398,11 @@ public: do { \ if (nodep) { \ VL_PREFETCH_RD(&((nodep)->m_nextp)); \ - VL_PREFETCH_RD(&((nodep)->m_iterpp)); \ + VL_PREFETCH_RD(&((nodep)->m_type)); \ } \ } while (false) -class AstNode { +class AstNode VL_NOT_FINAL { // v ASTNODE_PREFETCH depends on below ordering of members AstNode* m_nextp; // Next peer in the parent's list AstNode* m_backp; // Node that points to this one (via next/op1/op2/...) @@ -1414,22 +1411,21 @@ class AstNode { AstNode* m_op3p; // Generic pointer 3 AstNode* m_op4p; // Generic pointer 4 AstNode** m_iterpp; // Pointer to node iterating on, change it if we replace this node. + const AstType m_type; // Node sub-type identifier // ^ ASTNODE_PREFETCH depends on above ordering of members + // padding - 2 extra bytes here after m_type + int m_cloneCnt; // Mark of when userp was set + + AstNodeDType* m_dtypep; // Data type of output or assignment (etc) AstNode* m_headtailp; // When at begin/end of list, the opposite end of the list - - const AstType m_type; // Node sub-type identifier - FileLine* m_fileline; // Where it was declared vluint64_t m_editCount; // When it was last edited static vluint64_t s_editCntGbl; // Global edit counter // Global edit counter, last value for printing * near node #s static vluint64_t s_editCntLast; - AstNodeDType* m_dtypep; // Data type of output or assignment (etc) - AstNode* m_clonep; // Pointer to clone of/ source of this module (for *LAST* cloneTree() ONLY) - int m_cloneCnt; // Mark of when userp was set static int s_cloneCntGbl; // Count of which userp is set // Attributes @@ -1545,7 +1541,7 @@ public: bool brokeExistsBelow() const; // CONSTRUCTORS - virtual ~AstNode() {} + virtual ~AstNode() = default; #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); @@ -1734,7 +1730,7 @@ public: void dtypeSetLogicSized(int width, VSigning numeric) { dtypep(findLogicDType(width, width, numeric)); // Since sized, widthMin is width } - void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); } + void dtypeSetBit() { dtypep(findBitDType()); } void dtypeSetDouble() { dtypep(findDoubleDType()); } void dtypeSetString() { dtypep(findStringDType()); } void dtypeSetSigned32() { dtypep(findSigned32DType()); } @@ -1743,7 +1739,7 @@ public: void dtypeSetVoid() { dtypep(findVoidDType()); } // Data type locators - AstNodeDType* findLogicBoolDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); } + AstNodeDType* findBitDType() { return findBasicDType(AstBasicDTypeKwd::LOGIC); } AstNodeDType* findDoubleDType() { return findBasicDType(AstBasicDTypeKwd::DOUBLE); } AstNodeDType* findStringDType() { return findBasicDType(AstBasicDTypeKwd::STRING); } AstNodeDType* findSigned32DType() { return findBasicDType(AstBasicDTypeKwd::INTEGER); } @@ -1768,7 +1764,7 @@ public: string warnOther() const { return fileline()->warnOther(); } virtual void dump(std::ostream& str = std::cout) const; - void dumpGdb(); // For GDB only + static void dumpGdb(const AstNode* nodep); // For GDB only void dumpGdbHeader() const; // METHODS - Tree modifications @@ -1818,12 +1814,12 @@ public: void dumpTree(const string& indent, int maxDepth = 0) const { dumpTree(cout, indent, maxDepth); } - void dumpTreeGdb(); // For GDB only + static void dumpTreeGdb(const AstNode* nodep); // For GDB only void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ", int maxDepth = 0) const; void dumpTreeFile(const string& filename, bool append = false, bool doDump = true, bool doCheck = true); - static void dumpTreeFileGdb(const char* filenamep = nullptr); + static void dumpTreeFileGdb(const AstNode* nodep, const char* filenamep = nullptr); // METHODS - queries // Changes control flow, disable some optimizations @@ -1912,7 +1908,7 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } //=== AstNode* : Derived generic node types #define ASTNODE_BASE_FUNCS(name) \ - virtual ~Ast##name() {} \ + virtual ~Ast##name() override = default; \ static Ast##name* cloneTreeNull(Ast##name* nodep, bool cloneNextLink) { \ return nodep ? nodep->cloneTree(cloneNextLink) : nullptr; \ } \ @@ -1921,7 +1917,7 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); } } \ Ast##name* clonep() const { return static_cast(AstNode::clonep()); } -class AstNodeMath : public AstNode { +class AstNodeMath VL_NOT_FINAL : public AstNode { // Math -- anything that's part of an expression tree public: AstNodeMath(AstType t, FileLine* fl) @@ -1941,7 +1937,7 @@ public: bool isOpaque() { return VN_IS(this, CvtPackString); } }; -class AstNodeTermop : public AstNodeMath { +class AstNodeTermop VL_NOT_FINAL : public AstNodeMath { // Terminal operator -- a operator with no "inputs" public: AstNodeTermop(AstType t, FileLine* fl) @@ -1954,7 +1950,7 @@ public: virtual void dump(std::ostream& str) const override; }; -class AstNodeUniop : public AstNodeMath { +class AstNodeUniop VL_NOT_FINAL : public AstNodeMath { // Unary math public: AstNodeUniop(AstType t, FileLine* fl, AstNode* lhsp) @@ -1980,7 +1976,7 @@ public: virtual bool same(const AstNode*) const override { return true; } }; -class AstNodeBiop : public AstNodeMath { +class AstNodeBiop VL_NOT_FINAL : public AstNodeMath { // Binary math public: AstNodeBiop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) @@ -2012,7 +2008,7 @@ public: virtual bool same(const AstNode*) const override { return true; } }; -class AstNodeTriop : public AstNodeMath { +class AstNodeTriop VL_NOT_FINAL : public AstNodeMath { // Trinary math public: AstNodeTriop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) @@ -2045,7 +2041,7 @@ public: virtual bool same(const AstNode*) const override { return true; } }; -class AstNodeQuadop : public AstNodeMath { +class AstNodeQuadop VL_NOT_FINAL : public AstNodeMath { // Quaternary math public: AstNodeQuadop(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths, AstNode* fhs) @@ -2082,7 +2078,7 @@ public: virtual bool same(const AstNode*) const override { return true; } }; -class AstNodeBiCom : public AstNodeBiop { +class AstNodeBiCom VL_NOT_FINAL : public AstNodeBiop { // Binary math with commutative properties public: AstNodeBiCom(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) @@ -2090,14 +2086,14 @@ public: ASTNODE_BASE_FUNCS(NodeBiCom) }; -class AstNodeBiComAsv : public AstNodeBiCom { +class AstNodeBiComAsv VL_NOT_FINAL : public AstNodeBiCom { // Binary math with commutative & associative properties public: AstNodeBiComAsv(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs) : AstNodeBiCom{t, fl, lhs, rhs} {} ASTNODE_BASE_FUNCS(NodeBiComAsv) }; -class AstNodeCond : public AstNodeTriop { +class AstNodeCond VL_NOT_FINAL : public AstNodeTriop { public: AstNodeCond(AstType t, FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p) : AstNodeTriop{t, fl, condp, expr1p, expr2p} { @@ -2128,7 +2124,7 @@ public: virtual AstNode* cloneType(AstNode* condp, AstNode* expr1p, AstNode* expr2p) = 0; }; -class AstNodeBlock : public AstNode { +class AstNodeBlock VL_NOT_FINAL : public AstNode { // A Begin/fork block // Parents: statement // Children: statements @@ -2152,7 +2148,7 @@ public: bool unnamed() const { return m_unnamed; } }; -class AstNodePreSel : public AstNode { +class AstNodePreSel VL_NOT_FINAL : public AstNode { // Something that becomes an AstSel public: AstNodePreSel(AstType t, FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths) @@ -2176,7 +2172,7 @@ public: virtual bool same(const AstNode*) const override { return true; } }; -class AstNodeProcedure : public AstNode { +class AstNodeProcedure VL_NOT_FINAL : public AstNode { // IEEE procedure: initial, final, always public: AstNodeProcedure(AstType t, FileLine* fl, AstNode* bodysp) @@ -2191,7 +2187,7 @@ public: bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; -class AstNodeStmt : public AstNode { +class AstNodeStmt VL_NOT_FINAL : public AstNode { // Statement -- anything that's directly under a function bool m_statement; // Really a statement (e.g. not a function with return) public: @@ -2209,7 +2205,7 @@ public: virtual void dump(std::ostream& str = std::cout) const override; }; -class AstNodeAssign : public AstNodeStmt { +class AstNodeAssign VL_NOT_FINAL : public AstNodeStmt { public: AstNodeAssign(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStmt{t, fl} { @@ -2234,7 +2230,7 @@ public: virtual bool brokeLhsMustBeLvalue() const = 0; }; -class AstNodeFor : public AstNodeStmt { +class AstNodeFor VL_NOT_FINAL : public AstNodeStmt { public: AstNodeFor(AstType t, FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) @@ -2255,7 +2251,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstNodeIf : public AstNodeStmt { +class AstNodeIf VL_NOT_FINAL : public AstNodeStmt { private: VBranchPred m_branchPred; // Branch prediction as taken/untaken? public: @@ -2281,7 +2277,7 @@ public: VBranchPred branchPred() const { return m_branchPred; } }; -class AstNodeCase : public AstNodeStmt { +class AstNodeCase VL_NOT_FINAL : public AstNodeStmt { public: AstNodeCase(AstType t, FileLine* fl, AstNode* exprp, AstNode* casesp) : AstNodeStmt{t, fl} { @@ -2299,15 +2295,16 @@ public: void addNotParallelp(AstNode* nodep) { setOp3p(nodep); } }; -class AstNodeVarRef : public AstNodeMath { +class AstNodeVarRef VL_NOT_FINAL : public AstNodeMath { // An AstVarRef or AstVarXRef private: VAccess m_access; // Left hand side assignment AstVar* m_varp; // [AfterLink] Pointer to variable itself AstVarScope* m_varScopep = nullptr; // Varscope for hierarchy - AstNodeModule* m_packagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy string m_name; // Name of variable - string m_hiername; // Scope converted into name-> for emitting + string m_hiernameToProt; // Scope converted into name-> for emitting + string m_hiernameToUnprot; // Scope converted into name-> for emitting bool m_hierThis = false; // Hiername points to "this" function public: @@ -2338,20 +2335,22 @@ public: void varp(AstVar* varp); AstVarScope* varScopep() const { return m_varScopep; } void varScopep(AstVarScope* varscp) { m_varScopep = varscp; } - string hiername() const { return m_hiername; } + string hiernameToProt() const { return m_hiernameToProt; } + void hiernameToProt(const string& hn) { m_hiernameToProt = hn; } + string hiernameToUnprot() const { return m_hiernameToUnprot; } + void hiernameToUnprot(const string& hn) { m_hiernameToUnprot = hn; } string hiernameProtect() const; - void hiername(const string& hn) { m_hiername = hn; } bool hierThis() const { return m_hierThis; } void hierThis(bool flag) { m_hierThis = flag; } - AstNodeModule* packagep() const { return m_packagep; } - void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } // Know no children, and hot function, so skip iterator for speed // See checkTreeIter also that asserts no children // cppcheck-suppress functionConst void iterateChildren(AstNVisitor& v) {} }; -class AstNodeText : public AstNode { +class AstNodeText VL_NOT_FINAL : public AstNode { private: string m_text; @@ -2371,7 +2370,7 @@ public: const string& text() const { return m_text; } }; -class AstNodeDType : public AstNode { +class AstNodeDType VL_NOT_FINAL : public AstNode { // Ideally width() would migrate to BasicDType as that's where it makes sense, // but it's currently so prevalent in the code we leave it here. // Note the below members are included in AstTypeTable::Key lookups @@ -2467,7 +2466,7 @@ private: CTypeRecursed cTypeRecurse(bool compound) const; }; -class AstNodeUOrStructDType : public AstNodeDType { +class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType { // A struct or union; common handling private: // TYPES @@ -2531,7 +2530,7 @@ public: VNumRange declRange() const { return VNumRange(msb(), lsb(), false); } }; -class AstNodeArrayDType : public AstNodeDType { +class AstNodeArrayDType VL_NOT_FINAL : public AstNodeDType { // Array data type, ie "some_dtype var_name [2:0]" // Children: DTYPE (moved to refDTypep() in V3Width) // Children: RANGE (array bounds) @@ -2594,7 +2593,7 @@ public: VNumRange declRange() const; }; -class AstNodeSel : public AstNodeBiop { +class AstNodeSel VL_NOT_FINAL : public AstNodeBiop { // Single bit range extraction, perhaps with non-constant selection or array selection public: AstNodeSel(AstType t, FileLine* fl, AstNode* fromp, AstNode* bitp) @@ -2610,7 +2609,7 @@ public: virtual bool hasDType() const override { return true; } }; -class AstNodeStream : public AstNodeBiop { +class AstNodeStream VL_NOT_FINAL : public AstNodeBiop { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstNodeStream(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -2623,11 +2622,12 @@ public: //###################################################################### // Tasks/functions common handling -class AstNodeCCall : public AstNodeStmt { +class AstNodeCCall VL_NOT_FINAL : public AstNodeStmt { // A call of a C++ function, perhaps a AstCFunc or perhaps globally named // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. AstCFunc* m_funcp; - string m_hiername; + string m_hiernameToProt; + string m_hiernameToUnprot; string m_argTypes; public: @@ -2641,7 +2641,8 @@ public: AstNodeCCall(AstType t, AstNodeCCall* oldp, AstCFunc* funcp) : AstNodeStmt{t, oldp->fileline(), true} , m_funcp{funcp} { - m_hiername = oldp->hiername(); + m_hiernameToProt = oldp->hiernameToProt(); + m_hiernameToUnprot = oldp->hiernameToUnprot(); m_argTypes = oldp->argTypes(); if (oldp->argsp()) addNOp2p(oldp->argsp()->unlinkFrBackWithNext()); } @@ -2661,8 +2662,10 @@ public: virtual bool isPure() const override; virtual bool isOutputter() const override { return !isPure(); } AstCFunc* funcp() const { return m_funcp; } - string hiername() const { return m_hiername; } - void hiername(const string& hn) { m_hiername = hn; } + string hiernameToProt() const { return m_hiernameToProt; } + void hiernameToProt(const string& hn) { m_hiernameToProt = hn; } + string hiernameToUnprot() const { return m_hiernameToUnprot; } + void hiernameToUnprot(const string& hn) { m_hiernameToUnprot = hn; } string hiernameProtect() const; void argTypes(const string& str) { m_argTypes = str; } string argTypes() const { return m_argTypes; } @@ -2671,7 +2674,7 @@ public: void addArgsp(AstNode* nodep) { addOp2p(nodep); } }; -class AstNodeFTask : public AstNode { +class AstNodeFTask VL_NOT_FINAL : public AstNode { private: string m_name; // Name of task string m_cname; // Name of task if DPI import @@ -2688,6 +2691,8 @@ private: bool m_dpiOpenChild : 1; // DPI import open array child wrapper bool m_dpiTask : 1; // DPI import task (vs. void function) bool m_isConstructor : 1; // Class constructor + bool m_isHideLocal : 1; // Verilog local + bool m_isHideProtected : 1; // Verilog protected bool m_pure : 1; // DPI import pure (vs. virtual pure) bool m_pureVirtual : 1; // Pure virtual bool m_virtual : 1; // Virtual method in class @@ -2708,6 +2713,8 @@ public: , m_dpiOpenChild{false} , m_dpiTask{false} , m_isConstructor{false} + , m_isHideLocal{false} + , m_isHideProtected{false} , m_pure{false} , m_pureVirtual{false} , m_virtual{false} { @@ -2730,8 +2737,8 @@ public: void addFvarp(AstNode* nodep) { addNOp1p(nodep); } bool isFunction() const { return fvarp() != nullptr; } // op2 = Class/package scope - AstNode* packagep() const { return op2p(); } - void packagep(AstNode* nodep) { setNOp2p(nodep); } + AstNode* classOrPackagep() const { return op2p(); } + void classOrPackagep(AstNode* nodep) { setNOp2p(nodep); } // op3 = Statements/Ports/Vars AstNode* stmtsp() const { return op3p(); } // op3 = List of statements void addStmtsp(AstNode* nodep) { addNOp3p(nodep); } @@ -2766,6 +2773,10 @@ public: bool dpiTask() const { return m_dpiTask; } void isConstructor(bool flag) { m_isConstructor = flag; } bool isConstructor() const { return m_isConstructor; } + bool isHideLocal() const { return m_isHideLocal; } + void isHideLocal(bool flag) { m_isHideLocal = flag; } + bool isHideProtected() const { return m_isHideProtected; } + void isHideProtected(bool flag) { m_isHideProtected = flag; } void pure(bool flag) { m_pure = flag; } bool pure() const { return m_pure; } void pureVirtual(bool flag) { m_pureVirtual = flag; } @@ -2776,12 +2787,12 @@ public: VLifetime lifetime() const { return m_lifetime; } }; -class AstNodeFTaskRef : public AstNodeStmt { +class AstNodeFTaskRef VL_NOT_FINAL : public AstNodeStmt { // A reference to a task (or function) // Functions are not statements, while tasks are. AstNodeStmt needs isStatement() to deal. private: AstNodeFTask* m_taskp = nullptr; // [AfterLink] Pointer to task referenced - AstNodeModule* m_packagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy string m_name; // Name of variable string m_dotted; // Dotted part of scope the name()ed task/func is under or "" string m_inlinedDots; // Dotted hierarchy flattened out @@ -2815,8 +2826,8 @@ public: void taskp(AstNodeFTask* taskp) { m_taskp = taskp; } virtual void name(const string& name) override { m_name = name; } void dotted(const string& name) { m_dotted = name; } - AstNodeModule* packagep() const { return m_packagep; } - void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } bool pli() const { return m_pli; } void pli(bool flag) { m_pli = flag; } // op1 = namep @@ -2830,7 +2841,7 @@ public: void scopeNamep(AstNode* nodep) { setNOp4p(nodep); } }; -class AstNodeModule : public AstNode { +class AstNodeModule VL_NOT_FINAL : public AstNode { // A module, package, program or interface declaration; // something that can live directly under the TOP, // excluding $unit package stuff @@ -2909,7 +2920,7 @@ public: VOptionBool unconnectedDrive() const { return m_unconnectedDrive; } }; -class AstNodeRange : public AstNode { +class AstNodeRange VL_NOT_FINAL : public AstNode { // A range, sized or unsized public: AstNodeRange(AstType t, FileLine* fl) @@ -3001,7 +3012,7 @@ inline VNumRange AstNodeArrayDType::declRange() const { inline const char* AstNodeFTaskRef::broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); - BROKEN_RTN(m_packagep && !m_packagep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); return nullptr; } diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp index c620cb432..a8f0bcba0 100644 --- a/src/V3AstNodes.cpp +++ b/src/V3AstNodes.cpp @@ -54,7 +54,7 @@ void AstNodeVarRef::cloneRelink() { } string AstNodeVarRef::hiernameProtect() const { - return VIdProtect::protectWordsIf(hiername(), protect()); + return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect()); } int AstNodeSel::bitConst() const { @@ -107,7 +107,7 @@ const char* AstNodeCCall::broken() const { } bool AstNodeCCall::isPure() const { return funcp()->pure(); } string AstNodeCCall::hiernameProtect() const { - return VIdProtect::protectWordsIf(hiername(), protect()); + return hiernameToUnprot() + VIdProtect::protectWordsIf(hiernameToProt(), protect()); } void AstNodeCond::numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs, @@ -455,38 +455,99 @@ string AstVar::cPubArgType(bool named, bool forReturn) const { return arg; } -string AstVar::dpiArgType(bool named, bool forReturn) const { - if (forReturn) named = false; - string arg; - if (isDpiOpenArray()) { - arg = "const svOpenArrayHandle"; - } else if (!basicp()) { - arg = "UNKNOWN"; - } else if (basicp()->isDpiBitVec()) { - if (forReturn) { - arg = "svBitVecVal"; - } else if (isReadOnly()) { - arg = "const svBitVecVal*"; - } else { - arg = "svBitVecVal*"; - } - } else if (basicp()->isDpiLogicVec()) { - if (forReturn) { - arg = "svLogicVecVal"; - } else if (isReadOnly()) { - arg = "const svLogicVecVal*"; - } else { - arg = "svLogicVecVal*"; - } - } else { - arg = basicp()->keyword().dpiType(); - if (basicp()->keyword().isDpiUnsignable() && !basicp()->isSigned()) { - arg = "unsigned " + arg; - } - if (!forReturn && isWritable()) arg += "*"; +class dpiTypesToStringConverter VL_NOT_FINAL { +public: + virtual string openArray(const AstVar*) const { return "const svOpenArrayHandle"; } + virtual string bitLogicVector(const AstVar* varp, bool isBit) const { + return isBit ? "svBitVecVal" : "svLogicVecVal"; } - if (named) arg += " " + name(); - return arg; + virtual string primitive(const AstVar* varp) const { + string type; + if (varp->basicp()->keyword().isDpiUnsignable() && !varp->basicp()->isSigned()) { + type = "unsigned "; + } + type += varp->basicp()->keyword().dpiType(); + return type; + } + string convert(const AstVar* varp) const { + if (varp->isDpiOpenArray()) { + return openArray(varp); + } else if (!varp->basicp()) { + return "UNKNOWN"; + } else if (varp->basicp()->isDpiBitVec() || varp->basicp()->isDpiLogicVec()) { + return bitLogicVector(varp, varp->basicp()->isDpiBitVec()); + } else { + return primitive(varp); + } + } +}; + +string AstVar::dpiArgType(bool named, bool forReturn) const { + if (forReturn) { + return dpiTypesToStringConverter{}.convert(this); + } else { + class converter final : public dpiTypesToStringConverter { + virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { + return string(varp->isReadOnly() ? "const " : "") + + dpiTypesToStringConverter::bitLogicVector(varp, isBit) + '*'; + } + virtual string primitive(const AstVar* varp) const override { + string type = dpiTypesToStringConverter::primitive(varp); + if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { + if (!varp->isWritable() + && varp->basicp()->keyword() != AstBasicDTypeKwd::STRING) + type = "const " + type; + type += "*"; + } + return type; + } + }; + string arg = converter{}.convert(this); + if (named) arg += " " + name(); + return arg; + } +} + +string AstVar::dpiTmpVarType(const string& varName) const { + class converter final : public dpiTypesToStringConverter { + string m_name; + string arraySuffix(const AstVar* varp, size_t n) const { + if (AstUnpackArrayDType* unpackp + = VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) { + // Convert multi dimensional unpacked array to 1D array + if (n == 0) n = 1; + n *= unpackp->arrayUnpackedElements(); + return '[' + cvtToStr(n) + ']'; + } else if (n > 0) { + return '[' + cvtToStr(n) + ']'; + } else { + return ""; + } + } + virtual string openArray(const AstVar* varp) const override { + return dpiTypesToStringConverter::openArray(varp) + ' ' + m_name + + arraySuffix(varp, 0); + } + virtual string bitLogicVector(const AstVar* varp, bool isBit) const override { + string type = dpiTypesToStringConverter::bitLogicVector(varp, isBit); + type += ' ' + m_name + arraySuffix(varp, varp->widthWords()); + return type; + } + virtual string primitive(const AstVar* varp) const override { + string type = dpiTypesToStringConverter::primitive(varp); + if (varp->isWritable() || VN_IS(varp->dtypep()->skipRefp(), UnpackArrayDType)) { + if (!varp->isWritable() && varp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) + type = "const " + type; + } + type += ' ' + m_name + arraySuffix(varp, 0); + return type; + } + + public: + explicit converter(const string& name) + : m_name(name) {} + }; + return converter{varName}.convert(this); } string AstVar::scType() const { @@ -553,7 +614,7 @@ string AstVar::mtasksString() const { return os.str(); } -class AstNodeDType::CTypeRecursed { +class AstNodeDType::CTypeRecursed final { public: string m_type; // The base type, e.g.: "Foo_t"s string m_dims; // Array dimensions, e.g.: "[3][2][1]" @@ -610,8 +671,6 @@ AstNodeDType::CTypeRecursed AstNodeDType::cTypeRecurse(bool compound) const { info.m_type = "const VerilatedScope*"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::DOUBLE) { info.m_type = "double"; - } else if (bdtypep->keyword() == AstBasicDTypeKwd::FLOAT) { - info.m_type = "float"; } else if (bdtypep->keyword() == AstBasicDTypeKwd::STRING) { info.m_type = "std::string"; } else if (dtypep->widthMin() <= 8) { // Handle unpacked arrays; not bdtypep->width @@ -1112,6 +1171,13 @@ void AstClass::repairCache() { clearCache(); for (AstNode* itemp = membersp(); itemp; itemp = itemp->nextp()) { insertCache(itemp); } } +bool AstClass::isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp) { + // TAIL RECURSIVE + if (!refClassp || !baseClassp) return false; + if (refClassp == baseClassp) return true; + if (!refClassp->extendsp()) return false; + return isClassExtendedFrom(refClassp->extendsp()->classp(), baseClassp); +} void AstClass::dump(std::ostream& str) const { this->AstNode::dump(str); if (isExtended()) str << " [EXT]"; @@ -1119,6 +1185,9 @@ void AstClass::dump(std::ostream& str) const { } AstClass* AstClassExtends::classp() const { AstClassRefDType* refp = VN_CAST(dtypep(), ClassRefDType); + if (VL_UNLIKELY(!refp)) { // LinkDot uses this for 'super.' + refp = VN_CAST(childDTypep(), ClassRefDType); + } UASSERT_OBJ(refp, this, "class extends non-ref"); return refp->classp(); } @@ -1347,6 +1416,18 @@ string AstUnpackArrayDType::prettyDTypeName() const { os << subp->prettyDTypeName() << "$" << ranges; return os.str(); } +std::vector AstUnpackArrayDType::unpackDimensions() { + std::vector dims; + for (AstUnpackArrayDType* unpackp = this; unpackp;) { + dims.push_back(unpackp); + if (AstNodeDType* subp = unpackp->subDTypep()) { + unpackp = VN_CAST(subp, UnpackArrayDType); + } else { + unpackp = nullptr; + } + } + return dims; +} void AstNetlist::dump(std::ostream& str) const { this->AstNode::dump(str); str << " [" << timeunit() << "/" << timeprecision() << "]"; @@ -1397,7 +1478,7 @@ void AstTypeTable::dump(std::ostream& str) const { this->AstNode::dump(str); for (int i = 0; i < static_cast(AstBasicDTypeKwd::_ENUM_MAX); ++i) { if (AstBasicDType* subnodep = m_basicps[i]) { - str << endl; // Newline from caller, so newline first + str << '\n'; // Newline from caller, so newline first str << "\t\t" << std::setw(8) << AstBasicDTypeKwd(i).ascii(); str << " -> "; subnodep->dump(str); @@ -1407,7 +1488,7 @@ void AstTypeTable::dump(std::ostream& str) const { const DetailedMap& mapr = m_detailedMap; for (const auto& itr : mapr) { AstBasicDType* dtypep = itr.second; - str << endl; // Newline from caller, so newline first + str << '\n'; // Newline from caller, so newline first str << "\t\tdetailed -> "; dtypep->dump(str); } @@ -1453,11 +1534,13 @@ void AstVarScope::dump(std::ostream& str) const { str << " ->UNLINKED"; } } -void AstNodeVarRef::dump(std::ostream& str) const { this->AstNodeMath::dump(str); } +void AstNodeVarRef::dump(std::ostream& str) const { + this->AstNodeMath::dump(str); + if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); + str << " " << access().arrow() << " "; +} void AstVarXRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); - if (packagep()) str << " pkg=" << nodeAddr(packagep()); - str << " " << access().arrow() << " "; str << ".=" << dotted() << " "; if (inlinedDots() != "") str << " inline.=" << inlinedDots() << " - "; if (varScopep()) { @@ -1470,8 +1553,6 @@ void AstVarXRef::dump(std::ostream& str) const { } void AstVarRef::dump(std::ostream& str) const { this->AstNodeVarRef::dump(str); - if (packagep()) str << " pkg=" << nodeAddr(packagep()); - str << " " << access().arrow() << " "; if (varScopep()) { varScopep()->dump(str); } else if (varp()) { @@ -1547,7 +1628,7 @@ void AstActive::dump(std::ostream& str) const { } void AstNodeFTaskRef::dump(std::ostream& str) const { this->AstNodeStmt::dump(str); - if (packagep()) { str << " pkg=" << nodeAddr(packagep()); } + if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep()); str << " -> "; if (dotted() != "") { str << ".=" << dotted() << " "; } if (taskp()) { diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h index 94cbc43e2..909b741fa 100644 --- a/src/V3AstNodes.h +++ b/src/V3AstNodes.h @@ -36,7 +36,7 @@ Ast##name* clonep() const { return static_cast(AstNode::clonep()); } #define ASTNODE_NODE_FUNCS(name) \ - virtual ~Ast##name() override {} \ + virtual ~Ast##name() override = default; \ ASTNODE_NODE_FUNCS_NO_DTOR(name) //###################################################################### @@ -48,7 +48,7 @@ //=== Ast* : Specific types // Netlist interconnect -class AstConst : public AstNodeMath { +class AstConst final : public AstNodeMath { // A constant private: V3Number m_num; // Constant value @@ -140,17 +140,18 @@ public: , m_num(V3Number::String(), this, num) { dtypeSetString(); } - class LogicFalse {}; - AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, dtype should be a logic of size 1 + class BitFalse {}; + AstConst(FileLine* fl, BitFalse) // Shorthand const 0, dtype should be a logic of size 1 : ASTGEN_SUPER(fl) , m_num(this, 1, 0) { - dtypeSetLogicBool(); + dtypeSetBit(); } - class LogicTrue {}; - AstConst(FileLine* fl, LogicTrue) // Shorthand const 1, dtype should be a logic of size 1 + // Shorthand const 1 (or with argument 0/1), dtype should be a logic of size 1 + class BitTrue {}; + AstConst(FileLine* fl, BitTrue, bool on = true) : ASTGEN_SUPER(fl) - , m_num(this, 1, 1) { - dtypeSetLogicBool(); + , m_num(this, 1, on) { + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Const) virtual string name() const override { return num().ascii(); } // * = Value @@ -175,7 +176,7 @@ public: static AstConst* parseParamLiteral(FileLine* fl, const string& literal); }; -class AstRange : public AstNodeRange { +class AstRange final : public AstNodeRange { // Range specification, for use under variables and cells private: bool m_littleEndian : 1; // Bit vector is little endian @@ -234,7 +235,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstBracketRange : public AstNodeRange { +class AstBracketRange final : public AstNodeRange { // Parser only concept "[lhsp]", a AstUnknownRange, QueueRange or Range, // unknown until lhsp type is determined public: @@ -253,7 +254,7 @@ public: AstNode* elementsp() const { return op1p(); } }; -class AstUnsizedRange : public AstNodeRange { +class AstUnsizedRange final : public AstNodeRange { // Unsized range specification, for open arrays public: explicit AstUnsizedRange(FileLine* fl) @@ -265,7 +266,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstGatePin : public AstNodeMath { +class AstGatePin final : public AstNodeMath { // Possibly expand a gate primitive input pin value to match the range of the gate primitive public: AstGatePin(FileLine* fl, AstNode* lhsp, AstRange* rangep) @@ -284,7 +285,7 @@ public: //###################################################################### // Classes -class AstClassPackage : public AstNodeModule { +class AstClassPackage final : public AstNodeModule { // The static information portion of a class (treated similarly to a package) AstClass* m_classp = nullptr; // Class package this is under (weak pointer, hard link is other way) @@ -298,12 +299,12 @@ public: void classp(AstClass* classp) { m_classp = classp; } }; -class AstClass : public AstNodeModule { +class AstClass final : public AstNodeModule { // TYPES typedef std::map MemberNameMap; // MEMBERS MemberNameMap m_members; // Members or method children - AstClassPackage* m_packagep = nullptr; // Class package this is under + AstClassPackage* m_classOrPackagep = nullptr; // Class package this is under bool m_virtual = false; // Virtual class bool m_extended = false; // Is extension or extended by other classes void insertCache(AstNode* nodep); @@ -318,12 +319,12 @@ public: virtual void dump(std::ostream& str) const override; virtual const char* broken() const override { BROKEN_BASE_RTN(AstNodeModule::broken()); - BROKEN_RTN(m_packagep && !m_packagep->brokeExists()); + BROKEN_RTN(m_classOrPackagep && !m_classOrPackagep->brokeExists()); return nullptr; } // op1/op2/op3 in AstNodeModule - AstClassPackage* packagep() const { return m_packagep; } - void packagep(AstClassPackage* classpackagep) { m_packagep = classpackagep; } + AstClassPackage* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstClassPackage* classpackagep) { m_classOrPackagep = classpackagep; } AstNode* membersp() const { return stmtsp(); } // op2 = List of statements void addMembersp(AstNode* nodep) { insertCache(nodep); @@ -341,9 +342,12 @@ public: void isExtended(bool flag) { m_extended = flag; } bool isVirtual() const { return m_virtual; } void isVirtual(bool flag) { m_virtual = flag; } + // Return true if this class is an extension of base class (SLOW) + // Accepts nullptrs + static bool isClassExtendedFrom(const AstClass* refClassp, const AstClass* baseClassp); }; -class AstClassExtends : public AstNode { +class AstClassExtends final : public AstNode { // Children: List of AstParseRef for packages/classes // during early parse, then moves to dtype public: @@ -364,7 +368,7 @@ public: //###################################################################### //==== Data Types -class AstParamTypeDType : public AstNodeDType { +class AstParamTypeDType final : public AstNodeDType { // Parents: MODULE // A parameter type statement; much like a var or typedef private: @@ -395,7 +399,8 @@ public: virtual AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); } virtual bool similarDType(AstNodeDType* samep) const override { const AstParamTypeDType* sp = static_cast(samep); - return (sp && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp())); + return type() == samep->type() && sp + && this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp()); } virtual int widthAlignBytes() const override { return dtypep()->widthAlignBytes(); } virtual int widthTotalBytes() const override { return dtypep()->widthTotalBytes(); } @@ -409,7 +414,7 @@ public: bool isGParam() const { return (varType() == AstVarType::GPARAM); } }; -class AstTypedef : public AstNode { +class AstTypedef final : public AstNode { private: string m_name; bool m_attrPublic; @@ -444,7 +449,7 @@ public: virtual string tag() const override { return m_tag; } }; -class AstTypedefFwd : public AstNode { +class AstTypedefFwd final : public AstNode { // Forward declaration of a type; stripped after netlist parsing is complete private: string m_name; @@ -459,7 +464,7 @@ public: virtual bool maybePointedTo() const override { return true; } }; -class AstDefImplicitDType : public AstNodeDType { +class AstDefImplicitDType final : public AstNodeDType { // For parsing enum/struct/unions that are declared with a variable rather than typedef // This allows "var enum {...} a,b" to share the enum definition for both variables // After link, these become typedefs @@ -509,7 +514,7 @@ public: virtual void name(const string& flag) override { m_name = flag; } }; -class AstAssocArrayDType : public AstNodeDType { +class AstAssocArrayDType final : public AstNodeDType { // Associative array data type, ie "[some_dtype]" // Children: DTYPE (moved to refDTypep() in V3Width) // Children: DTYPE (the key, which remains here as a pointer) @@ -545,8 +550,8 @@ public: } virtual bool similarDType(AstNodeDType* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; @@ -580,7 +585,7 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstBracketArrayDType : public AstNodeDType { +class AstBracketArrayDType final : public AstNodeDType { // Associative/Queue/Normal array data type, ie "[dtype_or_expr]" // only for early parsing then becomes another data type // Children: DTYPE (moved to refDTypep() in V3Width) @@ -610,7 +615,7 @@ public: virtual int widthTotalBytes() const override { V3ERROR_NA_RETURN(0); } }; -class AstDynArrayDType : public AstNodeDType { +class AstDynArrayDType final : public AstNodeDType { // Dynamic array data type, ie "[]" // Children: DTYPE (moved to refDTypep() in V3Width) private: @@ -643,8 +648,8 @@ public: } virtual bool similarDType(AstNodeDType* samep) const override { const AstAssocArrayDType* asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual string prettyDTypeName() const override; virtual void dumpSmall(std::ostream& str) const override; @@ -669,7 +674,7 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstPackArrayDType : public AstNodeArrayDType { +class AstPackArrayDType final : public AstNodeArrayDType { // Packed array data type, ie "some_dtype [2:0] var_name" // Children: DTYPE (moved to refDTypep() in V3Width) // Children: RANGE (array bounds) @@ -695,7 +700,7 @@ public: virtual string prettyDTypeName() const override; }; -class AstUnpackArrayDType : public AstNodeArrayDType { +class AstUnpackArrayDType final : public AstNodeArrayDType { // Array data type, ie "some_dtype var_name [2:0]" // Children: DTYPE (moved to refDTypep() in V3Width) // Children: RANGE (array bounds) @@ -721,9 +726,11 @@ public: } ASTNODE_NODE_FUNCS(UnpackArrayDType) virtual string prettyDTypeName() const override; + // Outer dimension comes first. The first element is this node. + std::vector unpackDimensions(); }; -class AstUnsizedArrayDType : public AstNodeDType { +class AstUnsizedArrayDType final : public AstNodeDType { // Unsized/open-range Array data type, ie "some_dtype var_name []" // Children: DTYPE (moved to refDTypep() in V3Width) private: @@ -751,8 +758,8 @@ public: } virtual bool similarDType(AstNodeDType* samep) const override { const AstNodeArrayDType* asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } @@ -775,7 +782,7 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstBasicDType : public AstNodeDType { +class AstBasicDType final : public AstNodeDType { // Builtin atomic/vectored data type // Children: RANGE (converted to constant in V3Width) private: @@ -932,7 +939,7 @@ public: } }; -class AstConstDType : public AstNodeDType { +class AstConstDType final : public AstNodeDType { // const data type, ie "const some_dtype var_name [2:0]" // ConstDType are removed in V3LinkLValue and become AstVar::isConst. // When more generic types are supported AstConstDType will be propagated further. @@ -984,16 +991,18 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstClassRefDType : public AstNodeDType { +class AstClassRefDType final : public AstNodeDType { // Reference to a class + // Children: PINs (for parameter settings) private: AstClass* m_classp; // data type pointed to, BELOW the AstTypedef - AstNodeModule* m_packagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: - AstClassRefDType(FileLine* fl, AstClass* classp) + AstClassRefDType(FileLine* fl, AstClass* classp, AstNode* paramsp) : ASTGEN_SUPER(fl) , m_classp{classp} { dtypep(this); + addNOp4p(paramsp); } ASTNODE_NODE_FUNCS(ClassRefDType) // METHODS @@ -1006,13 +1015,13 @@ public: } virtual bool same(const AstNode* samep) const override { const AstClassRefDType* asamep = static_cast(samep); - return (m_classp == asamep->m_classp && m_packagep == asamep->m_packagep); + return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep); } virtual bool similarDType(AstNodeDType* samep) const override { - return this == samep || same(samep); + return this == samep || (type() == samep->type() && same(samep)); } virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_classp), V3Hash(m_packagep)); + return V3Hash(V3Hash(m_classp), V3Hash(m_classOrPackagep)); } virtual void dump(std::ostream& str = std::cout) const override; virtual void dumpSmall(std::ostream& str) const override; @@ -1026,13 +1035,14 @@ public: virtual AstNodeDType* virtRefDTypep() const override { return nullptr; } virtual void virtRefDTypep(AstNodeDType* nodep) override {} virtual AstNodeDType* subDTypep() const override { return nullptr; } - AstNodeModule* packagep() const { return m_packagep; } - void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } AstClass* classp() const { return m_classp; } void classp(AstClass* nodep) { m_classp = nodep; } + AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; -class AstIfaceRefDType : public AstNodeDType { +class AstIfaceRefDType final : public AstNodeDType { // Reference to an interface, either for a port, or inside parent cell private: FileLine* m_modportFileline; // Where modport token was @@ -1087,7 +1097,7 @@ public: bool isModport() { return !m_modportName.empty(); } }; -class AstQueueDType : public AstNodeDType { +class AstQueueDType final : public AstNodeDType { // Queue array data type, ie "[ $ ]" // Children: DTYPE (moved to refDTypep() in V3Width) private: @@ -1122,8 +1132,8 @@ public: } virtual bool similarDType(AstNodeDType* samep) const override { const AstQueueDType* asamep = static_cast(samep); - if (!asamep->subDTypep()) return false; - return (subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp())); + return type() == samep->type() && asamep->subDTypep() + && subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp()); } virtual void dumpSmall(std::ostream& str) const override; virtual V3Hash sameHash() const override { return V3Hash(m_refDTypep); } @@ -1157,7 +1167,7 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstRefDType : public AstNodeDType { +class AstRefDType final : public AstNodeDType { private: // Pre-Width must reference the Typeref, not what it points to, as some child // types like AstBracketArrayType will disappear and can't lose the handle @@ -1165,7 +1175,7 @@ private: // Post-width typedefs are removed and point to type directly AstNodeDType* m_refDTypep = nullptr; // data type pointed to, BELOW the AstTypedef string m_name; // Name of an AstTypedef - AstNodeModule* m_packagep = nullptr; // Package hierarchy + AstNodeModule* m_classOrPackagep = nullptr; // Package hierarchy public: AstRefDType(FileLine* fl, const string& name) : ASTGEN_SUPER(fl) @@ -1195,13 +1205,13 @@ public: virtual bool same(const AstNode* samep) const override { const AstRefDType* asamep = static_cast(samep); return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep - && m_name == asamep->m_name && m_packagep == asamep->m_packagep); + && m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep); } virtual bool similarDType(AstNodeDType* samep) const override { return skipRefp()->similarDType(samep->skipRefp()); } virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(m_typedefp), V3Hash(m_packagep)); + return V3Hash(V3Hash(m_typedefp), V3Hash(m_classOrPackagep)); } virtual void dump(std::ostream& str = std::cout) const override; virtual string name() const override { return m_name; } @@ -1251,14 +1261,14 @@ public: void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; } virtual AstNodeDType* virtRefDTypep() const override { return refDTypep(); } virtual void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); } - AstNodeModule* packagep() const { return m_packagep; } - void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } AstNode* typeofp() const { return op2p(); } - AstNode* classOrPackagep() const { return op3p(); } + AstNode* classOrPackageOpp() const { return op3p(); } AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; -class AstStructDType : public AstNodeUOrStructDType { +class AstStructDType final : public AstNodeUOrStructDType { public: // VSigning below is mispurposed to indicate if packed or not AstStructDType(FileLine* fl, VSigning numericUnpack) @@ -1267,7 +1277,7 @@ public: virtual string verilogKwd() const override { return "struct"; } }; -class AstUnionDType : public AstNodeUOrStructDType { +class AstUnionDType final : public AstNodeUOrStructDType { public: // UNSUP: bool isTagged; // VSigning below is mispurposed to indicate if packed or not @@ -1277,7 +1287,7 @@ public: virtual string verilogKwd() const override { return "union"; } }; -class AstMemberDType : public AstNodeDType { +class AstMemberDType final : public AstNodeDType { // A member of a struct/union // PARENT: AstNodeUOrStructDType private: @@ -1340,7 +1350,7 @@ public: void lsb(int lsb) { m_lsb = lsb; } }; -class AstVoidDType : public AstNodeDType { +class AstVoidDType final : public AstNodeDType { // For e.g. a function returning void public: explicit AstVoidDType(FileLine* fl) @@ -1367,7 +1377,7 @@ public: virtual V3Hash sameHash() const override { return V3Hash(); } }; -class AstEnumItem : public AstNode { +class AstEnumItem final : public AstNode { private: string m_name; @@ -1390,15 +1400,15 @@ public: void valuep(AstNode* nodep) { addOp2p(nodep); } }; -class AstEnumItemRef : public AstNodeMath { +class AstEnumItemRef final : public AstNodeMath { private: AstEnumItem* m_itemp; // [AfterLink] Pointer to item - AstNodeModule* m_packagep; // Package hierarchy + AstNodeModule* m_classOrPackagep; // Package hierarchy public: - AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* packagep) + AstEnumItemRef(FileLine* fl, AstEnumItem* itemp, AstNodeModule* classOrPackagep) : ASTGEN_SUPER(fl) , m_itemp{itemp} - , m_packagep{packagep} { + , m_classOrPackagep{classOrPackagep} { dtypeFrom(m_itemp); } ASTNODE_NODE_FUNCS(EnumItemRef) @@ -1420,11 +1430,11 @@ public: virtual string emitVerilog() override { V3ERROR_NA_RETURN(""); } virtual string emitC() override { V3ERROR_NA_RETURN(""); } virtual bool cleanOut() const override { return true; } - AstNodeModule* packagep() const { return m_packagep; } - void packagep(AstNodeModule* nodep) { m_packagep = nodep; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } + void classOrPackagep(AstNodeModule* nodep) { m_classOrPackagep = nodep; } }; -class AstEnumDType : public AstNodeDType { +class AstEnumDType final : public AstNodeDType { // Parents: TYPEDEF/MODULE // Children: ENUMVALUEs private: @@ -1483,7 +1493,7 @@ public: virtual int widthTotalBytes() const override { return subDTypep()->widthTotalBytes(); } }; -class AstParseTypeDType : public AstNodeDType { +class AstParseTypeDType final : public AstNodeDType { // Parents: VAR // During parsing, this indicates the type of a parameter is a "parameter type" // e.g. the data type is a container of any data type @@ -1506,7 +1516,7 @@ public: //###################################################################### -class AstArraySel : public AstNodeSel { +class AstArraySel final : public AstNodeSel { // Parents: math|stmt // Children: varref|arraysel, math private: @@ -1552,7 +1562,7 @@ public: baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences? }; -class AstAssocSel : public AstNodeSel { +class AstAssocSel final : public AstNodeSel { // Parents: math|stmt // Children: varref|arraysel, math private: @@ -1591,7 +1601,7 @@ public: virtual int instrCount() const override { return widthInstrs(); } }; -class AstWordSel : public AstNodeSel { +class AstWordSel final : public AstNodeSel { // Select a single word from a multi-word wide value public: AstWordSel(FileLine* fl, AstNode* fromp, AstNode* bitp) @@ -1618,7 +1628,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstSelLoopVars : public AstNode { +class AstSelLoopVars final : public AstNode { // Parser only concept "[id, id, id]" for a foreach statement // Unlike normal selects elements is a list public: @@ -1635,7 +1645,7 @@ public: AstNode* elementsp() const { return op2p(); } }; -class AstSelExtract : public AstNodePreSel { +class AstSelExtract final : public AstNodePreSel { // Range extraction, gets replaced with AstSel public: AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp) @@ -1645,7 +1655,7 @@ public: AstNode* lsbp() const { return thsp(); } }; -class AstSelBit : public AstNodePreSel { +class AstSelBit final : public AstNodePreSel { // Single bit range extraction, perhaps with non-constant selection or array selection // Gets replaced during link with AstArraySel or AstSel public: @@ -1658,7 +1668,7 @@ public: AstNode* bitp() const { return rhsp(); } }; -class AstSelPlus : public AstNodePreSel { +class AstSelPlus final : public AstNodePreSel { // +: range extraction, perhaps with non-constant selection // Gets replaced during link with AstSel public: @@ -1669,7 +1679,7 @@ public: AstNode* widthp() const { return thsp(); } }; -class AstSelMinus : public AstNodePreSel { +class AstSelMinus final : public AstNodePreSel { // -: range extraction, perhaps with non-constant selection // Gets replaced during link with AstSel public: @@ -1680,7 +1690,7 @@ public: AstNode* widthp() const { return thsp(); } }; -class AstSel : public AstNodeTriop { +class AstSel final : public AstNodeTriop { // Multiple bit range extraction // Parents: math|stmt // Children: varref|arraysel, math, constant math @@ -1740,7 +1750,7 @@ public: void declElWidth(int flag) { m_declElWidth = flag; } }; -class AstSliceSel : public AstNodeTriop { +class AstSliceSel final : public AstNodeTriop { // Multiple array element extraction // Parents: math|stmt // Children: varref|arraysel, math, constant math @@ -1778,7 +1788,7 @@ public: void declRange(const VNumRange& flag) { m_declRange = flag; } }; -class AstMethodCall : public AstNodeFTaskRef { +class AstMethodCall final : public AstNodeFTaskRef { // A reference to a member task (or function) // PARENTS: stmt/math // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. @@ -1812,7 +1822,7 @@ public: void fromp(AstNode* nodep) { setOp2p(nodep); } }; -class AstCMethodHard : public AstNodeStmt { +class AstCMethodHard final : public AstNodeStmt { // A reference to a "C" hardcoded member task (or function) // PARENTS: stmt/math // Not all calls are statments vs math. AstNodeStmt needs isStatement() to deal. @@ -1857,7 +1867,7 @@ public: void addPinsp(AstNode* nodep) { addOp2p(nodep); } }; -class AstVar : public AstNode { +class AstVar final : public AstNode { // A variable (in/out/wire/reg/param) inside a module private: string m_name; // Name of variable @@ -1895,6 +1905,8 @@ private: bool m_isPullup : 1; // Tri1 bool m_isIfaceParent : 1; // dtype is reference to interface present in this module bool m_isDpiOpenArray : 1; // DPI import open array + bool m_isHideLocal : 1; // Verilog local + bool m_isHideProtected : 1; // Verilog protected bool m_noReset : 1; // Do not do automated reset/randomization bool m_noSubst : 1; // Do not substitute out references bool m_overridenParam : 1; // Overridden parameter by #(...) or defparam @@ -1932,6 +1944,8 @@ private: m_isPullup = false; m_isIfaceParent = false; m_isDpiOpenArray = false; + m_isHideLocal = false; + m_isHideProtected = false; m_noReset = false; m_noSubst = false; m_overridenParam = false; @@ -2026,6 +2040,7 @@ public: // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc. string cPubArgType(bool named, bool forReturn) const; string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument + string dpiTmpVarType(const string& varName) const; // Return Verilator internal type for argument: CData, SData, IData, WData string vlArgType(bool named, bool forReturn, bool forFunc, const string& namespc = "") const; string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc @@ -2080,6 +2095,10 @@ public: void funcReturn(bool flag) { m_funcReturn = flag; } void isDpiOpenArray(bool flag) { m_isDpiOpenArray = flag; } bool isDpiOpenArray() const { return m_isDpiOpenArray; } + bool isHideLocal() const { return m_isHideLocal; } + void isHideLocal(bool flag) { m_isHideLocal = flag; } + bool isHideProtected() const { return m_isHideProtected; } + void isHideProtected(bool flag) { m_isHideProtected = flag; } void noReset(bool flag) { m_noReset = flag; } bool noReset() const { return m_noReset; } void noSubst(bool flag) { m_noSubst = flag; } @@ -2190,7 +2209,7 @@ public: string mtasksString() const; }; -class AstDefParam : public AstNode { +class AstDefParam final : public AstNode { // A defparam assignment // Parents: MODULE // Children: math @@ -2212,7 +2231,7 @@ public: string path() const { return m_path; } }; -class AstImplicit : public AstNode { +class AstImplicit final : public AstNode { // Create implicit wires and do nothing else, for gates that are ignored // Parents: MODULE public: @@ -2224,7 +2243,7 @@ public: AstNode* exprsp() const { return op1p(); } // op1 = Assign from }; -class AstScope : public AstNode { +class AstScope final : public AstNode { // A particular usage of a cell // Parents: MODULE // Children: NODEBLOCK @@ -2263,7 +2282,7 @@ public: bool isTop() const { return aboveScopep() == nullptr; } // At top of hierarchy }; -class AstTopScope : public AstNode { +class AstTopScope final : public AstNode { // In the top level netlist, a complete scope tree // There may be two of these, when we support "rare" and "usual" splitting // Parents: topMODULE @@ -2279,7 +2298,7 @@ public: AstScope* scopep() const { return VN_CAST(op2p(), Scope); } // op1 = AstVarScope's }; -class AstVarScope : public AstNode { +class AstVarScope final : public AstNode { // A particular scoped usage of a variable // That is, as a module is used under multiple cells, we get a different // varscope for each var in the module @@ -2327,7 +2346,7 @@ public: void trace(bool flag) { m_trace = flag; } }; -class AstVarRef : public AstNodeVarRef { +class AstVarRef final : public AstNodeVarRef { // A reference to a variable (lvalue or rvalue) public: AstVarRef(FileLine* fl, const string& name, const VAccess& access) @@ -2344,7 +2363,7 @@ public: ASTNODE_NODE_FUNCS(VarRef) virtual void dump(std::ostream& str) const override; virtual V3Hash sameHash() const override { - return V3Hash(V3Hash(varp()->name()), V3Hash(hiername())); + return V3Hash(V3Hash(varp()->name()), V3Hash(hiernameToProt())); } virtual bool same(const AstNode* samep) const override { return same(static_cast(samep)); @@ -2353,16 +2372,18 @@ public: if (varScopep()) { return (varScopep() == samep->varScopep() && access() == samep->access()); } else { - return (hiername() == samep->hiername() && varp()->name() == samep->varp()->name() - && access() == samep->access()); + return (hiernameToProt() == samep->hiernameToProt() + && hiernameToUnprot() == samep->hiernameToUnprot() + && varp()->name() == samep->varp()->name() && access() == samep->access()); } } inline bool sameNoLvalue(AstVarRef* samep) const { if (varScopep()) { return (varScopep() == samep->varScopep()); } else { - return (hiername() == samep->hiername() - && (hiername() != "" || samep->hiername() != "") + return (hiernameToProt() == samep->hiernameToProt() + && hiernameToUnprot() == samep->hiernameToUnprot() + && (!hiernameToProt().empty() || !samep->hiernameToProt().empty()) && varp()->name() == samep->varp()->name()); } } @@ -2374,7 +2395,7 @@ public: virtual bool cleanOut() const override { return true; } }; -class AstVarXRef : public AstNodeVarRef { +class AstVarXRef final : public AstNodeVarRef { // A VarRef to something in another module before AstScope. // Includes pin on a cell, as part of a ASSIGN statement to connect I/Os until AstScope private: @@ -2403,12 +2424,13 @@ public: virtual V3Hash sameHash() const override { return V3Hash(V3Hash(varp()), V3Hash(dotted())); } virtual bool same(const AstNode* samep) const override { const AstVarXRef* asamep = static_cast(samep); - return (hiername() == asamep->hiername() && varp() == asamep->varp() + return (hiernameToProt() == asamep->hiernameToProt() + && hiernameToUnprot() == asamep->hiernameToUnprot() && varp() == asamep->varp() && name() == asamep->name() && dotted() == asamep->dotted()); } }; -class AstPin : public AstNode { +class AstPin final : public AstNode { // A pin on a cell private: int m_pinNum; // Pin number @@ -2462,7 +2484,7 @@ public: void svImplicit(bool flag) { m_svImplicit = flag; } }; -class AstArg : public AstNode { +class AstArg final : public AstNode { // An argument to a function/task private: string m_name; // Pin name, or "" for number based interconnect @@ -2482,7 +2504,7 @@ public: bool emptyConnectNoNext() const { return !exprp() && name() == "" && !nextp(); } }; -class AstModule : public AstNodeModule { +class AstModule final : public AstNodeModule { // A module declaration private: bool m_isProgram; // Module represents a program @@ -2494,7 +2516,7 @@ public: virtual string verilogKwd() const override { return m_isProgram ? "program" : "module"; } }; -class AstNotFoundModule : public AstNodeModule { +class AstNotFoundModule final : public AstNodeModule { // A missing module declaration public: AstNotFoundModule(FileLine* fl, const string& name) @@ -2503,7 +2525,7 @@ public: virtual string verilogKwd() const override { return "/*not-found-*/ module"; } }; -class AstPackage : public AstNodeModule { +class AstPackage final : public AstNodeModule { // A package declaration public: AstPackage(FileLine* fl, const string& name) @@ -2514,7 +2536,7 @@ public: bool isDollarUnit() const { return name() == dollarUnitName(); } }; -class AstPrimitive : public AstNodeModule { +class AstPrimitive final : public AstNodeModule { // A primitive declaration public: AstPrimitive(FileLine* fl, const string& name) @@ -2523,7 +2545,7 @@ public: virtual string verilogKwd() const override { return "primitive"; } }; -class AstPackageExportStarStar : public AstNode { +class AstPackageExportStarStar final : public AstNode { // A package export *::* declaration public: // cppcheck-suppress noExplicitConstructor @@ -2532,7 +2554,7 @@ public: ASTNODE_NODE_FUNCS(PackageExportStarStar) }; -class AstPackageExport : public AstNode { +class AstPackageExport final : public AstNode { private: // A package export declaration string m_name; @@ -2556,7 +2578,7 @@ public: void packagep(AstPackage* nodep) { m_packagep = nodep; } }; -class AstPackageImport : public AstNode { +class AstPackageImport final : public AstNode { private: // A package import declaration string m_name; @@ -2580,7 +2602,7 @@ public: void packagep(AstPackage* nodep) { m_packagep = nodep; } }; -class AstIface : public AstNodeModule { +class AstIface final : public AstNodeModule { // A module declaration public: AstIface(FileLine* fl, const string& name) @@ -2588,7 +2610,7 @@ public: ASTNODE_NODE_FUNCS(Iface) }; -class AstMemberSel : public AstNodeMath { +class AstMemberSel final : public AstNodeMath { // Parents: math|stmt // Children: varref|arraysel, math private: @@ -2634,7 +2656,7 @@ public: void varp(AstVar* nodep) { m_varp = nodep; } }; -class AstModportFTaskRef : public AstNode { +class AstModportFTaskRef final : public AstNode { // An import/export referenced under a modport // The storage for the function itself is inside the // interface/instantiator, thus this is a reference @@ -2664,7 +2686,7 @@ public: void ftaskp(AstNodeFTask* ftaskp) { m_ftaskp = ftaskp; } }; -class AstModportVarRef : public AstNode { +class AstModportVarRef final : public AstNode { // A input/output/etc variable referenced under a modport // The storage for the variable itself is inside the interface, thus this is a reference // PARENT: AstModport @@ -2693,7 +2715,7 @@ public: void varp(AstVar* varp) { m_varp = varp; } }; -class AstModport : public AstNode { +class AstModport final : public AstNode { // A modport in an interface private: string m_name; // Name of the modport @@ -2709,7 +2731,7 @@ public: AstNode* varsp() const { return op1p(); } // op1 = List of Vars }; -class AstIntfRef : public AstNode { +class AstIntfRef final : public AstNode { // An interface reference private: string m_name; // Name of the reference @@ -2721,7 +2743,7 @@ public: ASTNODE_NODE_FUNCS(IntfRef) }; -class AstCell : public AstNode { +class AstCell final : public AstNode { // A instantiation cell or interface call (don't know which until link) private: FileLine* m_modNameFileline; // Where module the cell instances token was @@ -2783,7 +2805,7 @@ public: bool recursive() const { return m_recursive; } }; -class AstCellInline : public AstNode { +class AstCellInline final : public AstNode { // A instantiation cell that was removed by inlining // For communication between V3Inline and V3LinkDot, // except for VPI runs where it exists until the end. @@ -2817,7 +2839,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstCellRef : public AstNode { +class AstCellRef final : public AstNode { // As-of-yet unlinkable reference into a cell private: string m_name; // Cell name @@ -2835,7 +2857,7 @@ public: AstNode* exprp() const { return op2p(); } // op2 = Expression }; -class AstCellArrayRef : public AstNode { +class AstCellArrayRef final : public AstNode { // As-of-yet unlinkable reference into an array of cells private: string m_name; // Array name @@ -2851,7 +2873,7 @@ public: AstNode* selp() const { return op1p(); } // op1 = Select expression }; -class AstUnlinkedRef : public AstNode { +class AstUnlinkedRef final : public AstNode { // As-of-yet unlinkable Ref private: string m_name; // Var name @@ -2869,7 +2891,7 @@ public: AstNode* cellrefp() const { return op2p(); } // op2 = CellArrayRef or CellRef }; -class AstBind : public AstNode { +class AstBind final : public AstNode { // Parents: MODULE // Children: CELL private: @@ -2888,7 +2910,7 @@ public: AstNode* cellsp() const { return op1p(); } // op1 = cells }; -class AstPort : public AstNode { +class AstPort final : public AstNode { // A port (in/out/inout) on a module private: int m_pinNum; // Pin number @@ -2906,7 +2928,7 @@ public: //###################################################################### -class AstParseRef : public AstNode { +class AstParseRef final : public AstNode { // A reference to a variable, function or task // We don't know which at parse time due to bison constraints // The link stages will replace this with AstVarRef, or AstTaskRef, etc. @@ -2942,7 +2964,7 @@ public: void ftaskrefp(AstNodeFTaskRef* nodep) { setNOp2p(nodep); } // op2 = Function/task reference }; -class AstClassOrPackageRef : public AstNode { +class AstClassOrPackageRef final : public AstNode { private: string m_name; AstNode* m_classOrPackagep; // Package hierarchy @@ -2978,7 +3000,7 @@ public: AstPin* paramsp() const { return VN_CAST(op4p(), Pin); } }; -class AstDot : public AstNode { +class AstDot final : public AstNode { // A dot separating paths in an AstVarXRef, AstFuncRef or AstTaskRef // These are eliminated in the link stage bool m_colon; // Is a "::" instead of a "." (lhs must be package/class) @@ -3001,7 +3023,7 @@ public: bool colon() const { return m_colon; } }; -class AstUnbounded : public AstNodeMath { +class AstUnbounded final : public AstNodeMath { // A $ in the parser, used for unbounded and queues // Due to where is used, treated as Signed32 public: @@ -3017,7 +3039,7 @@ public: //###################################################################### -class AstTask : public AstNodeFTask { +class AstTask final : public AstNodeFTask { // A task inside a module public: AstTask(FileLine* fl, const string& name, AstNode* stmtp) @@ -3025,7 +3047,7 @@ public: ASTNODE_NODE_FUNCS(Task) }; -class AstFunc : public AstNodeFTask { +class AstFunc final : public AstNodeFTask { // A function inside a module public: AstFunc(FileLine* fl, const string& name, AstNode* stmtp, AstNode* fvarsp) @@ -3036,7 +3058,7 @@ public: virtual bool hasDType() const override { return true; } }; -class AstTaskRef : public AstNodeFTaskRef { +class AstTaskRef final : public AstNodeFTaskRef { // A reference to a task public: AstTaskRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) @@ -3048,7 +3070,7 @@ public: ASTNODE_NODE_FUNCS(TaskRef) }; -class AstFuncRef : public AstNodeFTaskRef { +class AstFuncRef final : public AstNodeFTaskRef { // A reference to a function public: AstFuncRef(FileLine* fl, AstParseRef* namep, AstNode* pinsp) @@ -3059,7 +3081,7 @@ public: virtual bool hasDType() const override { return true; } }; -class AstDpiExport : public AstNode { +class AstDpiExport final : public AstNode { // We could put an AstNodeFTaskRef instead of the verilog function name, // however we're not *calling* it, so that seems somehow wrong. // (Probably AstNodeFTaskRef should be renamed AstNodeFTaskCall and have-a AstNodeFTaskRef) @@ -3078,7 +3100,7 @@ public: void cname(const string& cname) { m_cname = cname; } }; -class AstWithParse : public AstNodeStmt { +class AstWithParse final : public AstNodeStmt { // In early parse, FUNC(index) WITH equation-using-index // Replaced with AstWith // Parents: math|stmt @@ -3098,17 +3120,19 @@ public: AstNode* exprp() const { return op2p(); } }; -class AstLambdaArgRef : public AstNodeMath { +class AstLambdaArgRef final : public AstNodeMath { // Lambda argument usage // These are not AstVarRefs because we need to be able to delete/clone lambdas during // optimizations and AstVar's are painful to remove. private: string m_name; // Name of variable + bool m_index; // Index, not value public: - AstLambdaArgRef(FileLine* fl, const string& name) + AstLambdaArgRef(FileLine* fl, const string& name, bool index) : ASTGEN_SUPER(fl) - , m_name{name} {} + , m_name{name} + , m_index(index) {} ASTNODE_NODE_FUNCS(LambdaArgRef) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } @@ -3119,36 +3143,42 @@ public: virtual int instrCount() const override { return widthInstrs(); } virtual string name() const override { return m_name; } // * = Var name virtual void name(const string& name) override { m_name = name; } + bool index() const { return m_index; } }; -class AstWith : public AstNodeStmt { +class AstWith final : public AstNodeStmt { // Used as argument to method, then to AstCMethodHard // dtypep() contains the with lambda's return dtype // Parents: funcref (similar to AstArg) - // Children: VAR that declares the index variable + // Children: LambdaArgRef that declares the item variable + // Children: LambdaArgRef that declares the item.index variable // Children: math (equation establishing the with) public: - AstWith(FileLine* fl, AstLambdaArgRef* argrefp, AstNode* exprp) + AstWith(FileLine* fl, AstLambdaArgRef* indexArgRefp, AstLambdaArgRef* valueArgRefp, + AstNode* exprp) : ASTGEN_SUPER(fl) { - addOp1p(argrefp); - addNOp2p(exprp); + addOp1p(indexArgRefp); + addOp2p(valueArgRefp); + addNOp3p(exprp); } ASTNODE_NODE_FUNCS(With) virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } virtual bool hasDType() const override { return true; } virtual const char* broken() const override { - BROKEN_RTN(!argrefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!indexArgRefp()); // varp needed to know lambda's arg dtype + BROKEN_RTN(!valueArgRefp()); // varp needed to know lambda's arg dtype return nullptr; } // - AstLambdaArgRef* argrefp() const { return VN_CAST(op1p(), LambdaArgRef); } - AstNode* exprp() const { return op2p(); } + AstLambdaArgRef* indexArgRefp() const { return VN_CAST(op1p(), LambdaArgRef); } + AstLambdaArgRef* valueArgRefp() const { return VN_CAST(op2p(), LambdaArgRef); } + AstNode* exprp() const { return op3p(); } }; //###################################################################### -class AstSenItem : public AstNode { +class AstSenItem final : public AstNode { // Parents: SENTREE // Children: (optional) VARREF private: @@ -3204,7 +3234,7 @@ public: bool hasVar() const { return !(isCombo() || isInitial() || isSettle() || isNever()); } }; -class AstSenTree : public AstNode { +class AstSenTree final : public AstNode { // A list of senitems // Parents: MODULE | SBLOCK // Children: SENITEM list @@ -3231,21 +3261,21 @@ public: bool hasCombo() const; // Includes a COMBO SenItem }; -class AstFinal : public AstNodeProcedure { +class AstFinal final : public AstNodeProcedure { public: AstFinal(FileLine* fl, AstNode* bodysp) : ASTGEN_SUPER(fl, bodysp) {} ASTNODE_NODE_FUNCS(Final) }; -class AstInitial : public AstNodeProcedure { +class AstInitial final : public AstNodeProcedure { public: AstInitial(FileLine* fl, AstNode* bodysp) : ASTGEN_SUPER(fl, bodysp) {} ASTNODE_NODE_FUNCS(Initial) }; -class AstAlways : public AstNodeProcedure { +class AstAlways final : public AstNodeProcedure { VAlwaysKwd m_keyword; public: @@ -3261,8 +3291,16 @@ public: void sensesp(AstSenTree* nodep) { setOp1p(nodep); } VAlwaysKwd keyword() const { return m_keyword; } }; +class AstAlwaysPostponed final : public AstNodeProcedure { + // Like always but postponement scheduling region -class AstAlwaysPublic : public AstNodeStmt { +public: + AstAlwaysPostponed(FileLine* fl, AstNode* bodysp) + : ASTGEN_SUPER(fl, bodysp) {} + ASTNODE_NODE_FUNCS(AlwaysPostponed) +}; + +class AstAlwaysPublic final : public AstNodeStmt { // "Fake" sensitivity created by /*verilator public_flat_rw @(edgelist)*/ // Body statements are just AstVarRefs to the public signals public: @@ -3282,7 +3320,7 @@ public: bool isJustOneBodyStmt() const { return bodysp() && !bodysp()->nextp(); } }; -class AstAlwaysPost : public AstNode { +class AstAlwaysPost final : public AstNode { // Like always but post assignments for memory assignment IFs public: AstAlwaysPost(FileLine* fl, AstSenTree* sensesp, AstNode* bodysp) @@ -3296,7 +3334,7 @@ public: void addBodysp(AstNode* newp) { addOp2p(newp); } }; -class AstAssign : public AstNodeAssign { +class AstAssign final : public AstNodeAssign { public: AstAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -3309,7 +3347,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return true; } }; -class AstAssignAlias : public AstNodeAssign { +class AstAssignAlias final : public AstNodeAssign { // Like AstAssignW, but a true bidirect interconnection alias // If both sides are wires, there's no LHS vs RHS, public: @@ -3322,7 +3360,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return false; } }; -class AstAssignDly : public AstNodeAssign { +class AstAssignDly final : public AstNodeAssign { public: AstAssignDly(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} @@ -3335,7 +3373,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return true; } }; -class AstAssignW : public AstNodeAssign { +class AstAssignW final : public AstNodeAssign { // Like assign, but wire/assign's in verilog, the only setting of the specified variable public: AstAssignW(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -3355,7 +3393,7 @@ public: } }; -class AstAssignVarScope : public AstNodeAssign { +class AstAssignVarScope final : public AstNodeAssign { // Assign two VarScopes to each other public: AstAssignVarScope(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -3369,7 +3407,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return false; } }; -class AstPull : public AstNode { +class AstPull final : public AstNode { private: bool m_direction; @@ -3388,7 +3426,7 @@ public: uint32_t direction() const { return (uint32_t)m_direction; } }; -class AstAssignPre : public AstNodeAssign { +class AstAssignPre final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPre(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -3400,7 +3438,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return true; } }; -class AstAssignPost : public AstNodeAssign { +class AstAssignPost final : public AstNodeAssign { // Like Assign, but predelayed assignment requiring special order handling public: AstAssignPost(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -3412,7 +3450,7 @@ public: virtual bool brokeLhsMustBeLvalue() const override { return true; } }; -class AstComment : public AstNodeStmt { +class AstComment final : public AstNodeStmt { // Some comment to put into the output stream // Parents: {statement list} // Children: none @@ -3433,7 +3471,7 @@ public: virtual bool showAt() const { return m_showAt; } }; -class AstCond : public AstNodeCond { +class AstCond final : public AstNodeCond { // Conditional ?: statement // Parents: MATH // Children: MATH @@ -3446,7 +3484,7 @@ public: } }; -class AstCondBound : public AstNodeCond { +class AstCondBound final : public AstNodeCond { // Conditional ?: statement, specially made for safety checking of array bounds // Parents: MATH // Children: MATH @@ -3459,7 +3497,7 @@ public: } }; -class AstCoverDecl : public AstNodeStmt { +class AstCoverDecl final : public AstNodeStmt { // Coverage analysis point declaration // Parents: {statement list} // Children: none @@ -3520,7 +3558,7 @@ public: AstCoverDecl* dataDeclThisp() { return dataDeclNullp() ? dataDeclNullp() : this; } }; -class AstCoverInc : public AstNodeStmt { +class AstCoverInc final : public AstNodeStmt { // Coverage analysis point; increment coverage count // Parents: {statement list} // Children: none @@ -3551,7 +3589,7 @@ public: AstCoverDecl* declp() const { return m_declp; } // Where defined }; -class AstCoverToggle : public AstNodeStmt { +class AstCoverToggle final : public AstNodeStmt { // Toggle analysis of given signal // Parents: MODULE // Children: AstCoverInc, orig var, change det var @@ -3578,7 +3616,7 @@ public: AstNode* changep() const { return op3p(); } }; -class AstDelay : public AstNodeStmt { +class AstDelay final : public AstNodeStmt { // Delay statement public: AstDelay(FileLine* fl, AstNode* lhsp) @@ -3593,7 +3631,7 @@ public: void lhsp(AstNode* nodep) { setOp1p(nodep); } }; -class AstGenCase : public AstNodeCase { +class AstGenCase final : public AstNodeCase { // Generate Case statement // Parents: {statement list} // exprp Children: MATHs @@ -3604,7 +3642,7 @@ public: ASTNODE_NODE_FUNCS(GenCase) }; -class AstCase : public AstNodeCase { +class AstCase final : public AstNodeCase { // Case statement // Parents: {statement list} // exprp Children: MATHs @@ -3644,7 +3682,7 @@ public: void priorityPragma(bool flag) { m_priorityPragma = flag; } }; -class AstCaseItem : public AstNode { +class AstCaseItem final : public AstNode { // Single item of a case statement // Parents: CASE // condsp Children: MATH (Null condition used for default block) @@ -3668,7 +3706,7 @@ public: void ignoreOverlap(bool flag) { m_ignoreOverlap = flag; } }; -class AstSFormatF : public AstNode { +class AstSFormatF final : public AstNode { // Convert format to string, generally under an AstDisplay or AstSFormat // Also used as "real" function for /*verilator sformat*/ functions string m_text; @@ -3726,7 +3764,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstDisplay : public AstNodeStmt { +class AstDisplay final : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref // Children: SFORMATF to generate print string @@ -3780,7 +3818,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp3p(nodep); } }; -class AstDumpCtl : public AstNodeStmt { +class AstDumpCtl final : public AstNodeStmt { // $dumpon etc // Parents: expr // Child: expr based on type of control statement @@ -3805,7 +3843,7 @@ public: void exprp(AstNode* nodep) { setOp1p(nodep); } }; -class AstElabDisplay : public AstNode { +class AstElabDisplay final : public AstNode { // Parents: stmtlist // Children: SFORMATF to generate print string private: @@ -3843,7 +3881,7 @@ public: AstSFormatF* fmtp() const { return VN_CAST(op1p(), SFormatF); } }; -class AstSFormat : public AstNodeStmt { +class AstSFormat final : public AstNodeStmt { // Parents: statement container // Children: string to load // Children: SFORMATF to generate print string @@ -3879,7 +3917,7 @@ public: void lhsp(AstNode* nodep) { setOp3p(nodep); } }; -class AstSysFuncAsTask : public AstNodeStmt { +class AstSysFuncAsTask final : public AstNodeStmt { // Call what is normally a system function (with a return) in a non-return context // Parents: stmtlist // Children: a system function @@ -3901,7 +3939,7 @@ public: void lhsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to eval }; -class AstSysIgnore : public AstNodeStmt { +class AstSysIgnore final : public AstNodeStmt { // Parents: stmtlist // Children: varrefs or exprs public: @@ -3922,7 +3960,7 @@ public: void exprsp(AstNode* nodep) { addOp1p(nodep); } // op1 = Expressions to output }; -class AstFClose : public AstNodeStmt { +class AstFClose final : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref public: @@ -3943,7 +3981,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; -class AstFOpen : public AstNodeStmt { +class AstFOpen final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpen(FileLine* fl, AstNode* filep, AstNode* filenamep, AstNode* modep) @@ -3967,7 +4005,7 @@ public: AstNode* modep() const { return op3p(); } }; -class AstFOpenMcd : public AstNodeStmt { +class AstFOpenMcd final : public AstNodeStmt { // Although a system function in IEEE, here a statement which sets the file pointer (MCD) public: AstFOpenMcd(FileLine* fl, AstNode* filep, AstNode* filenamep) @@ -3989,7 +4027,7 @@ public: AstNode* filenamep() const { return op2p(); } }; -class AstFFlush : public AstNodeStmt { +class AstFFlush final : public AstNodeStmt { // Parents: stmtlist // Children: file which must be a varref public: @@ -4010,7 +4048,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; -class AstFRead : public AstNodeMath { +class AstFRead final : public AstNodeMath { // Parents: expr // Children: varrefs to load // Children: file which must be a varref @@ -4045,7 +4083,7 @@ public: void countp(AstNode* nodep) { setNOp4p(nodep); } }; -class AstFRewind : public AstNodeMath { +class AstFRewind final : public AstNodeMath { // Parents: stmtlist // Children: file which must be a varref public: @@ -4069,7 +4107,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; -class AstFTell : public AstNodeMath { +class AstFTell final : public AstNodeMath { // Parents: stmtlist // Children: file which must be a varref public: @@ -4093,7 +4131,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; -class AstFSeek : public AstNodeMath { +class AstFSeek final : public AstNodeMath { // Parents: expr // Children: file which must be a varref // Children: offset @@ -4124,7 +4162,7 @@ public: void operation(AstNode* nodep) { setNOp4p(nodep); } }; -class AstFScanF : public AstNodeMath { +class AstFScanF final : public AstNodeMath { // Parents: expr // Children: file which must be a varref // Children: varrefs to load @@ -4160,7 +4198,7 @@ public: void filep(AstNodeVarRef* nodep) { setNOp2p(nodep); } }; -class AstSScanF : public AstNodeMath { +class AstSScanF final : public AstNodeMath { // Parents: expr // Children: file which must be a varref // Children: varrefs to load @@ -4196,7 +4234,7 @@ public: void fromp(AstNode* nodep) { setOp2p(nodep); } }; -class AstNodeReadWriteMem : public AstNodeStmt { +class AstNodeReadWriteMem VL_NOT_FINAL : public AstNodeStmt { private: bool m_isHex; // readmemh, not readmemb public: @@ -4227,7 +4265,7 @@ public: virtual const char* cFuncPrefixp() const = 0; }; -class AstReadMem : public AstNodeReadWriteMem { +class AstReadMem final : public AstNodeReadWriteMem { public: AstReadMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) @@ -4237,7 +4275,7 @@ public: virtual const char* cFuncPrefixp() const override { return "VL_READMEM_"; } }; -class AstWriteMem : public AstNodeReadWriteMem { +class AstWriteMem final : public AstNodeReadWriteMem { public: AstWriteMem(FileLine* fl, bool hex, AstNode* filenamep, AstNode* memp, AstNode* lsbp, AstNode* msbp) @@ -4247,7 +4285,30 @@ public: virtual const char* cFuncPrefixp() const override { return "VL_WRITEMEM_"; } }; -class AstSystemT : public AstNodeStmt { +class AstMonitorOff final : public AstNodeStmt { + bool m_off; // Monitor off. Using 0=on allows faster init and comparison + +public: + AstMonitorOff(FileLine* fl, bool off) + : ASTGEN_SUPER(fl) + , m_off{off} {} + ASTNODE_NODE_FUNCS(MonitorOff) + virtual string verilogKwd() const override { return m_off ? "$monitoroff" : "$monitoron"; } + virtual bool isGateOptimizable() const override { return false; } // Though deleted before opt + virtual bool isPredictOptimizable() const override { + return false; + } // Though deleted before opt + virtual bool isPure() const override { return false; } // Though deleted before opt + virtual bool isOutputter() const override { return true; } // Though deleted before opt + virtual int instrCount() const override { return instrCountPli(); } + virtual V3Hash sameHash() const override { return V3Hash(m_off); } + virtual bool same(const AstNode* samep) const override { + return m_off == static_cast(samep)->m_off; + } + bool off() const { return m_off; } +}; + +class AstSystemT final : public AstNodeStmt { // $system used as task public: AstSystemT(FileLine* fl, AstNode* lhsp) @@ -4266,7 +4327,7 @@ public: AstNode* lhsp() const { return op1p(); } }; -class AstSystemF : public AstNodeMath { +class AstSystemF final : public AstNodeMath { // $system used as function public: AstSystemF(FileLine* fl, AstNode* lhsp) @@ -4288,7 +4349,7 @@ public: AstNode* lhsp() const { return op1p(); } }; -class AstValuePlusArgs : public AstNodeMath { +class AstValuePlusArgs final : public AstNodeMath { // Parents: expr // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs public: @@ -4313,7 +4374,7 @@ public: void outp(AstNode* nodep) { setOp2p(nodep); } }; -class AstTestPlusArgs : public AstNodeMath { +class AstTestPlusArgs final : public AstNodeMath { // Parents: expr // Child: variable to set. If nullptr then this is a $test$plusargs instead of $value$plusargs private: @@ -4339,14 +4400,14 @@ public: void text(const string& text) { m_text = text; } }; -class AstGenFor : public AstNodeFor { +class AstGenFor final : public AstNodeFor { public: AstGenFor(FileLine* fl, AstNode* initsp, AstNode* condp, AstNode* incsp, AstNode* bodysp) : ASTGEN_SUPER(fl, initsp, condp, incsp, bodysp) {} ASTNODE_NODE_FUNCS(GenFor) }; -class AstForeach : public AstNodeStmt { +class AstForeach final : public AstNodeStmt { public: AstForeach(FileLine* fl, AstNode* arrayp, AstNode* bodysp) : ASTGEN_SUPER(fl) { @@ -4362,7 +4423,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstRepeat : public AstNodeStmt { +class AstRepeat final : public AstNodeStmt { public: AstRepeat(FileLine* fl, AstNode* countp, AstNode* bodysp) : ASTGEN_SUPER(fl) { @@ -4380,7 +4441,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstWait : public AstNodeStmt { +class AstWait final : public AstNodeStmt { public: AstWait(FileLine* fl, AstNode* condp, AstNode* bodysp) : ASTGEN_SUPER(fl) { @@ -4391,7 +4452,7 @@ public: AstNode* bodysp() const { return op3p(); } // op3 = body of loop }; -class AstWhile : public AstNodeStmt { +class AstWhile final : public AstNodeStmt { public: AstWhile(FileLine* fl, AstNode* condp, AstNode* bodysp, AstNode* incsp = nullptr) : ASTGEN_SUPER(fl) { @@ -4418,7 +4479,7 @@ public: virtual void addNextStmt(AstNode* newp, AstNode* belowp) override; }; -class AstBreak : public AstNodeStmt { +class AstBreak final : public AstNodeStmt { public: explicit AstBreak(FileLine* fl) : ASTGEN_SUPER(fl) {} @@ -4430,7 +4491,7 @@ public: } }; -class AstContinue : public AstNodeStmt { +class AstContinue final : public AstNodeStmt { public: explicit AstContinue(FileLine* fl) : ASTGEN_SUPER(fl) {} @@ -4442,7 +4503,7 @@ public: } }; -class AstDisable : public AstNodeStmt { +class AstDisable final : public AstNodeStmt { private: string m_name; // Name of block public: @@ -4457,7 +4518,7 @@ public: } }; -class AstDisableFork : public AstNodeStmt { +class AstDisableFork final : public AstNodeStmt { // A "disable fork" statement public: AstDisableFork(FileLine* fl) @@ -4465,7 +4526,7 @@ public: ASTNODE_NODE_FUNCS(DisableFork) }; -class AstWaitFork : public AstNodeStmt { +class AstWaitFork final : public AstNodeStmt { // A "wait fork" statement public: AstWaitFork(FileLine* fl) @@ -4473,7 +4534,7 @@ public: ASTNODE_NODE_FUNCS(WaitFork) }; -class AstReturn : public AstNodeStmt { +class AstReturn final : public AstNodeStmt { public: explicit AstReturn(FileLine* fl, AstNode* lhsp = nullptr) : ASTGEN_SUPER(fl) { @@ -4488,14 +4549,14 @@ public: } }; -class AstGenIf : public AstNodeIf { +class AstGenIf final : public AstNodeIf { public: AstGenIf(FileLine* fl, AstNode* condp, AstNode* ifsp, AstNode* elsesp) : ASTGEN_SUPER(fl, condp, ifsp, elsesp) {} ASTNODE_NODE_FUNCS(GenIf) }; -class AstIf : public AstNodeIf { +class AstIf final : public AstNodeIf { private: bool m_uniquePragma; // unique case bool m_unique0Pragma; // unique0 case @@ -4516,7 +4577,7 @@ public: void priorityPragma(bool flag) { m_priorityPragma = flag; } }; -class AstJumpBlock : public AstNodeStmt { +class AstJumpBlock final : public AstNodeStmt { // Block of code including a JumpGo and JumpLabel // Parents: {statement list} // Children: {statement list, with JumpGo and JumpLabel below} @@ -4547,7 +4608,7 @@ public: void labelp(AstJumpLabel* labelp) { m_labelp = labelp; } }; -class AstJumpLabel : public AstNodeStmt { +class AstJumpLabel final : public AstNodeStmt { // Jump point declaration // Parents: {statement list with JumpBlock above} // Children: none @@ -4576,7 +4637,7 @@ public: AstJumpBlock* blockp() const { return m_blockp; } }; -class AstJumpGo : public AstNodeStmt { +class AstJumpGo final : public AstNodeStmt { // Jump point; branch down to a JumpLabel // No support for backward jumps at present // Parents: {statement list with JumpBlock above} @@ -4608,7 +4669,7 @@ public: AstJumpLabel* labelp() const { return m_labelp; } }; -class AstChangeXor : public AstNodeBiComAsv { +class AstChangeXor final : public AstNodeBiComAsv { // A comparison to determine change detection, common & must be fast. // Returns 32-bit or 64-bit value where 0 indicates no change. // Parents: OR or LOGOR @@ -4636,7 +4697,7 @@ public: virtual int instrCount() const override { return widthInstrs(); } }; -class AstChangeDet : public AstNodeStmt { +class AstChangeDet final : public AstNodeStmt { // A comparison to determine change detection, common & must be fast. private: bool m_clockReq; // Type of detection @@ -4659,7 +4720,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstConsAssoc : public AstNodeMath { +class AstConsAssoc final : public AstNodeMath { // Construct an assoc array and return object, '{} // Parents: math // Children: expression (elements or other queues) @@ -4678,7 +4739,7 @@ public: virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } }; -class AstSetAssoc : public AstNodeMath { +class AstSetAssoc final : public AstNodeMath { // Set an assoc array element and return object, '{} // Parents: math // Children: expression (elements or other queues) @@ -4702,7 +4763,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstConsDynArray : public AstNodeMath { +class AstConsDynArray final : public AstNodeMath { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // Parents: math // Children: expression (elements or other queues) @@ -4724,7 +4785,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstConsQueue : public AstNodeMath { +class AstConsQueue final : public AstNodeMath { // Construct a queue and return object, '{}. '{lhs}, '{lhs. rhs} // Parents: math // Children: expression (elements or other queues) @@ -4746,7 +4807,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstBegin : public AstNodeBlock { +class AstBegin final : public AstNodeBlock { // A Begin/end named block, only exists shortly after parsing until linking // Parents: statement // Children: statements @@ -4771,7 +4832,7 @@ public: bool implied() const { return m_implied; } }; -class AstFork : public AstNodeBlock { +class AstFork final : public AstNodeBlock { // A fork named block // Parents: statement // Children: statements @@ -4787,13 +4848,13 @@ public: void joinType(const VJoinType& flag) { m_joinType = flag; } }; -class AstInside : public AstNodeMath { +class AstInside final : public AstNodeMath { public: AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp) : ASTGEN_SUPER(fl) { addOp1p(exprp); addOp2p(itemsp); - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Inside) AstNode* exprp() const { return op1p(); } // op1 = LHS expression to compare with @@ -4804,7 +4865,7 @@ public: virtual bool cleanOut() const override { return false; } // NA }; -class AstInsideRange : public AstNodeMath { +class AstInsideRange final : public AstNodeMath { public: AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl) { @@ -4821,7 +4882,7 @@ public: AstNode* newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp); }; -class AstInitItem : public AstNode { +class AstInitItem final : public AstNode { // Container for a item in an init array // This container is present so that the value underneath may get replaced with a new nodep // and the upper AstInitArray's map will remain correct (pointing to this InitItem) @@ -4839,7 +4900,7 @@ public: void valuep(AstNode* nodep) { addOp1p(nodep); } }; -class AstInitArray : public AstNode { +class AstInitArray final : public AstNode { // Set a var to a map of values // The list of initsp() is not relevant // If default is specified, the vector may be sparse, and not provide each value. @@ -4912,7 +4973,7 @@ public: } }; -class AstNew : public AstNodeFTaskRef { +class AstNew final : public AstNodeFTaskRef { // New as constructor // Don't need the class we are extracting from, as the "fromp()"'s datatype can get us to it // Parents: math|stmt @@ -4928,7 +4989,7 @@ public: virtual int instrCount() const override { return widthInstrs(); } }; -class AstNewCopy : public AstNodeMath { +class AstNewCopy final : public AstNodeMath { // New as shallow copy // Parents: math|stmt // Children: varref|arraysel, math @@ -4948,7 +5009,7 @@ public: AstNode* rhsp() const { return op1p(); } }; -class AstNewDynamic : public AstNodeMath { +class AstNewDynamic final : public AstNodeMath { // New for dynamic array // Parents: math|stmt // Children: varref|arraysel, math @@ -4970,7 +5031,7 @@ public: AstNode* rhsp() const { return op2p(); } }; -class AstPragma : public AstNode { +class AstPragma final : public AstNode { private: AstPragmaType m_pragType; // Type of pragma public: @@ -4988,7 +5049,7 @@ public: } }; -class AstPrintTimeScale : public AstNodeStmt { +class AstPrintTimeScale final : public AstNodeStmt { // Parents: stmtlist string m_name; // Parent module name VTimescale m_timeunit; // Parent module time unit @@ -5010,7 +5071,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstStop : public AstNodeStmt { +class AstStop final : public AstNodeStmt { public: AstStop(FileLine* fl, bool maybe) : ASTGEN_SUPER(fl) {} @@ -5029,7 +5090,7 @@ public: } }; -class AstFinish : public AstNodeStmt { +class AstFinish final : public AstNodeStmt { public: explicit AstFinish(FileLine* fl) : ASTGEN_SUPER(fl) {} @@ -5048,7 +5109,7 @@ public: } }; -class AstNullCheck : public AstNodeUniop { +class AstNullCheck final : public AstNodeUniop { // Return LHS after checking that LHS is non-null // Children: VarRef or something returning pointer public: @@ -5071,7 +5132,7 @@ public: } }; -class AstTimingControl : public AstNodeStmt { +class AstTimingControl final : public AstNodeStmt { // Parents: stmtlist public: AstTimingControl(FileLine* fl, AstSenTree* sensesp, AstNode* stmtsp) @@ -5091,7 +5152,7 @@ public: AstNode* stmtsp() const { return op2p(); } }; -class AstTimeFormat : public AstNodeStmt { +class AstTimeFormat final : public AstNodeStmt { // Parents: stmtlist public: AstTimeFormat(FileLine* fl, AstNode* unitsp, AstNode* precisionp, AstNode* suffixp, @@ -5116,7 +5177,7 @@ public: AstNode* widthp() const { return op4p(); } }; -class AstTraceDecl : public AstNodeStmt { +class AstTraceDecl final : public AstNodeStmt { // Trace point declaration // Separate from AstTraceInc; as a declaration can't be deleted // Parents: {statement list} @@ -5170,7 +5231,7 @@ public: AstNode* valuep() const { return op1p(); } }; -class AstTraceInc : public AstNodeStmt { +class AstTraceInc final : public AstNodeStmt { // Trace point dump // Parents: {statement list} // Children: op1: things to emit before this node, @@ -5214,7 +5275,7 @@ public: bool full() const { return m_full; } }; -class AstActive : public AstNode { +class AstActive final : public AstNode { // Block of code with sensitivity activation // Parents: MODULE | CFUNC // Children: SENTREE, statements @@ -5257,7 +5318,7 @@ public: bool hasClocked() const { return m_sensesp->hasClocked(); } }; -class AstAttrOf : public AstNode { +class AstAttrOf final : public AstNode { private: // Return a value of a attribute, for example a LSB or array LSB of a signal AstAttrType m_attrType; // What sort of extraction @@ -5277,7 +5338,7 @@ public: virtual void dump(std::ostream& str = std::cout) const override; }; -class AstScopeName : public AstNodeMath { +class AstScopeName final : public AstNodeMath { // For display %m and DPI context imports // Parents: DISPLAY // Children: TEXT @@ -5319,7 +5380,7 @@ public: void dpiExport(bool flag) { m_dpiExport = flag; } }; -class AstUdpTable : public AstNode { +class AstUdpTable final : public AstNode { public: AstUdpTable(FileLine* fl, AstNode* bodysp) : ASTGEN_SUPER(fl) { @@ -5330,7 +5391,7 @@ public: AstUdpTableLine* bodysp() const { return VN_CAST(op1p(), UdpTableLine); } }; -class AstUdpTableLine : public AstNode { +class AstUdpTableLine final : public AstNode { string m_text; public: @@ -5345,23 +5406,33 @@ public: //====================================================================== // non-ary ops -class AstRand : public AstNodeTermop { +class AstRand final : public AstNodeMath { + // $random/$random(seed) or $urandom/$urandom(seed) // Return a random number, based upon width() private: - bool m_reset; // Random reset, versus always random + bool m_urandom = false; // $urandom vs $random + bool m_reset = false; // Random reset, versus always random public: - AstRand(FileLine* fl, AstNodeDType* dtp, bool reset) + class Reset {}; + AstRand(FileLine* fl, Reset, AstNodeDType* dtp, bool reset) : ASTGEN_SUPER(fl) , m_reset{reset} { dtypep(dtp); } - explicit AstRand(FileLine* fl) + AstRand(FileLine* fl, AstNode* seedp, bool urandom) : ASTGEN_SUPER(fl) - , m_reset{false} {} + , m_urandom(urandom) { + setNOp1p(seedp); + } ASTNODE_NODE_FUNCS(Rand) - virtual string emitVerilog() override { return "%f$random"; } + virtual string emitVerilog() override { + return seedp() ? (m_urandom ? "%f$urandom(%l)" : "%f$random(%l)") + : (m_urandom ? "%f$urandom()" : "%f$random()"); + } virtual string emitC() override { - return (m_reset ? "VL_RAND_RESET_%nq(%nw, %P)" : "VL_RANDOM_%nq(%nw, %P)"); + return m_reset + ? "VL_RAND_RESET_%nq(%nw, %P)" + : seedp() ? "VL_RANDOM_SEEDED_%nq%lq(%nw, %P, %li)" : "VL_RANDOM_%nq(%nw, %P)"; } virtual bool cleanOut() const override { return true; } virtual bool isGateOptimizable() const override { return false; } @@ -5369,27 +5440,12 @@ public: virtual int instrCount() const override { return instrCountPli(); } virtual V3Hash sameHash() const override { return V3Hash(); } virtual bool same(const AstNode* samep) const override { return true; } + AstNode* seedp() const { return op1p(); } + bool reset() const { return m_reset; } + bool urandom() const { return m_urandom; } }; -class AstURandom : public AstNodeTermop { - // $urandom -public: - explicit AstURandom(FileLine* fl) - : ASTGEN_SUPER(fl) { - dtypeSetUInt32(); // Says IEEE - } - ASTNODE_NODE_FUNCS(URandom) - virtual string emitVerilog() override { return "%f$urandom"; } - virtual string emitC() override { return "VL_RANDOM_%nq(%nw)"; } - virtual bool cleanOut() const override { return true; } - virtual bool isGateOptimizable() const override { return false; } - virtual bool isPredictOptimizable() const override { return false; } - virtual int instrCount() const override { return instrCountPli(); } - virtual V3Hash sameHash() const override { return V3Hash(); } - virtual bool same(const AstNode* samep) const override { return true; } -}; - -class AstURandomRange : public AstNodeBiop { +class AstURandomRange final : public AstNodeBiop { // $urandom_range public: explicit AstURandomRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -5415,7 +5471,7 @@ public: virtual int instrCount() const override { return instrCountPli(); } }; -class AstTime : public AstNodeTermop { +class AstTime final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTime(FileLine* fl, const VTimescale& timeunit) @@ -5437,7 +5493,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstTimeD : public AstNodeTermop { +class AstTimeD final : public AstNodeTermop { VTimescale m_timeunit; // Parent module time unit public: AstTimeD(FileLine* fl, const VTimescale& timeunit) @@ -5459,7 +5515,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstUCFunc : public AstNodeMath { +class AstUCFunc final : public AstNodeMath { // User's $c function // Perhaps this should be an AstNodeListop; but there's only one list math right now public: @@ -5485,7 +5541,7 @@ public: //====================================================================== // Unary ops -class AstNegate : public AstNodeUniop { +class AstNegate final : public AstNodeUniop { public: AstNegate(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5500,7 +5556,7 @@ public: virtual bool cleanLhs() const override { return false; } virtual bool sizeMattersLhs() const override { return true; } }; -class AstNegateD : public AstNodeUniop { +class AstNegateD final : public AstNodeUniop { public: AstNegateD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5517,11 +5573,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstRedAnd : public AstNodeUniop { +class AstRedAnd final : public AstNodeUniop { public: AstRedAnd(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedAnd) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedAnd(lhs); } @@ -5531,11 +5587,11 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstRedOr : public AstNodeUniop { +class AstRedOr final : public AstNodeUniop { public: AstRedOr(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedOr) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedOr(lhs); } @@ -5545,11 +5601,11 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstRedXor : public AstNodeUniop { +class AstRedXor final : public AstNodeUniop { public: AstRedXor(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedXor) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXor(lhs); } @@ -5563,12 +5619,12 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return 1 + V3Number::log2b(width()); } }; -class AstRedXnor : public AstNodeUniop { +class AstRedXnor final : public AstNodeUniop { // AstRedXnors are replaced with AstRedXors in V3Const. public: AstRedXnor(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(RedXnor) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opRedXnor(lhs); } @@ -5583,7 +5639,7 @@ public: virtual int instrCount() const override { return 1 + V3Number::log2b(width()); } }; -class AstLenN : public AstNodeUniop { +class AstLenN final : public AstNodeUniop { // Length of a string public: AstLenN(FileLine* fl, AstNode* lhsp) @@ -5598,11 +5654,11 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstLogNot : public AstNodeUniop { +class AstLogNot final : public AstNodeUniop { public: AstLogNot(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogNot) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opLogNot(lhs); } @@ -5613,7 +5669,7 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstNot : public AstNodeUniop { +class AstNot final : public AstNodeUniop { public: AstNot(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5628,7 +5684,7 @@ public: virtual bool cleanLhs() const override { return false; } virtual bool sizeMattersLhs() const override { return true; } }; -class AstExtend : public AstNodeUniop { +class AstExtend final : public AstNodeUniop { // Expand a value into a wider entity by 0 extension. Width is implied from nodep->width() public: AstExtend(FileLine* fl, AstNode* lhsp) @@ -5648,7 +5704,7 @@ public: } virtual int instrCount() const override { return 0; } }; -class AstExtendS : public AstNodeUniop { +class AstExtendS final : public AstNodeUniop { // Expand a value into a wider entity by sign extension. Width is implied from nodep->width() public: AstExtendS(FileLine* fl, AstNode* lhsp) @@ -5672,7 +5728,7 @@ public: virtual int instrCount() const override { return 0; } virtual bool signedFlavor() const override { return true; } }; -class AstSigned : public AstNodeUniop { +class AstSigned final : public AstNodeUniop { // $signed(lhs) public: AstSigned(FileLine* fl, AstNode* lhsp) @@ -5692,7 +5748,7 @@ public: virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters virtual int instrCount() const override { return 0; } }; -class AstUnsigned : public AstNodeUniop { +class AstUnsigned final : public AstNodeUniop { // $unsigned(lhs) public: AstUnsigned(FileLine* fl, AstNode* lhsp) @@ -5712,7 +5768,7 @@ public: virtual bool sizeMattersLhs() const override { return true; } // Eliminated before matters virtual int instrCount() const override { return 0; } }; -class AstRToIS : public AstNodeUniop { +class AstRToIS final : public AstNodeUniop { // $rtoi(lhs) public: AstRToIS(FileLine* fl, AstNode* lhsp) @@ -5728,7 +5784,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters virtual int instrCount() const override { return instrCountDouble(); } }; -class AstRToIRoundS : public AstNodeUniop { +class AstRToIRoundS final : public AstNodeUniop { // Convert real to integer, with arbitrary sized output (not just "integer" format) public: AstRToIRoundS(FileLine* fl, AstNode* lhsp) @@ -5746,7 +5802,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return instrCountDouble(); } }; -class AstIToRD : public AstNodeUniop { +class AstIToRD final : public AstNodeUniop { // $itor where lhs is unsigned public: AstIToRD(FileLine* fl, AstNode* lhsp) @@ -5762,7 +5818,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return instrCountDouble(); } }; -class AstISToRD : public AstNodeUniop { +class AstISToRD final : public AstNodeUniop { // $itor where lhs is signed public: AstISToRD(FileLine* fl, AstNode* lhsp) @@ -5779,7 +5835,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return instrCountDouble(); } }; -class AstRealToBits : public AstNodeUniop { +class AstRealToBits final : public AstNodeUniop { public: AstRealToBits(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5796,7 +5852,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } // Eliminated before matters virtual int instrCount() const override { return instrCountDouble(); } }; -class AstBitsToRealD : public AstNodeUniop { +class AstBitsToRealD final : public AstNodeUniop { public: AstBitsToRealD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { @@ -5814,7 +5870,7 @@ public: virtual int instrCount() const override { return instrCountDouble(); } }; -class AstCLog2 : public AstNodeUniop { +class AstCLog2 final : public AstNodeUniop { public: AstCLog2(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -5827,7 +5883,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 16; } }; -class AstCountBits : public AstNodeQuadop { +class AstCountBits final : public AstNodeQuadop { // Number of bits set in vector public: AstCountBits(FileLine* fl, AstNode* exprp, AstNode* ctrl1p) @@ -5854,7 +5910,7 @@ public: virtual bool sizeMattersFhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 16; } }; -class AstCountOnes : public AstNodeUniop { +class AstCountOnes final : public AstNodeUniop { // Number of bits set in vector public: AstCountOnes(FileLine* fl, AstNode* lhsp) @@ -5870,12 +5926,12 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 16; } }; -class AstIsUnknown : public AstNodeUniop { +class AstIsUnknown final : public AstNodeUniop { // True if any unknown bits public: AstIsUnknown(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnknown) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { @@ -5887,12 +5943,12 @@ public: virtual bool cleanLhs() const override { return false; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstIsUnbounded : public AstNodeUniop { +class AstIsUnbounded final : public AstNodeUniop { // True if is unmbounded ($) public: AstIsUnbounded(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(IsUnbounded) virtual void numberOperate(V3Number& out, const V3Number&) override { @@ -5905,12 +5961,12 @@ public: virtual bool cleanLhs() const override { return false; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstOneHot : public AstNodeUniop { +class AstOneHot final : public AstNodeUniop { // True if only single bit set in vector public: AstOneHot(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot(lhs); } @@ -5921,12 +5977,12 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 4; } }; -class AstOneHot0 : public AstNodeUniop { +class AstOneHot0 final : public AstNodeUniop { // True if only single bit, or no bits set in vector public: AstOneHot0(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(OneHot0) virtual void numberOperate(V3Number& out, const V3Number& lhs) override { out.opOneHot0(lhs); } @@ -5938,15 +5994,20 @@ public: virtual int instrCount() const override { return widthInstrs() * 3; } }; -class AstCast : public AstNode { +class AstCast final : public AstNode { // Cast to appropriate data type - note lhsp is value, to match AstTypedef, AstCCast, etc public: - AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) + AstCast(FileLine* fl, AstNode* lhsp, VFlagChildDType, AstNodeDType* dtp) : ASTGEN_SUPER(fl) { setOp1p(lhsp); setOp2p(dtp); dtypeFrom(dtp); } + AstCast(FileLine* fl, AstNode* lhsp, AstNodeDType* dtp) + : ASTGEN_SUPER(fl) { + setOp1p(lhsp); + dtypeFrom(dtp); + } ASTNODE_NODE_FUNCS(Cast) virtual bool hasDType() const override { return true; } virtual string emitVerilog() { return "((%d)'(%l))"; } @@ -5960,7 +6021,7 @@ public: virtual AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); } }; -class AstCastDynamic : public AstNodeBiop { +class AstCastDynamic final : public AstNodeBiop { // Verilog $cast used as a function // Task usage of $cast is converted during parse to assert($cast(...)) // Parents: MATH @@ -5987,7 +6048,7 @@ public: virtual bool isPure() const override { return true; } }; -class AstCastParse : public AstNode { +class AstCastParse final : public AstNode { // Cast to appropriate type, where we haven't determined yet what the data type is public: AstCastParse(FileLine* fl, AstNode* lhsp, AstNode* dtp) @@ -6005,7 +6066,7 @@ public: AstNode* dtp() const { return op2p(); } }; -class AstCastSize : public AstNode { +class AstCastSize final : public AstNode { // Cast to specific size; signed/twostate inherited from lower element per IEEE public: AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) @@ -6023,7 +6084,7 @@ public: AstNode* rhsp() const { return op2p(); } }; -class AstCCast : public AstNodeUniop { +class AstCCast final : public AstNodeUniop { // Cast to C-based data type private: int m_size; @@ -6058,7 +6119,7 @@ public: int size() const { return m_size; } }; -class AstCvtPackString : public AstNodeUniop { +class AstCvtPackString final : public AstNodeUniop { // Convert to Verilator Packed String (aka verilog "string") public: AstCvtPackString(FileLine* fl, AstNode* lhsp) @@ -6076,7 +6137,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstFEof : public AstNodeUniop { +class AstFEof final : public AstNodeUniop { public: AstFEof(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6094,7 +6155,7 @@ public: AstNode* filep() const { return lhsp(); } }; -class AstFError : public AstNodeMath { +class AstFError final : public AstNodeMath { public: AstFError(FileLine* fl, AstNode* filep, AstNode* strp) : ASTGEN_SUPER(fl) { @@ -6119,7 +6180,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstFGetC : public AstNodeUniop { +class AstFGetC final : public AstNodeUniop { public: AstFGetC(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6138,7 +6199,7 @@ public: AstNode* filep() const { return lhsp(); } }; -class AstFUngetC : public AstNodeBiop { +class AstFUngetC final : public AstNodeBiop { public: AstFUngetC(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} @@ -6167,7 +6228,7 @@ public: AstNode* charp() const { return rhsp(); } }; -class AstNodeSystemUniop : public AstNodeUniop { +class AstNodeSystemUniop VL_NOT_FINAL : public AstNodeUniop { public: AstNodeSystemUniop(AstType t, FileLine* fl, AstNode* lhsp) : AstNodeUniop(t, fl, lhsp) { @@ -6181,7 +6242,7 @@ public: virtual bool doubleFlavor() const override { return true; } }; -class AstLogD : public AstNodeSystemUniop { +class AstLogD final : public AstNodeSystemUniop { public: AstLogD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6192,7 +6253,7 @@ public: virtual string emitVerilog() override { return "%f$ln(%l)"; } virtual string emitC() override { return "log(%li)"; } }; -class AstLog10D : public AstNodeSystemUniop { +class AstLog10D final : public AstNodeSystemUniop { public: AstLog10D(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6204,7 +6265,7 @@ public: virtual string emitC() override { return "log10(%li)"; } }; -class AstExpD : public AstNodeSystemUniop { +class AstExpD final : public AstNodeSystemUniop { public: AstExpD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6216,7 +6277,7 @@ public: virtual string emitC() override { return "exp(%li)"; } }; -class AstSqrtD : public AstNodeSystemUniop { +class AstSqrtD final : public AstNodeSystemUniop { public: AstSqrtD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6228,7 +6289,7 @@ public: virtual string emitC() override { return "sqrt(%li)"; } }; -class AstFloorD : public AstNodeSystemUniop { +class AstFloorD final : public AstNodeSystemUniop { public: AstFloorD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6240,7 +6301,7 @@ public: virtual string emitC() override { return "floor(%li)"; } }; -class AstCeilD : public AstNodeSystemUniop { +class AstCeilD final : public AstNodeSystemUniop { public: AstCeilD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6252,7 +6313,7 @@ public: virtual string emitC() override { return "ceil(%li)"; } }; -class AstSinD : public AstNodeSystemUniop { +class AstSinD final : public AstNodeSystemUniop { public: AstSinD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6264,7 +6325,7 @@ public: virtual string emitC() override { return "sin(%li)"; } }; -class AstCosD : public AstNodeSystemUniop { +class AstCosD final : public AstNodeSystemUniop { public: AstCosD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6276,7 +6337,7 @@ public: virtual string emitC() override { return "cos(%li)"; } }; -class AstTanD : public AstNodeSystemUniop { +class AstTanD final : public AstNodeSystemUniop { public: AstTanD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6288,7 +6349,7 @@ public: virtual string emitC() override { return "tan(%li)"; } }; -class AstAsinD : public AstNodeSystemUniop { +class AstAsinD final : public AstNodeSystemUniop { public: AstAsinD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6300,7 +6361,7 @@ public: virtual string emitC() override { return "asin(%li)"; } }; -class AstAcosD : public AstNodeSystemUniop { +class AstAcosD final : public AstNodeSystemUniop { public: AstAcosD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6312,7 +6373,7 @@ public: virtual string emitC() override { return "acos(%li)"; } }; -class AstAtanD : public AstNodeSystemUniop { +class AstAtanD final : public AstNodeSystemUniop { public: AstAtanD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6324,7 +6385,7 @@ public: virtual string emitC() override { return "atan(%li)"; } }; -class AstSinhD : public AstNodeSystemUniop { +class AstSinhD final : public AstNodeSystemUniop { public: AstSinhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6336,7 +6397,7 @@ public: virtual string emitC() override { return "sinh(%li)"; } }; -class AstCoshD : public AstNodeSystemUniop { +class AstCoshD final : public AstNodeSystemUniop { public: AstCoshD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6348,7 +6409,7 @@ public: virtual string emitC() override { return "cosh(%li)"; } }; -class AstTanhD : public AstNodeSystemUniop { +class AstTanhD final : public AstNodeSystemUniop { public: AstTanhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6360,7 +6421,7 @@ public: virtual string emitC() override { return "tanh(%li)"; } }; -class AstAsinhD : public AstNodeSystemUniop { +class AstAsinhD final : public AstNodeSystemUniop { public: AstAsinhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6372,7 +6433,7 @@ public: virtual string emitC() override { return "asinh(%li)"; } }; -class AstAcoshD : public AstNodeSystemUniop { +class AstAcoshD final : public AstNodeSystemUniop { public: AstAcoshD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6384,7 +6445,7 @@ public: virtual string emitC() override { return "acosh(%li)"; } }; -class AstAtanhD : public AstNodeSystemUniop { +class AstAtanhD final : public AstNodeSystemUniop { public: AstAtanhD(FileLine* fl, AstNode* lhsp) : ASTGEN_SUPER(fl, lhsp) {} @@ -6395,7 +6456,7 @@ public: virtual string emitVerilog() override { return "%f$atanh(%l)"; } virtual string emitC() override { return "atanh(%li)"; } }; -class AstToLowerN : public AstNodeUniop { +class AstToLowerN final : public AstNodeUniop { // string.tolower() public: AstToLowerN(FileLine* fl, AstNode* lhsp) @@ -6412,7 +6473,7 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstToUpperN : public AstNodeUniop { +class AstToUpperN final : public AstNodeUniop { // string.toupper() public: AstToUpperN(FileLine* fl, AstNode* lhsp) @@ -6429,7 +6490,7 @@ public: virtual bool cleanLhs() const override { return true; } virtual bool sizeMattersLhs() const override { return false; } }; -class AstTimeImport : public AstNodeUniop { +class AstTimeImport final : public AstNodeUniop { // Take a constant that represents a time and needs conversion based on time units VTimescale m_timeunit; // Parent module time unit public: @@ -6447,7 +6508,7 @@ public: VTimescale timeunit() const { return m_timeunit; } }; -class AstAtoN : public AstNodeUniop { +class AstAtoN final : public AstNodeUniop { // string.atoi(), atobin(), atohex(), atooct(), atoireal() public: enum FmtType { ATOI = 10, ATOHEX = 16, ATOOCT = 8, ATOBIN = 2, ATOREAL = -1 }; @@ -6495,11 +6556,11 @@ public: //====================================================================== // Binary ops -class AstLogOr : public AstNodeBiop { +class AstLogOr final : public AstNodeBiop { public: AstLogOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogOr) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6518,11 +6579,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() + instrCountBranch(); } }; -class AstLogAnd : public AstNodeBiop { +class AstLogAnd final : public AstNodeBiop { public: AstLogAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogAnd) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6541,11 +6602,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() + instrCountBranch(); } }; -class AstLogEq : public AstNodeBiCom { +class AstLogEq final : public AstNodeBiCom { public: AstLogEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogEq) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6564,11 +6625,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() + instrCountBranch(); } }; -class AstLogIf : public AstNodeBiop { +class AstLogIf final : public AstNodeBiop { public: AstLogIf(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LogIf) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6587,7 +6648,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() + instrCountBranch(); } }; -class AstOr : public AstNodeBiComAsv { +class AstOr final : public AstNodeBiComAsv { public: AstOr(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -6609,7 +6670,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstAnd : public AstNodeBiComAsv { +class AstAnd final : public AstNodeBiComAsv { public: AstAnd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -6631,7 +6692,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstXor : public AstNodeBiComAsv { +class AstXor final : public AstNodeBiComAsv { public: AstXor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -6653,7 +6714,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstXnor : public AstNodeBiComAsv { +class AstXnor final : public AstNodeBiComAsv { public: AstXnor(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -6675,11 +6736,11 @@ public: virtual bool sizeMattersLhs() const override { return true; } virtual bool sizeMattersRhs() const override { return true; } }; -class AstEq : public AstNodeBiCom { +class AstEq final : public AstNodeBiCom { public: AstEq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Eq) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6699,11 +6760,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstEqD : public AstNodeBiCom { +class AstEqD final : public AstNodeBiCom { public: AstEqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6723,11 +6784,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstEqN : public AstNodeBiCom { +class AstEqN final : public AstNodeBiCom { public: AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6747,11 +6808,11 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstNeq : public AstNodeBiCom { +class AstNeq final : public AstNodeBiCom { public: AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Neq) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6769,11 +6830,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstNeqD : public AstNodeBiCom { +class AstNeqD final : public AstNodeBiCom { public: AstNeqD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6793,11 +6854,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstNeqN : public AstNodeBiCom { +class AstNeqN final : public AstNodeBiCom { public: AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6817,11 +6878,11 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstLt : public AstNodeBiop { +class AstLt final : public AstNodeBiop { public: AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lt) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6839,11 +6900,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstLtD : public AstNodeBiop { +class AstLtD final : public AstNodeBiop { public: AstLtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6863,11 +6924,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstLtS : public AstNodeBiop { +class AstLtS final : public AstNodeBiop { public: AstLtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6886,11 +6947,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual bool signedFlavor() const override { return true; } }; -class AstLtN : public AstNodeBiop { +class AstLtN final : public AstNodeBiop { public: AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LtN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6910,11 +6971,11 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstGt : public AstNodeBiop { +class AstGt final : public AstNodeBiop { public: AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gt) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6932,11 +6993,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstGtD : public AstNodeBiop { +class AstGtD final : public AstNodeBiop { public: AstGtD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6956,11 +7017,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstGtS : public AstNodeBiop { +class AstGtS final : public AstNodeBiop { public: AstGtS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -6979,11 +7040,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual bool signedFlavor() const override { return true; } }; -class AstGtN : public AstNodeBiop { +class AstGtN final : public AstNodeBiop { public: AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GtN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7003,11 +7064,11 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstGte : public AstNodeBiop { +class AstGte final : public AstNodeBiop { public: AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Gte) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7027,11 +7088,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstGteD : public AstNodeBiop { +class AstGteD final : public AstNodeBiop { public: AstGteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7051,11 +7112,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstGteS : public AstNodeBiop { +class AstGteS final : public AstNodeBiop { public: AstGteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7074,11 +7135,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual bool signedFlavor() const override { return true; } }; -class AstGteN : public AstNodeBiop { +class AstGteN final : public AstNodeBiop { public: AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(GteN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7098,11 +7159,11 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstLte : public AstNodeBiop { +class AstLte final : public AstNodeBiop { public: AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(Lte) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7122,11 +7183,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstLteD : public AstNodeBiop { +class AstLteD final : public AstNodeBiop { public: AstLteD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteD) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7146,11 +7207,11 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstLteS : public AstNodeBiop { +class AstLteS final : public AstNodeBiop { public: AstLteS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteS) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7169,11 +7230,11 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual bool signedFlavor() const override { return true; } }; -class AstLteN : public AstNodeBiop { +class AstLteN final : public AstNodeBiop { public: AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(LteN) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7193,7 +7254,7 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstShiftL : public AstNodeBiop { +class AstShiftL final : public AstNodeBiop { public: AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7215,7 +7276,7 @@ public: virtual bool sizeMattersLhs() const override { return true; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstShiftR : public AstNodeBiop { +class AstShiftR final : public AstNodeBiop { public: AstShiftR(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth = 0) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7238,7 +7299,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstShiftRS : public AstNodeBiop { +class AstShiftRS final : public AstNodeBiop { // Shift right with sign extension, >>> operator // Output data type's width determines which bit is used for sign extension public: @@ -7264,7 +7325,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual bool signedFlavor() const override { return true; } }; -class AstAdd : public AstNodeBiComAsv { +class AstAdd final : public AstNodeBiComAsv { public: AstAdd(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7286,7 +7347,7 @@ public: virtual bool sizeMattersLhs() const override { return true; } virtual bool sizeMattersRhs() const override { return true; } }; -class AstAddD : public AstNodeBiComAsv { +class AstAddD final : public AstNodeBiComAsv { public: AstAddD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7310,7 +7371,7 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstSub : public AstNodeBiop { +class AstSub final : public AstNodeBiop { public: AstSub(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7332,7 +7393,7 @@ public: virtual bool sizeMattersLhs() const override { return true; } virtual bool sizeMattersRhs() const override { return true; } }; -class AstSubD : public AstNodeBiop { +class AstSubD final : public AstNodeBiop { public: AstSubD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7356,7 +7417,7 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstMul : public AstNodeBiComAsv { +class AstMul final : public AstNodeBiComAsv { public: AstMul(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7379,7 +7440,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual int instrCount() const override { return widthInstrs() * instrCountMul(); } }; -class AstMulD : public AstNodeBiComAsv { +class AstMulD final : public AstNodeBiComAsv { public: AstMulD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7403,7 +7464,7 @@ public: virtual int instrCount() const override { return instrCountDouble(); } virtual bool doubleFlavor() const override { return true; } }; -class AstMulS : public AstNodeBiComAsv { +class AstMulS final : public AstNodeBiComAsv { public: AstMulS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7428,7 +7489,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountMul(); } virtual bool signedFlavor() const override { return true; } }; -class AstDiv : public AstNodeBiop { +class AstDiv final : public AstNodeBiop { public: AstDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7450,7 +7511,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual int instrCount() const override { return widthInstrs() * instrCountDiv(); } }; -class AstDivD : public AstNodeBiop { +class AstDivD final : public AstNodeBiop { public: AstDivD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7474,7 +7535,7 @@ public: virtual int instrCount() const override { return instrCountDoubleDiv(); } virtual bool doubleFlavor() const override { return true; } }; -class AstDivS : public AstNodeBiop { +class AstDivS final : public AstNodeBiop { public: AstDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7497,7 +7558,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountDiv(); } virtual bool signedFlavor() const override { return true; } }; -class AstModDiv : public AstNodeBiop { +class AstModDiv final : public AstNodeBiop { public: AstModDiv(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7519,7 +7580,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual int instrCount() const override { return widthInstrs() * instrCountDiv(); } }; -class AstModDivS : public AstNodeBiop { +class AstModDivS final : public AstNodeBiop { public: AstModDivS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7542,7 +7603,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountDiv(); } virtual bool signedFlavor() const override { return true; } }; -class AstPow : public AstNodeBiop { +class AstPow final : public AstNodeBiop { public: AstPow(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7565,7 +7626,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * instrCountMul() * 10; } }; -class AstPowD : public AstNodeBiop { +class AstPowD final : public AstNodeBiop { public: AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7588,7 +7649,7 @@ public: virtual int instrCount() const override { return instrCountDoubleDiv() * 5; } virtual bool doubleFlavor() const override { return true; } }; -class AstPowSU : public AstNodeBiop { +class AstPowSU final : public AstNodeBiop { public: AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7614,7 +7675,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const override { return true; } }; -class AstPowSS : public AstNodeBiop { +class AstPowSS final : public AstNodeBiop { public: AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7640,7 +7701,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const override { return true; } }; -class AstPowUS : public AstNodeBiop { +class AstPowUS final : public AstNodeBiop { public: AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { @@ -7666,7 +7727,7 @@ public: virtual int instrCount() const override { return widthInstrs() * instrCountMul() * 10; } virtual bool signedFlavor() const override { return true; } }; -class AstPreAdd : public AstNodeTriop { +class AstPreAdd final : public AstNodeTriop { // Pre-increment/add // Parents: MATH // Children: lhsp: AstConst (1) as currently support only ++ not += @@ -7691,7 +7752,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual bool sizeMattersThs() const override { return true; } }; -class AstPreSub : public AstNodeTriop { +class AstPreSub final : public AstNodeTriop { // Pre-decrement/subtract // Parents: MATH // Children: lhsp: AstConst (1) as currently support only -- not -= @@ -7716,7 +7777,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual bool sizeMattersThs() const override { return true; } }; -class AstPostAdd : public AstNodeTriop { +class AstPostAdd final : public AstNodeTriop { // Post-increment/add // Parents: MATH // Children: lhsp: AstConst (1) as currently support only ++ not += @@ -7741,7 +7802,7 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual bool sizeMattersThs() const override { return true; } }; -class AstPostSub : public AstNodeTriop { +class AstPostSub final : public AstNodeTriop { // Post-decrement/subtract // Parents: MATH // Children: lhsp: AstConst (1) as currently support only -- not -= @@ -7766,11 +7827,11 @@ public: virtual bool sizeMattersRhs() const override { return true; } virtual bool sizeMattersThs() const override { return true; } }; -class AstEqCase : public AstNodeBiCom { +class AstEqCase final : public AstNodeBiCom { public: AstEqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqCase) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7788,11 +7849,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstNeqCase : public AstNodeBiCom { +class AstNeqCase final : public AstNodeBiCom { public: AstNeqCase(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqCase) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7810,12 +7871,12 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstEqWild : public AstNodeBiop { +class AstEqWild final : public AstNodeBiop { // Note wildcard operator rhs differs from lhs public: AstEqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(EqWild) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7835,11 +7896,11 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstNeqWild : public AstNodeBiop { +class AstNeqWild final : public AstNodeBiop { public: AstNeqWild(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) { - dtypeSetLogicBool(); + dtypeSetBit(); } ASTNODE_NODE_FUNCS(NeqWild) virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) override { @@ -7857,7 +7918,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstConcat : public AstNodeBiop { +class AstConcat final : public AstNodeBiop { // If you're looking for {#{}}, see AstReplicate public: AstConcat(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -7883,7 +7944,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 2; } }; -class AstConcatN : public AstNodeBiop { +class AstConcatN final : public AstNodeBiop { // String concatenate public: AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -7907,7 +7968,7 @@ public: virtual int instrCount() const override { return instrCountString(); } virtual bool stringFlavor() const override { return true; } }; -class AstReplicate : public AstNodeBiop { +class AstReplicate final : public AstNodeBiop { // Also used as a "Uniop" flavor of Concat, e.g. "{a}" // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp() public: @@ -7937,7 +7998,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 2; } }; -class AstReplicateN : public AstNodeBiop { +class AstReplicateN final : public AstNodeBiop { // String replicate public: AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -7963,7 +8024,7 @@ public: virtual int instrCount() const override { return widthInstrs() * 2; } virtual bool stringFlavor() const override { return true; } }; -class AstStreamL : public AstNodeStream { +class AstStreamL final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -7984,7 +8045,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 2; } }; -class AstStreamR : public AstNodeStream { +class AstStreamR final : public AstNodeStream { // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp() public: AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -8005,7 +8066,7 @@ public: virtual bool sizeMattersRhs() const override { return false; } virtual int instrCount() const override { return widthInstrs() * 2; } }; -class AstBufIf1 : public AstNodeBiop { +class AstBufIf1 final : public AstNodeBiop { // lhs is enable, rhs is data to drive // Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp // bit enables respective rhsp bit @@ -8030,7 +8091,7 @@ public: virtual bool sizeMattersLhs() const override { return false; } virtual bool sizeMattersRhs() const override { return false; } }; -class AstFGetS : public AstNodeBiop { +class AstFGetS final : public AstNodeBiop { public: AstFGetS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} @@ -8056,7 +8117,7 @@ public: AstNode* filep() const { return rhsp(); } }; -class AstNodeSystemBiop : public AstNodeBiop { +class AstNodeSystemBiop VL_NOT_FINAL : public AstNodeBiop { public: AstNodeSystemBiop(AstType t, FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(t, fl, lhsp, rhsp) { @@ -8071,7 +8132,7 @@ public: virtual bool doubleFlavor() const override { return true; } }; -class AstAtan2D : public AstNodeSystemBiop { +class AstAtan2D final : public AstNodeSystemBiop { public: AstAtan2D(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} @@ -8086,7 +8147,7 @@ public: virtual string emitC() override { return "atan2(%li,%ri)"; } }; -class AstHypotD : public AstNodeSystemBiop { +class AstHypotD final : public AstNodeSystemBiop { public: AstHypotD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : ASTGEN_SUPER(fl, lhsp, rhsp) {} @@ -8101,7 +8162,7 @@ public: virtual string emitC() override { return "hypot(%li,%ri)"; } }; -class AstPutcN : public AstNodeTriop { +class AstPutcN final : public AstNodeTriop { // Verilog string.putc() public: AstPutcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) @@ -8127,7 +8188,7 @@ public: virtual bool isHeavy() const override { return true; } }; -class AstGetcN : public AstNodeBiop { +class AstGetcN final : public AstNodeBiop { // Verilog string.getc() public: AstGetcN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) @@ -8153,7 +8214,7 @@ public: virtual bool isHeavy() const override { return true; } }; -class AstGetcRefN : public AstNodeBiop { +class AstGetcRefN final : public AstNodeBiop { // Verilog string[#] on the left-hand-side of assignment // Spec says is of type byte (not string of single character) public: @@ -8179,7 +8240,7 @@ public: virtual bool isHeavy() const override { return true; } }; -class AstSubstrN : public AstNodeTriop { +class AstSubstrN final : public AstNodeTriop { // Verilog string.substr() public: AstSubstrN(FileLine* fl, AstNode* lhsp, AstNode* rhsp, AstNode* ths) @@ -8205,7 +8266,7 @@ public: virtual bool isHeavy() const override { return true; } }; -class AstCompareNN : public AstNodeBiop { +class AstCompareNN final : public AstNodeBiop { // Verilog str.compare() and str.icompare() private: bool m_ignoreCase; // True for str.icompare() @@ -8238,7 +8299,7 @@ public: virtual bool isHeavy() const override { return true; } }; -class AstFell : public AstNodeMath { +class AstFell final : public AstNodeMath { // Verilog $fell // Parents: math // Children: expression @@ -8260,7 +8321,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstPast : public AstNodeMath { +class AstPast final : public AstNodeMath { // Verilog $past // Parents: math // Children: expression @@ -8284,7 +8345,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstRose : public AstNodeMath { +class AstRose final : public AstNodeMath { // Verilog $rose // Parents: math // Children: expression @@ -8306,7 +8367,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstSampled : public AstNodeMath { +class AstSampled final : public AstNodeMath { // Verilog $sampled // Parents: math // Children: expression @@ -8326,7 +8387,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstStable : public AstNodeMath { +class AstStable final : public AstNodeMath { // Verilog $stable // Parents: math // Children: expression @@ -8348,7 +8409,7 @@ public: virtual bool same(const AstNode* samep) const override { return true; } }; -class AstPattern : public AstNodeMath { +class AstPattern final : public AstNodeMath { // Verilog '{a,b,c,d...} // Parents: AstNodeAssign, AstPattern, ... // Children: expression, AstPattern, AstPatReplicate @@ -8370,7 +8431,7 @@ public: void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); } AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc }; -class AstPatMember : public AstNodeMath { +class AstPatMember final : public AstNodeMath { // Verilog '{a} or '{a{b}} // Parents: AstPattern // Children: expression, AstPattern, replication count @@ -8397,7 +8458,7 @@ public: void isDefault(bool flag) { m_default = flag; } }; -class AstImplication : public AstNodeMath { +class AstImplication final : public AstNodeMath { // Verilog |-> |=> // Parents: math // Children: expression @@ -8426,7 +8487,7 @@ public: //====================================================================== // Assertions -class AstClocking : public AstNode { +class AstClocking final : public AstNode { // Set default clock region // Parents: MODULE // Children: Assertions @@ -8445,7 +8506,7 @@ public: //====================================================================== // PSL -class AstPropClocked : public AstNode { +class AstPropClocked final : public AstNode { // A clocked property // Parents: ASSERT|COVER (property) // Children: SENITEM, Properties @@ -8465,7 +8526,7 @@ public: AstNode* propp() const { return op3p(); } // op3 = property }; -class AstNodeCoverOrAssert : public AstNodeStmt { +class AstNodeCoverOrAssert VL_NOT_FINAL : public AstNodeStmt { // Cover or Assert // Parents: {statement list} // Children: expression, report string @@ -8494,7 +8555,7 @@ public: bool immediate() const { return m_immediate; } }; -class AstAssert : public AstNodeCoverOrAssert { +class AstAssert final : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Assert) AstAssert(FileLine* fl, AstNode* propp, AstNode* passsp, AstNode* failsp, bool immediate, @@ -8505,7 +8566,7 @@ public: AstNode* failsp() const { return op3p(); } // op3 = if assertion fails }; -class AstCover : public AstNodeCoverOrAssert { +class AstCover final : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Cover) AstCover(FileLine* fl, AstNode* propp, AstNode* stmtsp, bool immediate, @@ -8516,7 +8577,7 @@ public: virtual bool immediate() const { return false; } }; -class AstRestrict : public AstNodeCoverOrAssert { +class AstRestrict final : public AstNodeCoverOrAssert { public: ASTNODE_NODE_FUNCS(Restrict) AstRestrict(FileLine* fl, AstNode* propp) @@ -8526,7 +8587,7 @@ public: //====================================================================== // Text based nodes -class AstNodeSimpleText : public AstNodeText { +class AstNodeSimpleText VL_NOT_FINAL : public AstNodeText { private: bool m_tracking; // When emit, it's ok to parse the string to do indentation public: @@ -8538,14 +8599,14 @@ public: bool tracking() const { return m_tracking; } }; -class AstText : public AstNodeSimpleText { +class AstText final : public AstNodeSimpleText { public: AstText(FileLine* fl, const string& textp, bool tracking = false) : ASTGEN_SUPER(fl, textp, tracking) {} ASTNODE_NODE_FUNCS(Text) }; -class AstTextBlock : public AstNodeSimpleText { +class AstTextBlock final : public AstNodeSimpleText { private: bool m_commas; // Comma separate emitted children public: @@ -8563,7 +8624,7 @@ public: } }; -class AstScCtor : public AstNodeText { +class AstScCtor final : public AstNodeText { public: AstScCtor(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8572,7 +8633,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstScDtor : public AstNodeText { +class AstScDtor final : public AstNodeText { public: AstScDtor(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8581,7 +8642,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstScHdr : public AstNodeText { +class AstScHdr final : public AstNodeText { public: AstScHdr(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8590,7 +8651,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstScImp : public AstNodeText { +class AstScImp final : public AstNodeText { public: AstScImp(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8599,7 +8660,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstScImpHdr : public AstNodeText { +class AstScImpHdr final : public AstNodeText { public: AstScImpHdr(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8608,7 +8669,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstScInt : public AstNodeText { +class AstScInt final : public AstNodeText { public: AstScInt(FileLine* fl, const string& textp) : ASTGEN_SUPER(fl, textp) {} @@ -8617,7 +8678,7 @@ public: virtual bool isOutputter() const override { return true; } }; -class AstUCStmt : public AstNodeStmt { +class AstUCStmt final : public AstNodeStmt { // User $c statement public: AstUCStmt(FileLine* fl, AstNode* exprsp) @@ -8637,7 +8698,7 @@ public: //====================================================================== // Emitted file nodes -class AstNodeFile : public AstNode { +class AstNodeFile VL_NOT_FINAL : public AstNode { // Emitted Otput file // Parents: NETLIST // Children: AstTextBlock @@ -8660,7 +8721,7 @@ public: //====================================================================== // Emit V nodes -class AstVFile : public AstNodeFile { +class AstVFile final : public AstNodeFile { // Verilog output file // Parents: NETLIST public: @@ -8673,7 +8734,7 @@ public: //====================================================================== // Emit C nodes -class AstCFile : public AstNodeFile { +class AstCFile final : public AstNodeFile { // C++ output file // Parents: NETLIST private: @@ -8696,7 +8757,7 @@ public: void support(bool flag) { m_support = flag; } }; -class AstCFunc : public AstNode { +class AstCFunc final : public AstNode { // C++ function // Parents: MODULE/SCOPE // Children: VAR/statements @@ -8848,7 +8909,7 @@ public: } }; -class AstCCall : public AstNodeCCall { +class AstCCall final : public AstNodeCCall { // C++ function call // Parents: Anything above a statement // Children: Args to the function @@ -8862,7 +8923,7 @@ public: ASTNODE_NODE_FUNCS(CCall) }; -class AstCMethodCall : public AstNodeCCall { +class AstCMethodCall final : public AstNodeCCall { // C++ method call // Parents: Anything above a statement // Children: Args to the function @@ -8883,7 +8944,7 @@ public: void fromp(AstNode* nodep) { setOp1p(nodep); } }; -class AstCNew : public AstNodeCCall { +class AstCNew final : public AstNodeCCall { // C++ new() call // Parents: Anything above an expression // Children: Args to the function @@ -8900,7 +8961,7 @@ public: ASTNODE_NODE_FUNCS(CNew) }; -class AstCReturn : public AstNodeStmt { +class AstCReturn final : public AstNodeStmt { // C++ return from a function // Parents: CFUNC/statement // Children: Math @@ -8917,7 +8978,7 @@ public: AstNode* lhsp() const { return op1p(); } }; -class AstCMath : public AstNodeMath { +class AstCMath final : public AstNodeMath { private: bool m_cleanOut; bool m_pure; // Pure optimizable @@ -8951,7 +9012,7 @@ public: void pure(bool flag) { m_pure = flag; } }; -class AstCReset : public AstNodeStmt { +class AstCReset final : public AstNodeStmt { // Reset variable at startup public: AstCReset(FileLine* fl, AstNode* exprsp) @@ -8966,7 +9027,7 @@ public: AstVarRef* varrefp() const { return VN_CAST(op1p(), VarRef); } // op1 = varref to reset }; -class AstCStmt : public AstNodeStmt { +class AstCStmt final : public AstNodeStmt { // Emit C statement public: AstCStmt(FileLine* fl, AstNode* exprsp) @@ -8986,7 +9047,7 @@ public: AstNode* bodysp() const { return op1p(); } // op1 = expressions to print }; -class AstCUse : public AstNode { +class AstCUse final : public AstNode { // C++ use of a class or #include; indicates need of forward declaration // Parents: NODEMODULE private: @@ -9005,7 +9066,7 @@ public: void useType(VUseType useType) { m_useType = useType; } }; -class AstMTaskBody : public AstNode { +class AstMTaskBody final : public AstNode { // Hold statements for each MTask private: ExecMTask* m_execMTaskp = nullptr; @@ -9025,7 +9086,7 @@ public: virtual void dump(std::ostream& str = std::cout) const override; }; -class AstExecGraph : public AstNode { +class AstExecGraph final : public AstNode { // For parallel execution, this node contains a dependency graph. Each // node in the graph is an ExecMTask, which contains a body for the // mtask, which contains a set of AstActive's, each of which calls a @@ -9049,7 +9110,7 @@ public: void addMTaskBody(AstMTaskBody* bodyp) { addOp1p(bodyp); } }; -class AstSplitPlaceholder : public AstNode { +class AstSplitPlaceholder final : public AstNode { public: // Dummy node used within V3Split; never exists outside of V3Split. explicit AstSplitPlaceholder(FileLine* fl) @@ -9060,7 +9121,7 @@ public: //###################################################################### // Right below top -class AstTypeTable : public AstNode { +class AstTypeTable final : public AstNode { // Container for hash of standard data types // Children: NODEDTYPEs AstVoidDType* m_voidp = nullptr; @@ -9094,7 +9155,7 @@ public: //###################################################################### // Top -class AstNetlist : public AstNode { +class AstNetlist final : public AstNode { // All modules are under this single top node. // Parents: none // Children: MODULEs & CFILEs diff --git a/src/V3Begin.cpp b/src/V3Begin.cpp index cbe3871eb..3f92f8081 100644 --- a/src/V3Begin.cpp +++ b/src/V3Begin.cpp @@ -36,7 +36,7 @@ //###################################################################### -class BeginState { +class BeginState final { private: // NODE STATE // Entire netlist: @@ -45,8 +45,8 @@ private: bool m_anyFuncInBegin = false; public: - BeginState() {} - ~BeginState() {} + BeginState() = default; + ~BeginState() = default; void userMarkChanged(AstNode* nodep) { nodep->user1(true); m_anyFuncInBegin = true; @@ -56,7 +56,7 @@ public: //###################################################################### -class BeginVisitor : public AstNVisitor { +class BeginVisitor final : public AstNVisitor { private: // STATE BeginState* m_statep; // Current global state @@ -242,12 +242,12 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~BeginVisitor() override {} + virtual ~BeginVisitor() override = default; }; //###################################################################### -class BeginRelinkVisitor : public AstNVisitor { +class BeginRelinkVisitor final : public AstNVisitor { // Replace tasks with new pointer private: // NODE STATE @@ -283,7 +283,7 @@ private: public: // CONSTRUCTORS BeginRelinkVisitor(AstNetlist* nodep, BeginState*) { iterate(nodep); } - virtual ~BeginRelinkVisitor() override {} + virtual ~BeginRelinkVisitor() override = default; }; //###################################################################### diff --git a/src/V3Begin.h b/src/V3Begin.h index 9b360c35c..fcd0a33f9 100644 --- a/src/V3Begin.h +++ b/src/V3Begin.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Begin { +class V3Begin final { public: static void debeginAll(AstNetlist* nodep); }; diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp index 2aa42a9b3..34901d20e 100644 --- a/src/V3Branch.cpp +++ b/src/V3Branch.cpp @@ -35,7 +35,7 @@ //###################################################################### // Branch state, as a visitor of each AstNode -class BranchVisitor : public AstNVisitor { +class BranchVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -118,7 +118,7 @@ public: iterateChildren(nodep); calc_tasks(); } - virtual ~BranchVisitor() override {} + virtual ~BranchVisitor() override = default; }; //###################################################################### diff --git a/src/V3Branch.h b/src/V3Branch.h index 9a82514a7..d8ebed0f5 100644 --- a/src/V3Branch.h +++ b/src/V3Branch.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Branch { +class V3Branch final { public: // CONSTRUCTORS static void branchAll(AstNetlist* nodep); diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp index f017c7fe5..7ca71dfff 100644 --- a/src/V3Broken.cpp +++ b/src/V3Broken.cpp @@ -36,7 +36,7 @@ //###################################################################### -class BrokenTable : public AstNVisitor { +class BrokenTable VL_NOT_FINAL : public AstNVisitor { // Table of brokenExists node pointers private: // MEMBERS @@ -190,8 +190,8 @@ public: } // CONSTRUCTORS - BrokenTable() {} - virtual ~BrokenTable() override {} + BrokenTable() = default; + virtual ~BrokenTable() override = default; }; BrokenTable::NodeMap BrokenTable::s_nodes; @@ -211,7 +211,7 @@ bool AstNode::brokeExistsBelow() const { //###################################################################### -class BrokenMarkVisitor : public AstNVisitor { +class BrokenMarkVisitor final : public AstNVisitor { // Mark every node in the tree private: // NODE STATE @@ -231,13 +231,15 @@ private: public: // CONSTRUCTORS explicit BrokenMarkVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~BrokenMarkVisitor() override {} + virtual ~BrokenMarkVisitor() override = default; }; //###################################################################### // Broken state, as a visitor of each AstNode -class BrokenCheckVisitor : public AstNVisitor { +class BrokenCheckVisitor final : public AstNVisitor { + bool m_inScope = false; // Under AstScope + private: static void checkWidthMin(const AstNode* nodep) { UASSERT_OBJ(nodep->width() == nodep->widthMin() @@ -278,6 +280,22 @@ private: && !VN_CAST(nodep->lhsp(), NodeVarRef)->access().isWriteOrRW()), nodep, "Assignment LHS is not an lvalue"); } + virtual void visit(AstScope* nodep) override { + VL_RESTORER(m_inScope); + { + m_inScope = true; + processAndIterate(nodep); + } + } + virtual void visit(AstNodeVarRef* nodep) override { + processAndIterate(nodep); + // m_inScope because some Vars have initial variable references without scopes + // This might false fire with some debug flags, as not certain we don't have temporary + // clear varScopep's during some an infrequent dump just before we re-LinkDot. + UASSERT_OBJ( + !(v3Global.assertScoped() && m_inScope && nodep->varp() && !nodep->varScopep()), nodep, + "VarRef missing VarScope pointer"); + } virtual void visit(AstNode* nodep) override { // Process not just iterate processAndIterate(nodep); @@ -286,7 +304,7 @@ private: public: // CONSTRUCTORS explicit BrokenCheckVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~BrokenCheckVisitor() override {} + virtual ~BrokenCheckVisitor() override = default; }; //###################################################################### diff --git a/src/V3Broken.h b/src/V3Broken.h index 104765f03..ee7d718f6 100644 --- a/src/V3Broken.h +++ b/src/V3Broken.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Broken { +class V3Broken final { public: static void brokenAll(AstNetlist* nodep); static void addNewed(AstNode* nodep); diff --git a/src/V3CCtors.cpp b/src/V3CCtors.cpp index 94a0b1306..65b98c3b1 100644 --- a/src/V3CCtors.cpp +++ b/src/V3CCtors.cpp @@ -34,7 +34,7 @@ #include #include -class V3CCtorsVisitor { +class V3CCtorsVisitor final { private: string m_basename; string m_argsp; @@ -42,8 +42,8 @@ private: AstNodeModule* m_modp; // Current module AstCFunc* m_tlFuncp; // Top level function being built AstCFunc* m_funcp; // Current function - int m_numStmts; // Number of statements output - int m_funcNum; // Function number being built + int m_numStmts = 0; // Number of statements output + int m_funcNum = 0; // Function number being built public: void add(AstNode* nodep) { @@ -76,8 +76,6 @@ public: m_argsp = argsp; m_callargsp = callargsp; m_modp = nodep; - m_numStmts = 0; - m_funcNum = 0; m_tlFuncp = new AstCFunc(nodep->fileline(), basename, nullptr, "void"); m_tlFuncp->declPrivate(true); m_tlFuncp->isStatic(false); @@ -87,7 +85,7 @@ public: m_funcp = m_tlFuncp; m_modp->addStmtp(m_tlFuncp); } - ~V3CCtorsVisitor() {} + ~V3CCtorsVisitor() = default; private: VL_UNCOPYABLE(V3CCtorsVisitor); diff --git a/src/V3CCtors.h b/src/V3CCtors.h index 1592d19c9..533a0e819 100644 --- a/src/V3CCtors.h +++ b/src/V3CCtors.h @@ -25,7 +25,7 @@ //============================================================================ -class V3CCtors { +class V3CCtors final { public: static void cctorsAll(); diff --git a/src/V3CUse.cpp b/src/V3CUse.cpp index 698378314..f9c835462 100644 --- a/src/V3CUse.cpp +++ b/src/V3CUse.cpp @@ -36,7 +36,7 @@ //###################################################################### -class CUseState { +class CUseState final { private: // MEMBERS AstNodeModule* m_modInsertp; // Current module to insert AstCUse under @@ -68,14 +68,14 @@ public: // CONSTRUCTORS explicit CUseState(AstNodeModule* nodep) : m_modInsertp{nodep} {} - virtual ~CUseState() {} + virtual ~CUseState() = default; VL_UNCOPYABLE(CUseState); }; // Visit within a module all nodes and data types they reference, finding // any classes so we can make sure they are defined when Verilated code // compiles -class CUseDTypeVisitor : public AstNVisitor { +class CUseDTypeVisitor final : public AstNVisitor { // MEMBERS CUseState& m_stater; // State for inserter bool m_impOnly = false; // In details needed only for implementation @@ -84,7 +84,7 @@ class CUseDTypeVisitor : public AstNVisitor { if (nodep->user2SetOnce()) return; // Process once if (!m_impOnly) m_stater.newUse(nodep, VUseType::INT_FWD_CLASS, nodep->classp()->name()); // No class.h, it's inside the class package's h file - m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->packagep()->name()); + m_stater.newUse(nodep, VUseType::IMP_INCLUDE, nodep->classp()->classOrPackagep()->name()); // Need to include extends() when we implement, but no need for pointers to know VL_RESTORER(m_impOnly); { @@ -109,11 +109,11 @@ public: : m_stater(stater) { // Need () or GCC 4.8 false warning iterate(nodep); } - virtual ~CUseDTypeVisitor() override {} + virtual ~CUseDTypeVisitor() override = default; VL_UNCOPYABLE(CUseDTypeVisitor); }; -class CUseVisitor : public AstNVisitor { +class CUseVisitor final : public AstNVisitor { // MEMBERS CUseState m_state; // Inserter state @@ -219,7 +219,7 @@ public: : m_state{nodep} { iterate(nodep); } - virtual ~CUseVisitor() override {} + virtual ~CUseVisitor() override = default; VL_UNCOPYABLE(CUseVisitor); }; diff --git a/src/V3CUse.h b/src/V3CUse.h index ffae09a46..d3d0a44af 100644 --- a/src/V3CUse.h +++ b/src/V3CUse.h @@ -25,7 +25,7 @@ //============================================================================ -class V3CUse { +class V3CUse final { public: static void cUseAll(); }; diff --git a/src/V3Case.cpp b/src/V3Case.cpp index a9a0a3511..06ece071c 100644 --- a/src/V3Case.cpp +++ b/src/V3Case.cpp @@ -50,7 +50,7 @@ //###################################################################### -class CaseLintVisitor : public AstNVisitor { +class CaseLintVisitor final : public AstNVisitor { private: AstNodeCase* m_caseExprp = nullptr; // Under a CASE value node, if so the relevant case statement @@ -111,13 +111,13 @@ private: public: // CONSTRUCTORS explicit CaseLintVisitor(AstNodeCase* nodep) { iterate(nodep); } - virtual ~CaseLintVisitor() override {} + virtual ~CaseLintVisitor() override = default; }; //###################################################################### // Case state, as a visitor of each AstNode -class CaseVisitor : public AstNVisitor { +class CaseVisitor final : public AstNVisitor { private: // NODE STATE // Cleared each Case @@ -133,7 +133,7 @@ private: int m_caseItems = 0; // Number of caseItem unique values bool m_caseNoOverlapsAllCovered = false; // Proven to be synopsys parallel_case compliant // For each possible value, the case branch we need - AstNode* m_valueItem[1 << CASE_OVERLAP_WIDTH]; + std::array m_valueItem; // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -318,7 +318,7 @@ private: itemp = VN_CAST(itemp->nextp(), CaseItem)) { if (!itemp->condsp()) { // Default clause. Just make true, we'll optimize it away later - itemp->condsp(new AstConst(itemp->fileline(), AstConst::LogicTrue())); + itemp->condsp(new AstConst(itemp->fileline(), AstConst::BitTrue())); hadDefault = true; } else { // Expressioned clause @@ -336,7 +336,7 @@ private: VL_DANGLING(iconstp); // For simplicity, make expression that is not equal, and let later // optimizations remove it - condp = new AstConst(itemp->fileline(), AstConst::LogicFalse()); + condp = new AstConst(itemp->fileline(), AstConst::BitFalse()); } else if (AstInsideRange* irangep = VN_CAST(icondp, InsideRange)) { // Similar logic in V3Width::visit(AstInside) condp = irangep->newAndFromInside(cexprp, irangep->lhsp()->unlinkFrBack(), @@ -375,9 +375,8 @@ private: if (!hadDefault) { // If there was no default, add a empty one, this greatly simplifies below code // and constant propagation will just eliminate it for us later. - nodep->addItemsp( - new AstCaseItem(nodep->fileline(), - new AstConst(nodep->fileline(), AstConst::LogicTrue()), nullptr)); + nodep->addItemsp(new AstCaseItem( + nodep->fileline(), new AstConst(nodep->fileline(), AstConst::BitTrue()), nullptr)); } if (debug() >= 9) nodep->dumpTree(cout, " _comp_COND: "); // Now build the IF statement tree @@ -419,7 +418,7 @@ private: VL_DANGLING(ifexprp); if (depth == CASE_ENCODER_GROUP_DEPTH) { // End of group - can skip the condition VL_DO_DANGLING(itemexprp->deleteTree(), itemexprp); - itemexprp = new AstConst(itemp->fileline(), AstConst::LogicTrue()); + itemexprp = new AstConst(itemp->fileline(), AstConst::BitTrue()); } AstIf* newp = new AstIf(itemp->fileline(), itemexprp, istmtsp, nullptr); if (itemnextp) { diff --git a/src/V3Case.h b/src/V3Case.h index 1e4d916b6..35d4abbf7 100644 --- a/src/V3Case.h +++ b/src/V3Case.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Case { +class V3Case final { public: static void caseAll(AstNetlist* nodep); static void caseLint(AstNodeCase* nodep); diff --git a/src/V3Cast.cpp b/src/V3Cast.cpp index faa0eedad..355516acb 100644 --- a/src/V3Cast.cpp +++ b/src/V3Cast.cpp @@ -49,7 +49,7 @@ //###################################################################### // Cast state, as a visitor of each AstNode -class CastVisitor : public AstNVisitor { +class CastVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -193,7 +193,7 @@ private: public: // CONSTRUCTORS explicit CastVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CastVisitor() override {} + virtual ~CastVisitor() override = default; }; //###################################################################### diff --git a/src/V3Cast.h b/src/V3Cast.h index d18fc641b..ab9ad4dc0 100644 --- a/src/V3Cast.h +++ b/src/V3Cast.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Cast { +class V3Cast final { public: static void castAll(AstNetlist* nodep); }; diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp index 60e85be33..dfb70a833 100644 --- a/src/V3Cdc.cpp +++ b/src/V3Cdc.cpp @@ -41,7 +41,7 @@ constexpr int CDC_WEIGHT_ASYNC = 0x1000; // Weight for edges that feed async lo //###################################################################### -class CdcBaseVisitor : public AstNVisitor { +class CdcBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: VL_DEBUG_FUNC; // Declare debug() }; @@ -49,7 +49,7 @@ public: //###################################################################### // Graph support classes -class CdcEitherVertex : public V3GraphVertex { +class CdcEitherVertex VL_NOT_FINAL : public V3GraphVertex { AstScope* m_scopep; AstNode* m_nodep; AstSenTree* m_srcDomainp = nullptr; @@ -66,7 +66,7 @@ public: , m_srcDomainSet{false} , m_dstDomainSet{false} , m_asyncPath{false} {} - virtual ~CdcEitherVertex() override {} + virtual ~CdcEitherVertex() override = default; // ACCESSORS virtual FileLine* fileline() const override { return nodep()->fileline(); } AstScope* scopep() const { return m_scopep; } @@ -83,7 +83,7 @@ public: void asyncPath(bool flag) { m_asyncPath = flag; } }; -class CdcVarVertex : public CdcEitherVertex { +class CdcVarVertex final : public CdcEitherVertex { AstVarScope* m_varScp; int m_cntAsyncRst = 0; bool m_fromFlop = false; @@ -92,7 +92,7 @@ public: CdcVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : CdcEitherVertex{graphp, scopep, varScp} , m_varScp{varScp} {} - virtual ~CdcVarVertex() override {} + virtual ~CdcVarVertex() override = default; // ACCESSORS AstVarScope* varScp() const { return m_varScp; } virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } @@ -105,7 +105,7 @@ public: void fromFlop(bool flag) { m_fromFlop = flag; } }; -class CdcLogicVertex : public CdcEitherVertex { +class CdcLogicVertex final : public CdcEitherVertex { bool m_hazard : 1; bool m_isFlop : 1; @@ -117,7 +117,7 @@ public: srcDomainp(sensenodep); dstDomainp(sensenodep); } - virtual ~CdcLogicVertex() override {} + virtual ~CdcLogicVertex() override = default; // ACCESSORS virtual string name() const override { return (cvtToHex(nodep()) + "@" + scopep()->prettyName()); @@ -135,7 +135,7 @@ public: //###################################################################### -class CdcDumpVisitor : public CdcBaseVisitor { +class CdcDumpVisitor final : public CdcBaseVisitor { private: // NODE STATE // Entire netlist: @@ -150,7 +150,7 @@ private: } else { *m_ofp << " "; } - *m_ofp << nodep->prettyTypeName() << " " << endl; + *m_ofp << nodep->prettyTypeName() << "\n"; string lastPrefix = m_prefix; m_prefix = lastPrefix + "1:"; iterateAndNextNull(nodep->op1p()); @@ -170,12 +170,12 @@ public: , m_prefix{prefix} { iterate(nodep); } - virtual ~CdcDumpVisitor() override {} + virtual ~CdcDumpVisitor() override = default; }; //###################################################################### -class CdcWidthVisitor : public CdcBaseVisitor { +class CdcWidthVisitor final : public CdcBaseVisitor { private: int m_maxLineno = 0; size_t m_maxFilenameLen = 0; @@ -194,7 +194,7 @@ private: public: // CONSTRUCTORS explicit CdcWidthVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~CdcWidthVisitor() override {} + virtual ~CdcWidthVisitor() override = default; // ACCESSORS int maxWidth() const { size_t width = 1; @@ -209,7 +209,7 @@ public: //###################################################################### // Cdc class functions -class CdcVisitor : public CdcBaseVisitor { +class CdcVisitor final : public CdcBaseVisitor { private: // NODE STATE // Entire netlist: @@ -292,7 +292,7 @@ private: told_file = true; std::cerr << V3Error::msgPrefix() << " See details in " << m_ofFilename << endl; } - *m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << endl; + *m_ofp << "%Warning-" << code.ascii() << ": " << nodep->fileline() << " " << msg << '\n'; } void setNodeHazard(AstNode* nodep) { @@ -462,7 +462,7 @@ private: string front = pad(filelineWidth(), nodep->fileline()->ascii() + ":") + " " + prefix + " +- "; if (VN_IS(nodep, VarScope)) { - *m_ofp << front << "Variable: " << nodep->prettyName() << endl; + *m_ofp << front << "Variable: " << nodep->prettyName() << '\n'; } else { V3EmitV::verilogPrefixedTree(nodep, *m_ofp, prefix + " +- ", filelineWidth(), vertexp->srcDomainp(), true); @@ -509,7 +509,7 @@ private: string filename = v3Global.opt.makeDir() + "/" + v3Global.opt.prefix() + "__cdc_edges.txt"; const std::unique_ptr ofp(V3File::new_ofstream(filename)); if (ofp->fail()) v3fatal("Can't write " << filename); - *ofp << "Edge Report for " << v3Global.opt.prefix() << endl; + *ofp << "Edge Report for " << v3Global.opt.prefix() << '\n'; std::deque report; // Sort output by name for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp = itp->verticesNextp()) { @@ -536,7 +536,7 @@ private: V3EmitV::verilogForTree(vvertexp->dstDomainp(), os); } os << std::setw(0); - os << endl; + os << '\n'; report.push_back(os.str()); } } @@ -732,7 +732,7 @@ public: m_ofp = V3File::new_ofstream(filename); if (m_ofp->fail()) v3fatal("Can't write " << filename); m_ofFilename = filename; - *m_ofp << "CDC Report for " << v3Global.opt.prefix() << endl; + *m_ofp << "CDC Report for " << v3Global.opt.prefix() << '\n'; *m_ofp << "Each dump below traces logic from inputs/source flops to destination flop(s).\n"; *m_ofp << "First source logic is listed, then a variable that logic generates,\n"; @@ -745,7 +745,7 @@ public: if (false) { *m_ofp << "\nDBG-test-dumper\n"; V3EmitV::verilogPrefixedTree(nodep, *m_ofp, "DBG ", 40, nullptr, true); - *m_ofp << endl; + *m_ofp << '\n'; } } virtual ~CdcVisitor() override { diff --git a/src/V3Cdc.h b/src/V3Cdc.h index cd6b33f30..9d59849f1 100644 --- a/src/V3Cdc.h +++ b/src/V3Cdc.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Cdc { +class V3Cdc final { public: static void cdcAll(AstNetlist* nodep); }; diff --git a/src/V3Changed.cpp b/src/V3Changed.cpp index 922d0686c..dbe1905b7 100644 --- a/src/V3Changed.cpp +++ b/src/V3Changed.cpp @@ -38,7 +38,7 @@ //###################################################################### -class ChangedState { +class ChangedState final { public: // STATE AstNodeModule* m_topModp = nullptr; // Top module @@ -48,8 +48,8 @@ public: int m_numStmts = 0; // Number of statements added to m_chgFuncp int m_funcNum = 0; // Number of change functions emitted - ChangedState() {} - ~ChangedState() {} + ChangedState() = default; + ~ChangedState() = default; void maybeCreateChgFuncp() { // Don't create an extra function call if splitting is disabled @@ -94,7 +94,7 @@ public: //###################################################################### // Utility visitor to find elements to be compared -class ChangedInsertVisitor : public AstNVisitor { +class ChangedInsertVisitor final : public AstNVisitor { private: // STATE ChangedState* m_statep; // Shared state across visitors @@ -117,10 +117,9 @@ private: "Unsupported: Can't detect more than " << cvtToStr(DETECTARRAY_MAX_INDEXES) << " array indexes (probably with UNOPTFLAT warning suppressed): " - << m_vscp->prettyName() << endl + << m_vscp->prettyName() << '\n' << m_vscp->warnMore() - << "... Could recompile with DETECTARRAY_MAX_INDEXES increased" - << endl); + << "... Could recompile with DETECTARRAY_MAX_INDEXES increased"); return; } m_statep->maybeCreateChgFuncp(); @@ -208,14 +207,14 @@ public: m_newLvEqnp->deleteTree(); m_newRvEqnp->deleteTree(); } - virtual ~ChangedInsertVisitor() override {} + virtual ~ChangedInsertVisitor() override = default; VL_UNCOPYABLE(ChangedInsertVisitor); }; //###################################################################### // Changed state, as a visitor of each AstNode -class ChangedVisitor : public AstNVisitor { +class ChangedVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -280,7 +279,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~ChangedVisitor() override {} + virtual ~ChangedVisitor() override = default; }; //###################################################################### diff --git a/src/V3Changed.h b/src/V3Changed.h index 311a0c371..79c56cb27 100644 --- a/src/V3Changed.h +++ b/src/V3Changed.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Changed { +class V3Changed final { public: static void changedAll(AstNetlist* nodep); }; diff --git a/src/V3Class.cpp b/src/V3Class.cpp index ebde82354..83f99724a 100644 --- a/src/V3Class.cpp +++ b/src/V3Class.cpp @@ -29,7 +29,7 @@ //###################################################################### -class ClassVisitor : public AstNVisitor { +class ClassVisitor final : public AstNVisitor { private: // MEMBERS AstUser1InUse m_inuser1; @@ -56,7 +56,7 @@ private: // Note origName is the same as the class origName so errors look correct AstClassPackage* packagep = new AstClassPackage(nodep->fileline(), nodep->origName()); packagep->name(nodep->name() + "__Vclpkg"); - nodep->packagep(packagep); + nodep->classOrPackagep(packagep); packagep->classp(nodep); v3Global.rootp()->addModulep(packagep); // Add package to hierarchy @@ -87,7 +87,8 @@ private: iterateChildren(nodep); } } - virtual void visit(AstPackage* nodep) override { + virtual void visit(AstNodeModule* nodep) override { + // Visit for NodeModules that are not AstClass (AstClass is-a AstNodeModule) VL_RESTORER(m_prefix); { m_prefix = nodep->name() + "__03a__03a"; // :: @@ -99,7 +100,7 @@ private: iterateChildren(nodep); // Don't move now, or wouldn't keep interating the class // TODO move class statics too - if (m_ftaskp && m_ftaskp->lifetime().isStatic()) { + if (m_packageScopep && m_ftaskp && m_ftaskp->lifetime().isStatic()) { m_moves.push_back(make_pair(nodep, m_packageScopep)); } } @@ -114,7 +115,7 @@ private: { m_ftaskp = nodep; iterateChildren(nodep); - if (nodep->lifetime().isStatic()) { + if (m_packageScopep && nodep->lifetime().isStatic()) { m_moves.push_back(make_pair(nodep, m_packageScopep)); } } diff --git a/src/V3Class.h b/src/V3Class.h index f93be9a71..a436bd9ed 100644 --- a/src/V3Class.h +++ b/src/V3Class.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Class { +class V3Class final { public: static void classAll(AstNetlist* nodep); }; diff --git a/src/V3Clean.cpp b/src/V3Clean.cpp index 3dcd7fc1e..458e366fe 100644 --- a/src/V3Clean.cpp +++ b/src/V3Clean.cpp @@ -35,7 +35,7 @@ //###################################################################### // Clean state, as a visitor of each AstNode -class CleanVisitor : public AstNVisitor { +class CleanVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -305,7 +305,7 @@ private: public: // CONSTRUCTORS explicit CleanVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~CleanVisitor() override {} + virtual ~CleanVisitor() override = default; }; //###################################################################### diff --git a/src/V3Clean.h b/src/V3Clean.h index 76b212a80..76223d2ee 100644 --- a/src/V3Clean.h +++ b/src/V3Clean.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Clean { +class V3Clean final { public: static void cleanAll(AstNetlist* nodep); }; diff --git a/src/V3Clock.cpp b/src/V3Clock.cpp index 1c39a0c9b..e4a5da09f 100644 --- a/src/V3Clock.cpp +++ b/src/V3Clock.cpp @@ -40,7 +40,7 @@ //###################################################################### // Clock state, as a visitor of each AstNode -class ClockVisitor : public AstNVisitor { +class ClockVisitor final : public AstNVisitor { private: // NODE STATE // Cleared each Module: @@ -293,7 +293,7 @@ private: } m_scopep = nullptr; } - virtual void visit(AstAlways* nodep) override { + virtual void visit(AstNodeProcedure* nodep) override { AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true); nodep->replaceWith(cmtp); if (AstNode* stmtsp = nodep->bodysp()) { @@ -311,6 +311,15 @@ private: } VL_DO_DANGLING(nodep->deleteTree(), nodep); } + virtual void visit(AstAlwaysPostponed* nodep) override { + AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true); + nodep->replaceWith(cmtp); + if (AstNode* stmtsp = nodep->bodysp()) { + stmtsp->unlinkFrBackWithNext(); + cmtp->addNextHere(stmtsp); + } + VL_DO_DANGLING(nodep->deleteTree(), nodep); + } virtual void visit(AstCoverToggle* nodep) override { // nodep->dumpTree(cout, "ct:"); // COVERTOGGLE(INC, ORIG, CHANGE) -> @@ -328,15 +337,6 @@ private: nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } - virtual void visit(AstInitial* nodep) override { - AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName(), true); - nodep->replaceWith(cmtp); - if (AstNode* stmtsp = nodep->bodysp()) { - stmtsp->unlinkFrBackWithNext(); - cmtp->addNextHere(stmtsp); - } - VL_DO_DANGLING(nodep->deleteTree(), nodep); - } virtual void visit(AstCFunc* nodep) override { iterateChildren(nodep); // Link to global function @@ -454,7 +454,7 @@ public: // easily without iterating through the tree. nodep->evalp(m_evalFuncp); } - virtual ~ClockVisitor() override {} + virtual ~ClockVisitor() override = default; }; //###################################################################### diff --git a/src/V3Clock.h b/src/V3Clock.h index c2301a8e3..de0ae9f2f 100644 --- a/src/V3Clock.h +++ b/src/V3Clock.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Clock { +class V3Clock final { public: static void clockAll(AstNetlist* nodep); }; diff --git a/src/V3Combine.cpp b/src/V3Combine.cpp index ad2bcc690..795f1a8b1 100644 --- a/src/V3Combine.cpp +++ b/src/V3Combine.cpp @@ -51,19 +51,19 @@ constexpr int COMBINE_MIN_STATEMENTS = 50; // Min # of statements to be worth m //###################################################################### -class CombBaseVisitor : public AstNVisitor { +class CombBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: // STATE // METHODS - virtual ~CombBaseVisitor() override {} + virtual ~CombBaseVisitor() override = default; VL_DEBUG_FUNC; // Declare debug() }; //###################################################################### // Combine replacement function -class CombCallVisitor : CombBaseVisitor { +class CombCallVisitor final : CombBaseVisitor { // Find all CCALLS of each CFUNC, so that we can later rename them private: // NODE STATE @@ -131,15 +131,15 @@ private: public: // CONSTRUCTORS - CombCallVisitor() {} - virtual ~CombCallVisitor() override {} + CombCallVisitor() = default; + virtual ~CombCallVisitor() override = default; void main(AstNetlist* nodep) { iterate(nodep); } }; //###################################################################### // Combine marking function -class CombMarkVisitor : CombBaseVisitor { +class CombMarkVisitor final : CombBaseVisitor { // Mark all nodes under specified one. private: // OUTPUT: @@ -153,13 +153,13 @@ private: public: // CONSTRUCTORS explicit CombMarkVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~CombMarkVisitor() override {} + virtual ~CombMarkVisitor() override = default; }; //###################################################################### // Combine state, as a visitor of each AstNode -class CombineVisitor : CombBaseVisitor { +class CombineVisitor final : CombBaseVisitor { private: // NODE STATE // Entire netlist: diff --git a/src/V3Combine.h b/src/V3Combine.h index 39a223fe8..aee53c2ae 100644 --- a/src/V3Combine.h +++ b/src/V3Combine.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Combine { +class V3Combine final { public: static void combineAll(AstNetlist* nodep); }; diff --git a/src/V3Config.cpp b/src/V3Config.cpp index 7a29b21fd..f552b766a 100644 --- a/src/V3Config.cpp +++ b/src/V3Config.cpp @@ -38,8 +38,8 @@ template class V3ConfigWildcardResolver { Map m_mapWildcard; // Wildcard strings to entities Map m_mapResolved; // Resolved strings to converged entities public: - V3ConfigWildcardResolver() {} - ~V3ConfigWildcardResolver() {} + V3ConfigWildcardResolver() = default; + ~V3ConfigWildcardResolver() = default; /// Update into maps from other void update(const V3ConfigWildcardResolver& other) { @@ -82,7 +82,7 @@ public: }; // Only public_flat_rw has the sensitity tree -class V3ConfigVarAttr { +class V3ConfigVarAttr final { public: AstAttrType m_type; // Type of attribute AstSenTree* m_sentreep; // Sensitivity tree for public_flat_rw @@ -92,7 +92,7 @@ public: }; // Overload vector with the required update function and to apply all entries -class V3ConfigVar : public std::vector { +class V3ConfigVar final : public std::vector { public: // Update from other by copying all attributes void update(const V3ConfigVar& node) { @@ -116,14 +116,14 @@ typedef V3ConfigWildcardResolver V3ConfigVarResolver; //###################################################################### // Function or task: Have variables and properties -class V3ConfigFTask { +class V3ConfigFTask final { V3ConfigVarResolver m_vars; // Variables in function/task bool m_isolate = false; // Isolate function return bool m_noinline = false; // Don't inline function/task bool m_public = false; // Public function/task public: - V3ConfigFTask() {} + V3ConfigFTask() = default; void update(const V3ConfigFTask& f) { // Don't overwrite true with false if (f.m_isolate) m_isolate = true; @@ -153,7 +153,7 @@ typedef V3ConfigWildcardResolver V3ConfigFTaskResolver; //###################################################################### // Modules have tasks, variables, named blocks and properties -class V3ConfigModule { +class V3ConfigModule final { typedef std::unordered_set StringSet; typedef std::set PragmaSet; @@ -165,7 +165,7 @@ class V3ConfigModule { bool m_inlineValue = false; // The inline value (on/off) public: - V3ConfigModule() {} + V3ConfigModule() = default; void update(const V3ConfigModule& m) { m_tasks.update(m.m_tasks); @@ -224,7 +224,7 @@ typedef V3ConfigWildcardResolver V3ConfigModuleResolver; // - Line attributes: Attributes attached to lines // lint/coverage/tracing on/off -class V3ConfigIgnoresLine { +class V3ConfigIgnoresLine final { public: int m_lineno; // Line number to make change at V3ErrorCode m_code; // Error code @@ -233,8 +233,8 @@ public: : m_lineno{lineno} , m_code{code} , m_on{on} {} - ~V3ConfigIgnoresLine() {} - inline bool operator<(const V3ConfigIgnoresLine& rh) const { + ~V3ConfigIgnoresLine() = default; + bool operator<(const V3ConfigIgnoresLine& rh) const { if (m_lineno < rh.m_lineno) return true; if (m_lineno > rh.m_lineno) return false; if (m_code < rh.m_code) return true; @@ -253,7 +253,7 @@ std::ostream& operator<<(std::ostream& os, const V3ConfigIgnoresLine& rhs) { typedef std::bitset V3ConfigLineAttribute; // File entity -class V3ConfigFile { +class V3ConfigFile final { typedef std::map LineAttrMap; // Map line->bitset of attributes typedef std::multiset IgnLines; // list of {line,code,on} typedef std::pair WaiverSetting; // Waive code if string matches @@ -347,16 +347,16 @@ typedef V3ConfigWildcardResolver V3ConfigFileResolver; //###################################################################### // Resolve modules and files in the design -class V3ConfigResolver { +class V3ConfigResolver final { V3ConfigModuleResolver m_modules; // Access to module names (with wildcards) V3ConfigFileResolver m_files; // Access to file names (with wildcards) static V3ConfigResolver s_singleton; // Singleton (not via local static, as that's slow) - V3ConfigResolver() {} - ~V3ConfigResolver() {} + V3ConfigResolver() = default; + ~V3ConfigResolver() = default; public: - inline static V3ConfigResolver& s() { return s_singleton; } + static V3ConfigResolver& s() { return s_singleton; } V3ConfigModuleResolver& modules() { return m_modules; } V3ConfigFileResolver& files() { return m_files; } @@ -405,7 +405,7 @@ void V3Config::addInline(FileLine* fl, const string& module, const string& ftask V3ConfigResolver::s().modules().at(module).setInline(on); } else { if (!on) { - fl->v3error("no_inline not supported for tasks" << endl); + fl->v3error("no_inline not supported for tasks"); } else { V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setNoInline(on); } @@ -416,15 +416,14 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas const string& var, AstAttrType attr, AstSenTree* sensep) { // Semantics: sensep only if public_flat_rw if ((attr != AstAttrType::VAR_PUBLIC_FLAT_RW) && sensep) { - sensep->v3error("sensitivity not expected for attribute" << endl); + sensep->v3error("sensitivity not expected for attribute"); return; } // Semantics: Most of the attributes operate on signals if (var.empty()) { if (attr == AstAttrType::VAR_ISOLATE_ASSIGNMENTS) { if (ftask.empty()) { - fl->v3error("isolate_assignments only applies to signals or functions/tasks" - << endl); + fl->v3error("isolate_assignments only applies to signals or functions/tasks"); } else { V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setIsolate(true); } @@ -437,7 +436,7 @@ void V3Config::addVarAttr(FileLine* fl, const string& module, const string& ftas V3ConfigResolver::s().modules().at(module).ftasks().at(ftask).setPublic(true); } } else { - fl->v3error("missing -signal" << endl); + fl->v3error("missing -signal"); } } else { V3ConfigModule& mod = V3ConfigResolver::s().modules().at(module); diff --git a/src/V3Config.h b/src/V3Config.h index cc3a3a42f..dcf01427f 100644 --- a/src/V3Config.h +++ b/src/V3Config.h @@ -26,7 +26,7 @@ //###################################################################### -class V3Config { +class V3Config final { public: static void addCaseFull(const string& file, int lineno); static void addCaseParallel(const string& file, int lineno); diff --git a/src/V3Const.cpp b/src/V3Const.cpp index 8f71622b6..1d0dccd64 100644 --- a/src/V3Const.cpp +++ b/src/V3Const.cpp @@ -36,7 +36,7 @@ //###################################################################### // Utilities -class ConstVarMarkVisitor : public AstNVisitor { +class ConstVarMarkVisitor final : public AstNVisitor { // NODE STATE // AstVar::user4p -> bool, Var marked, 0=not set yet private: @@ -52,10 +52,10 @@ public: AstNode::user4ClearTree(); // Check marked InUse before we're called iterate(nodep); } - virtual ~ConstVarMarkVisitor() override {} + virtual ~ConstVarMarkVisitor() override = default; }; -class ConstVarFindVisitor : public AstNVisitor { +class ConstVarFindVisitor final : public AstNVisitor { // NODE STATE // AstVar::user4p -> bool, input from ConstVarMarkVisitor // MEMBERS @@ -71,7 +71,7 @@ private: public: // CONSTRUCTORS explicit ConstVarFindVisitor(AstNode* nodep) { iterateAndNextNull(nodep); } - virtual ~ConstVarFindVisitor() override {} + virtual ~ConstVarFindVisitor() override = default; // METHODS bool found() const { return m_found; } }; @@ -79,7 +79,7 @@ public: //###################################################################### // Const state, as a visitor of each AstNode -class ConstVisitor : public AstNVisitor { +class ConstVisitor final : public AstNVisitor { private: // NODE STATE // ** only when m_warn/m_doExpensive is set. If state is needed other times, @@ -1262,7 +1262,7 @@ private: AstNode* errorp = simvis.whyNotNodep(); if (!errorp) errorp = nodep; nodep->v3error("Expecting expression to be constant, but can't determine constant for " - << nodep->prettyTypeName() << endl + << nodep->prettyTypeName() << '\n' << errorp->warnOther() << "... Location of non-constant " << errorp->prettyTypeName() << ": " << simvis.whyNotMessage()); VL_DO_DANGLING(replaceZero(nodep), nodep); @@ -1730,7 +1730,7 @@ private: } struct SenItemCmp { - inline bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const { + bool operator()(const AstSenItem* lhsp, const AstSenItem* rhsp) const { if (lhsp->type() < rhsp->type()) return true; if (lhsp->type() > rhsp->type()) return false; // Looks visually better if we keep sorted by name @@ -1930,8 +1930,9 @@ private: nodep->replaceWith(ifp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else if (ifSameAssign(nodep)) { - UINFO(4, "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})" - << endl); + UINFO( + 4, + "IF({a}) ASSIGN({b},{c}) else ASSIGN({b},{d}) => ASSIGN({b}, {a}?{c}:{d})\n"); AstNodeAssign* ifp = VN_CAST(nodep->ifsp(), NodeAssign); AstNodeAssign* elsep = VN_CAST(nodep->elsesp(), NodeAssign); ifp->unlinkFrBack(); @@ -2563,7 +2564,7 @@ public: } // clang-format on } - virtual ~ConstVisitor() override {} + virtual ~ConstVisitor() override = default; AstNode* mainAcceptEdit(AstNode* nodep) { // Operate starting at a random place return iterateSubtreeReturnEdits(nodep); diff --git a/src/V3Const.h b/src/V3Const.h index a7a45aca6..f5b8732f3 100644 --- a/src/V3Const.h +++ b/src/V3Const.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Const { +class V3Const final { public: static AstNode* constifyParamsEdit(AstNode* nodep); static AstNode* constifyGenerateParamsEdit(AstNode* nodep); diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp index a216b385c..3a4c2f3d9 100644 --- a/src/V3Coverage.cpp +++ b/src/V3Coverage.cpp @@ -37,7 +37,7 @@ //###################################################################### // Coverage state, as a visitor of each AstNode -class CoverageVisitor : public AstNVisitor { +class CoverageVisitor final : public AstNVisitor { private: // TYPES typedef std::unordered_map VarNameMap; @@ -52,7 +52,7 @@ private: : m_comment{comment} , m_varRefp{vp} , m_chgRefp{cp} {} - ~ToggleEnt() {} + ~ToggleEnt() = default; void cleanup() { VL_DO_CLEAR(m_varRefp->deleteTree(), m_varRefp = nullptr); VL_DO_CLEAR(m_chgRefp->deleteTree(), m_chgRefp = nullptr); @@ -64,7 +64,7 @@ private: bool m_inModOff = false; // In module with no coverage int m_handle = 0; // Opaque handle for index into line tracking const AstNode* m_nodep = nullptr; // Node establishing this state - CheckState() {} + CheckState() = default; bool lineCoverageOn(const AstNode* nodep) const { return m_on && !m_inModOff && nodep->fileline()->coverageOn() && v3Global.opt.coverageLine(); @@ -534,7 +534,7 @@ private: public: // CONSTRUCTORS explicit CoverageVisitor(AstNetlist* rootp) { iterateChildren(rootp); } - virtual ~CoverageVisitor() override {} + virtual ~CoverageVisitor() override = default; }; //###################################################################### diff --git a/src/V3Coverage.h b/src/V3Coverage.h index b24b25ee8..37ebbacd5 100644 --- a/src/V3Coverage.h +++ b/src/V3Coverage.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Coverage { +class V3Coverage final { public: // CONSTRUCTORS static void coverage(AstNetlist* rootp); diff --git a/src/V3CoverageJoin.cpp b/src/V3CoverageJoin.cpp index 94da008d7..aebcc1f7f 100644 --- a/src/V3CoverageJoin.cpp +++ b/src/V3CoverageJoin.cpp @@ -30,7 +30,7 @@ //###################################################################### // CoverageJoin state, as a visitor of each AstNode -class CoverageJoinVisitor : public AstNVisitor { +class CoverageJoinVisitor final : public AstNVisitor { private: // NODE STATE // V3Hashed diff --git a/src/V3CoverageJoin.h b/src/V3CoverageJoin.h index 1983db564..cdf2447e5 100644 --- a/src/V3CoverageJoin.h +++ b/src/V3CoverageJoin.h @@ -25,7 +25,7 @@ //============================================================================ -class V3CoverageJoin { +class V3CoverageJoin final { public: // CONSTRUCTORS static void coverageJoin(AstNetlist* rootp); diff --git a/src/V3Dead.cpp b/src/V3Dead.cpp index 7b75e4bdb..d9602c913 100644 --- a/src/V3Dead.cpp +++ b/src/V3Dead.cpp @@ -30,9 +30,8 @@ // Note on packagep: After the V3Scope/V3LinkDotScoped stage, package links // are no longer used, but their presence prevents us from removing empty // packages. As the links as no longer used after V3Scope, we remove them -// here after scoping to allow more dead node -// removal. -// ************************************************************************* +// here after scoping to allow more dead node removal. +//************************************************************************* #include "config_build.h" #include "verilatedos.h" @@ -46,7 +45,7 @@ //###################################################################### -class DeadModVisitor : public AstNVisitor { +class DeadModVisitor final : public AstNVisitor { // In a module that is dead, cleanup the in-use counts of the modules private: // NODE STATE @@ -63,13 +62,13 @@ private: public: // CONSTRUCTORS explicit DeadModVisitor(AstNodeModule* nodep) { iterate(nodep); } - virtual ~DeadModVisitor() override {} + virtual ~DeadModVisitor() override = default; }; //###################################################################### // Dead state, as a visitor of each AstNode -class DeadVisitor : public AstNVisitor { +class DeadVisitor final : public AstNVisitor { private: // NODE STATE // Entire Netlist: @@ -83,7 +82,7 @@ private: typedef std::multimap AssignMap; // STATE - AstNodeModule* m_modp; // Current module + AstNodeModule* m_modp = nullptr; // Current module // List of all encountered to avoid another loop through tree std::vector m_varsp; std::vector m_dtypesp; @@ -93,10 +92,10 @@ private: std::vector m_classesp; AssignMap m_assignMap; // List of all simple assignments for each variable - bool m_elimUserVars; // Allow removal of user's vars - bool m_elimDTypes; // Allow removal of DTypes - bool m_elimCells; // Allow removal of Cells - bool m_sideEffect; // Side effects discovered in assign RHS + const bool m_elimUserVars; // Allow removal of user's vars + const bool m_elimDTypes; // Allow removal of DTypes + const bool m_elimCells; // Allow removal of Cells + bool m_sideEffect = false; // Side effects discovered in assign RHS // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -107,6 +106,9 @@ private: } if (AstNode* subnodep = nodep->getChildDTypep()) subnodep->user1Inc(); } + void checkVarRef(AstNodeVarRef* nodep) { + if (nodep->classOrPackagep() && m_elimCells) nodep->classOrPackagep(nullptr); + } void checkDType(AstNodeDType* nodep) { if (!nodep->generic() // Don't remove generic types && m_elimDTypes // dtypes stick around until post-widthing @@ -120,6 +122,7 @@ private: // VISITORS virtual void visit(AstNodeModule* nodep) override { + if (m_modp) m_modp->user1Inc(); // e.g. Class under Package VL_RESTORER(m_modp); { m_modp = nodep; @@ -128,7 +131,7 @@ private: checkAll(nodep); if (AstClass* classp = VN_CAST(nodep, Class)) { if (classp->extendsp()) classp->extendsp()->user1Inc(); - if (classp->packagep()) classp->packagep()->user1Inc(); + if (classp->classOrPackagep()) classp->classOrPackagep()->user1Inc(); m_classesp.push_back(classp); // TODO we don't reclaim dead classes yet - graph implementation instead? classp->user1Inc(); @@ -160,29 +163,25 @@ private: } virtual void visit(AstNodeVarRef* nodep) override { + // Note NodeAssign skips calling this in some cases iterateChildren(nodep); checkAll(nodep); + checkVarRef(nodep); if (nodep->varScopep()) { nodep->varScopep()->user1Inc(); nodep->varScopep()->varp()->user1Inc(); } if (nodep->varp()) nodep->varp()->user1Inc(); - if (nodep->packagep()) { - if (m_elimCells) { - nodep->packagep(nullptr); - } else { - nodep->packagep()->user1Inc(); - } - } + if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(); } virtual void visit(AstNodeFTaskRef* nodep) override { iterateChildren(nodep); checkAll(nodep); - if (nodep->packagep()) { + if (nodep->classOrPackagep()) { if (m_elimCells) { - nodep->packagep(nullptr); + nodep->classOrPackagep(nullptr); } else { - nodep->packagep()->user1Inc(); + nodep->classOrPackagep()->user1Inc(); } } } @@ -196,11 +195,11 @@ private: checkAll(nodep); UASSERT_OBJ(!(m_elimCells && nodep->typedefp()), nodep, "RefDType should point to data type before typedefs removed"); - if (nodep->packagep()) { + if (nodep->classOrPackagep()) { if (m_elimCells) { - nodep->packagep(nullptr); + nodep->classOrPackagep(nullptr); } else { - nodep->packagep()->user1Inc(); + nodep->classOrPackagep()->user1Inc(); } } } @@ -208,11 +207,11 @@ private: iterateChildren(nodep); checkDType(nodep); checkAll(nodep); - if (nodep->packagep()) { + if (nodep->classOrPackagep()) { if (m_elimCells) { - nodep->packagep(nullptr); + nodep->classOrPackagep(nullptr); } else { - nodep->packagep()->user1Inc(); + nodep->classOrPackagep()->user1Inc(); } } if (nodep->classp()) nodep->classp()->user1Inc(); @@ -225,11 +224,11 @@ private: virtual void visit(AstEnumItemRef* nodep) override { iterateChildren(nodep); checkAll(nodep); - if (nodep->packagep()) { + if (nodep->classOrPackagep()) { if (m_elimCells) { - nodep->packagep(nullptr); + nodep->classOrPackagep(nullptr); } else { - nodep->packagep()->user1Inc(); + nodep->classOrPackagep()->user1Inc(); } } checkAll(nodep); @@ -277,19 +276,22 @@ private: // See if simple assignments to variables may be eliminated because // that variable is never used. // Similar code in V3Life - m_sideEffect = false; - iterateAndNextNull(nodep->rhsp()); - checkAll(nodep); - // Has to be direct assignment without any EXTRACTing. - AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); - if (varrefp && !m_sideEffect - && varrefp->varScopep()) { // For simplicity, we only remove post-scoping - m_assignMap.insert(make_pair(varrefp->varScopep(), nodep)); - checkAll(varrefp); // Must track reference to dtype() - } else { // Track like any other statement - iterateAndNextNull(nodep->lhsp()); + VL_RESTORER(m_sideEffect); + { + m_sideEffect = false; + iterateAndNextNull(nodep->rhsp()); + checkAll(nodep); + // Has to be direct assignment without any EXTRACTing. + AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); + if (varrefp && !m_sideEffect + && varrefp->varScopep()) { // For simplicity, we only remove post-scoping + m_assignMap.insert(make_pair(varrefp->varScopep(), nodep)); + checkAll(varrefp); // Must track reference to dtype() + checkVarRef(varrefp); + } else { // Track like any other statement + iterateAndNextNull(nodep->lhsp()); + } } - checkAll(nodep); } //----- @@ -371,7 +373,7 @@ private: if (AstClass* nodep = itr) { // nullptr if deleted earlier if (nodep->user1() == 0) { if (nodep->extendsp()) nodep->extendsp()->user1Inc(-1); - if (nodep->packagep()) nodep->packagep()->user1Inc(-1); + if (nodep->classOrPackagep()) nodep->classOrPackagep()->user1Inc(-1); VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep); itr = nullptr; retry = true; @@ -438,12 +440,10 @@ private: public: // CONSTRUCTORS DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes, bool elimScopes, - bool elimCells) { - m_modp = nullptr; - m_elimCells = elimCells; - m_elimUserVars = elimUserVars; - m_elimDTypes = elimDTypes; - m_sideEffect = false; + bool elimCells) + : m_elimUserVars{elimUserVars} + , m_elimDTypes{elimDTypes} + , m_elimCells{elimCells} { // Prepare to remove some datatypes nodep->typeTablep()->clearCache(); // Operate on whole netlist @@ -461,7 +461,7 @@ public: // We may have removed some datatypes, cleanup nodep->typeTablep()->repairCache(); } - virtual ~DeadVisitor() override {} + virtual ~DeadVisitor() override = default; }; //###################################################################### diff --git a/src/V3Dead.h b/src/V3Dead.h index 6ef94b8d6..45da1943c 100644 --- a/src/V3Dead.h +++ b/src/V3Dead.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Dead { +class V3Dead final { public: // Modules, no vars/dtypes static void deadifyModules(AstNetlist* nodep); diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp index c2f80ca6d..60888600e 100644 --- a/src/V3Delayed.cpp +++ b/src/V3Delayed.cpp @@ -63,7 +63,7 @@ //###################################################################### // Delayed state, as a visitor of each AstNode -class DelayedVisitor : public AstNVisitor { +class DelayedVisitor final : public AstNVisitor { private: // NODE STATE // Cleared each module: @@ -98,7 +98,7 @@ private: typedef std::map, AstVar*> VarMap; VarMap m_modVarMap; // Table of new var names created under module VDouble0 m_statSharedSet; // Statistic tracking - typedef std::map ScopeVecMap; + typedef std::unordered_map ScopeVecMap; ScopeVecMap m_scopeVecMap; // Next var number for each scope // METHODS @@ -160,10 +160,10 @@ private: varrefp->varp()->v3warn( MULTIDRIVEN, "Signal has multiple driving blocks with different clocking: " - << varrefp->varp()->prettyNameQ() << endl - << varrefp->warnOther() << "... Location of first driving block" << endl - << varrefp->warnContextPrimary() << endl - << oldactivep->warnOther() << "... Location of other driving block" << endl + << varrefp->varp()->prettyNameQ() << '\n' + << varrefp->warnOther() << "... Location of first driving block\n" + << varrefp->warnContextPrimary() << '\n' + << oldactivep->warnOther() << "... Location of other driving block\n" << oldactivep->warnContextSecondary()); varrefp->varp()->user2(true); } @@ -289,7 +289,7 @@ private: new AstConst(nodep->fileline(), 0)); AstAssign* setassignp = new AstAssign( nodep->fileline(), new AstVarRef(nodep->fileline(), setvscp, VAccess::WRITE), - new AstConst(nodep->fileline(), AstConst::LogicTrue())); + new AstConst(nodep->fileline(), AstConst::BitTrue())); nodep->addNextHere(setassignp); } if (m_nextDlyp) { // Tell next assigndly it can share the variable @@ -436,7 +436,7 @@ private: prep = new AstAssignPre( nodep->fileline(), new AstVarRef(nodep->fileline(), dlyvscp, VAccess::WRITE), - new AstConst(nodep->fileline(), AstConst::LogicFalse())); + new AstConst(nodep->fileline(), AstConst::BitFalse())); } else { prep = new AstAssignPre( nodep->fileline(), diff --git a/src/V3Delayed.h b/src/V3Delayed.h index cdacae1ff..eaa1e2650 100644 --- a/src/V3Delayed.h +++ b/src/V3Delayed.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Delayed { +class V3Delayed final { public: static void delayedAll(AstNetlist* nodep); }; diff --git a/src/V3Depth.cpp b/src/V3Depth.cpp index fce9b9cf4..6cc0bc5d7 100644 --- a/src/V3Depth.cpp +++ b/src/V3Depth.cpp @@ -34,7 +34,7 @@ //###################################################################### -class DepthVisitor : public AstNVisitor { +class DepthVisitor final : public AstNVisitor { private: // NODE STATE @@ -155,7 +155,7 @@ private: public: // CONSTRUCTORS explicit DepthVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DepthVisitor() override {} + virtual ~DepthVisitor() override = default; }; //###################################################################### diff --git a/src/V3Depth.h b/src/V3Depth.h index 6527afab8..9e1e4834f 100644 --- a/src/V3Depth.h +++ b/src/V3Depth.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Depth { +class V3Depth final { public: static void depthAll(AstNetlist* nodep); }; diff --git a/src/V3DepthBlock.cpp b/src/V3DepthBlock.cpp index b4346db8d..19a3a0604 100644 --- a/src/V3DepthBlock.cpp +++ b/src/V3DepthBlock.cpp @@ -32,7 +32,7 @@ //###################################################################### -class DepthBlockVisitor : public AstNVisitor { +class DepthBlockVisitor final : public AstNVisitor { private: // NODE STATE @@ -117,7 +117,7 @@ private: public: // CONSTRUCTORS explicit DepthBlockVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DepthBlockVisitor() override {} + virtual ~DepthBlockVisitor() override = default; }; //###################################################################### diff --git a/src/V3DepthBlock.h b/src/V3DepthBlock.h index 2ba04b280..7233cd320 100644 --- a/src/V3DepthBlock.h +++ b/src/V3DepthBlock.h @@ -25,7 +25,7 @@ //============================================================================ -class V3DepthBlock { +class V3DepthBlock final { public: static void depthBlockAll(AstNetlist* nodep); }; diff --git a/src/V3Descope.cpp b/src/V3Descope.cpp index 9cf15822b..a23413e8c 100644 --- a/src/V3Descope.cpp +++ b/src/V3Descope.cpp @@ -34,7 +34,7 @@ //###################################################################### -class DescopeVisitor : public AstNVisitor { +class DescopeVisitor final : public AstNVisitor { private: // NODE STATE // Cleared entire netlist @@ -76,7 +76,8 @@ private: // Sets 'hierThisr' true if the object is local to this scope // (and could be made into a function-local later in V3Localize), // false if the object is in another scope. - string descopedName(const AstScope* scopep, bool& hierThisr, const AstVar* varp = nullptr) { + string descopedName(bool& hierThisr, string& hierUnprot, const AstScope* scopep, + const AstVar* varp) { UASSERT(scopep, "Var/Func not scoped"); hierThisr = (scopep == m_scopep); @@ -118,6 +119,9 @@ private: } else if (relativeRefOk && scopep == m_scopep) { m_needThis = true; return "this->"; + } else if (VN_IS(scopep->modp(), Class)) { + hierUnprot = v3Global.opt.modPrefix() + "_"; // Prefix before protected part + return scopep->modp()->name() + "::"; } else if (relativeRefOk && scopep->aboveScopep() && scopep->aboveScopep() == m_scopep) { // Reference to scope of cell directly under this module, can just "cell->" string name = scopep->name(); @@ -249,12 +253,17 @@ private: virtual void visit(AstNodeVarRef* nodep) override { iterateChildren(nodep); // Convert the hierch name + UINFO(9, " ref-in " << nodep << endl); UASSERT_OBJ(m_scopep, nodep, "Node not under scope"); bool hierThis; - nodep->hiername(descopedName(nodep->varScopep()->scopep(), hierThis /*ref*/, - nodep->varScopep()->varp())); + string hierUnprot; + nodep->hiernameToProt(descopedName(hierThis /*ref*/, hierUnprot /*ref*/, + nodep->varScopep()->scopep(), + nodep->varScopep()->varp())); + nodep->hiernameToUnprot(hierUnprot); nodep->hierThis(hierThis); nodep->varScopep(nullptr); + UINFO(9, " refout " << nodep << endl); } virtual void visit(AstNodeCCall* nodep) override { // UINFO(9, " " << nodep << endl); @@ -263,7 +272,10 @@ private: UASSERT_OBJ(m_scopep, nodep, "Node not under scope"); UASSERT_OBJ(nodep->funcp()->scopep(), nodep, "CFunc not under scope"); bool hierThis; - nodep->hiername(descopedName(nodep->funcp()->scopep(), hierThis /*ref*/)); + string hierUnprot; + nodep->hiernameToProt( + descopedName(hierThis /*ref*/, hierUnprot /*ref*/, nodep->funcp()->scopep(), nullptr)); + nodep->hiernameToUnprot(hierUnprot); // Can't do this, as we may have more calls later // nodep->funcp()->scopep(nullptr); } @@ -296,7 +308,7 @@ private: public: // CONSTRUCTORS explicit DescopeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~DescopeVisitor() override {} + virtual ~DescopeVisitor() override = default; }; //###################################################################### @@ -304,6 +316,7 @@ public: void V3Descope::descopeAll(AstNetlist* nodep) { UINFO(2, __FUNCTION__ << ": " << endl); + v3Global.assertScoped(false); { DescopeVisitor visitor(nodep); } // Destruct before checking V3Global::dumpCheckGlobalTree("descope", 0, v3Global.opt.dumpTreeLevel(__FILE__) >= 3); } diff --git a/src/V3Descope.h b/src/V3Descope.h index f808a5a8d..04093afd6 100644 --- a/src/V3Descope.h +++ b/src/V3Descope.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Descope { +class V3Descope final { public: static void descopeAll(AstNetlist* nodep); }; diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp index 79a11f158..db5a803f5 100644 --- a/src/V3EmitC.cpp +++ b/src/V3EmitC.cpp @@ -39,7 +39,7 @@ constexpr int EMITC_NUM_CONSTW //###################################################################### // Emit statements and math operators -class EmitCStmts : public EmitCBaseVisitor { +class EmitCStmts VL_NOT_FINAL : public EmitCBaseVisitor { private: typedef std::vector VarVec; typedef std::map VarSortMap; // Map size class to VarVec @@ -216,7 +216,7 @@ public: } struct CmpName { - inline bool operator()(const AstNode* lhsp, const AstNode* rhsp) const { + bool operator()(const AstNode* lhsp, const AstNode* rhsp) const { return lhsp->name() < rhsp->name(); } }; @@ -430,8 +430,12 @@ public: virtual void visit(AstWith* nodep) override { // With uses a C++11 lambda putbs("[=]("); - if (auto* argrefp = nodep->argrefp()) { - putbs(argrefp->dtypep()->cType(nodep->argrefp()->nameProtect(), false, false)); + if (auto* argrefp = nodep->indexArgRefp()) { + putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); + puts(","); + } + if (auto* argrefp = nodep->valueArgRefp()) { + putbs(argrefp->dtypep()->cType(argrefp->nameProtect(), false, false)); } // Probably fragile, V3Task may need to convert to a AstCReturn puts(") { return "); @@ -836,6 +840,9 @@ public: putsQuoted(nodep->timeunit().ascii()); puts(");\n"); } + virtual void visit(AstRand* nodep) override { + emitOpName(nodep, nodep->emitC(), nodep->seedp(), nullptr, nullptr); + } virtual void visit(AstTime* nodep) override { puts("VL_TIME_UNITED_Q("); if (nodep->timeunit().isNone()) nodep->v3fatalSrc("$time has no units"); @@ -1258,25 +1265,25 @@ public: m_trackText = trackText; iterate(nodep); } - virtual ~EmitCStmts() override {} + virtual ~EmitCStmts() override = default; }; //###################################################################### // Establish mtask variable sort order in mtasks mode -class EmitVarTspSorter : public V3TSP::TspStateBase { +class EmitVarTspSorter final : public V3TSP::TspStateBase { private: // MEMBERS const MTaskIdSet& m_mtaskIds; // Mtask we're ordering - static unsigned m_serialNext; // Unique ID to establish serial order + static unsigned s_serialNext; // Unique ID to establish serial order unsigned m_serial; // Serial ordering public: // CONSTRUCTORS explicit EmitVarTspSorter(const MTaskIdSet& mtaskIds) : m_mtaskIds(mtaskIds) { // Cannot be {} or GCC 4.8 false warning - m_serial = ++m_serialNext; // Cannot be ()/{} or GCC 4.8 false warning + m_serial = ++s_serialNext; // Cannot be ()/{} or GCC 4.8 false warning } - virtual ~EmitVarTspSorter() {} + virtual ~EmitVarTspSorter() = default; // METHODS virtual bool operator<(const TspStateBase& other) const override { return operator<(dynamic_cast(other)); @@ -1301,12 +1308,12 @@ public: } }; -unsigned EmitVarTspSorter::m_serialNext = 0; +unsigned EmitVarTspSorter::s_serialNext = 0; //###################################################################### // Internal EmitC implementation -class EmitCImp : EmitCStmts { +class EmitCImp final : EmitCStmts { // MEMBERS AstNodeModule* m_modp = nullptr; std::vector m_blkChangeDetVec; // All encountered changes in block @@ -1840,8 +1847,8 @@ class EmitCImp : EmitCStmts { void maybeSplit(AstNodeModule* modp); public: - EmitCImp() {} - virtual ~EmitCImp() override {} + EmitCImp() = default; + virtual ~EmitCImp() override = default; void mainImp(AstNodeModule* modp, bool slow); void mainInt(AstNodeModule* modp); void mainDoFunc(AstCFunc* nodep) { iterate(nodep); } @@ -3401,7 +3408,7 @@ void EmitCImp::mainImp(AstNodeModule* modp, bool slow) { //###################################################################### // Tracing routines -class EmitCTrace : EmitCStmts { +class EmitCTrace final : EmitCStmts { // NODE STATE/TYPES // Cleared on netlist // AstNode::user1() -> int. Enum number @@ -3840,7 +3847,7 @@ class EmitCTrace : EmitCStmts { public: explicit EmitCTrace(bool slow) : m_slow{slow} {} - virtual ~EmitCTrace() override {} + virtual ~EmitCTrace() override = default; void main() { // Put out the file newOutCFile(0); diff --git a/src/V3EmitC.h b/src/V3EmitC.h index 0bd5ec642..e89b8f89a 100644 --- a/src/V3EmitC.h +++ b/src/V3EmitC.h @@ -25,7 +25,7 @@ //============================================================================ -class V3EmitC { +class V3EmitC final { public: static void emitc(); static void emitcInlines(); diff --git a/src/V3EmitCBase.h b/src/V3EmitCBase.h index 75e4838ec..731b8356e 100644 --- a/src/V3EmitCBase.h +++ b/src/V3EmitCBase.h @@ -30,7 +30,7 @@ //###################################################################### // Base Visitor class -- holds output file pointer -class EmitCBaseVisitor : public AstNVisitor { +class EmitCBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: // STATE V3OutCFile* m_ofp = nullptr; @@ -106,14 +106,14 @@ public: } // CONSTRUCTORS - EmitCBaseVisitor() {} - virtual ~EmitCBaseVisitor() override {} + EmitCBaseVisitor() = default; + virtual ~EmitCBaseVisitor() override = default; }; //###################################################################### // Count operations under the given node, as a visitor of each AstNode -class EmitCBaseCounterVisitor : public AstNVisitor { +class EmitCBaseCounterVisitor final : public AstNVisitor { private: // MEMBERS int m_count = 0; // Number of statements @@ -126,7 +126,7 @@ private: public: // CONSTRUCTORS explicit EmitCBaseCounterVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~EmitCBaseCounterVisitor() override {} + virtual ~EmitCBaseCounterVisitor() override = default; int count() const { return m_count; } }; diff --git a/src/V3EmitCInlines.cpp b/src/V3EmitCInlines.cpp index eb91000d0..df7d20c88 100644 --- a/src/V3EmitCInlines.cpp +++ b/src/V3EmitCInlines.cpp @@ -26,7 +26,7 @@ //###################################################################### -class EmitCInlines : EmitCBaseVisitor { +class EmitCInlines final : EmitCBaseVisitor { // STATE // METHODS diff --git a/src/V3EmitCMain.cpp b/src/V3EmitCMain.cpp index 3d066bc1b..f23cc7668 100644 --- a/src/V3EmitCMain.cpp +++ b/src/V3EmitCMain.cpp @@ -26,7 +26,7 @@ //###################################################################### -class EmitCMain : EmitCBaseVisitor { +class EmitCMain final : EmitCBaseVisitor { // METHODS // VISITORS diff --git a/src/V3EmitCMain.h b/src/V3EmitCMain.h index 04df088a2..c17449f50 100644 --- a/src/V3EmitCMain.h +++ b/src/V3EmitCMain.h @@ -22,7 +22,7 @@ //============================================================================ -class V3EmitCMain { +class V3EmitCMain final { public: static void emit(); }; diff --git a/src/V3EmitCMake.cpp b/src/V3EmitCMake.cpp index 0b7e0f52e..4844f5ad6 100644 --- a/src/V3EmitCMake.cpp +++ b/src/V3EmitCMake.cpp @@ -28,7 +28,7 @@ //###################################################################### // Emit statements -class CMakeEmitter { +class CMakeEmitter final { // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -256,7 +256,7 @@ class CMakeEmitter { public: explicit CMakeEmitter() { emitOverallCMake(); } - virtual ~CMakeEmitter() {} + virtual ~CMakeEmitter() = default; }; void V3EmitCMake::emit() { diff --git a/src/V3EmitCMake.h b/src/V3EmitCMake.h index 9cfe9275a..144a22925 100644 --- a/src/V3EmitCMake.h +++ b/src/V3EmitCMake.h @@ -22,7 +22,7 @@ //============================================================================ -class V3EmitCMake { +class V3EmitCMake final { public: static void emit(); }; diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp index f0e63fa1d..168437852 100644 --- a/src/V3EmitCSyms.cpp +++ b/src/V3EmitCSyms.cpp @@ -29,7 +29,7 @@ //###################################################################### // Symbol table emitting -class EmitCSyms : EmitCBaseVisitor { +class EmitCSyms final : EmitCBaseVisitor { // NODE STATE // Cleared on Netlist // AstNodeModule::user1() -> bool. Set true __Vconfigure called @@ -79,12 +79,12 @@ class EmitCSyms : EmitCBaseVisitor { typedef std::vector ScopeNameList; typedef std::map ScopeNameHierarchy; struct CmpName { - inline bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { + bool operator()(const ScopeModPair& lhsp, const ScopeModPair& rhsp) const { return lhsp.first->name() < rhsp.first->name(); } }; struct CmpDpi { - inline bool operator()(const AstCFunc* lhsp, const AstCFunc* rhsp) const { + bool operator()(const AstCFunc* lhsp, const AstCFunc* rhsp) const { if (lhsp->dpiImport() != rhsp->dpiImport()) { // cppcheck-suppress comparisonOfFuncReturningBoolError return lhsp->dpiImport() < rhsp->dpiImport(); @@ -109,7 +109,7 @@ class EmitCSyms : EmitCBaseVisitor { int m_numStmts = 0; // Number of statements output int m_funcNum = 0; // CFunc split function number V3OutCFile* m_ofpBase = nullptr; // Base (not split) C file - std::map m_usesVfinal; // Split method uses __Vfinal + std::unordered_map m_usesVfinal; // Split method uses __Vfinal // METHODS void emitSymHdr(); @@ -467,7 +467,7 @@ void EmitCSyms::emitSymHdr() { puts("\n// CREATORS\n"); puts(symClassName() + "(" + topClassName() + "* topp, const char* namep);\n"); - puts(string("~") + symClassName() + "() {}\n"); + puts(string("~") + symClassName() + "() = default;\n"); for (const auto& i : m_usesVfinal) { puts("void " + symClassName() + "_" + cvtToStr(i.first) + "("); diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp index 0a55a2ef9..cf50f1ea2 100644 --- a/src/V3EmitMk.cpp +++ b/src/V3EmitMk.cpp @@ -26,7 +26,7 @@ //###################################################################### // Emit statements and math operators -class EmitMk { +class EmitMk final { public: // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -285,11 +285,11 @@ public: emitClassMake(); emitOverallMake(); } - virtual ~EmitMk() {} + virtual ~EmitMk() = default; }; //###################################################################### -class EmitMkHierVerilation { +class EmitMkHierVerilation final { const V3HierBlockPlan* const m_planp; const string m_makefile; // path of this makefile void emitCommonOpts(V3OutMkFile& of) const { diff --git a/src/V3EmitMk.h b/src/V3EmitMk.h index 4e30f598c..bb329c3bd 100644 --- a/src/V3EmitMk.h +++ b/src/V3EmitMk.h @@ -24,7 +24,7 @@ class V3HierBlockPlan; //============================================================================ -class V3EmitMk { +class V3EmitMk final { public: static void emitmk(); static void emitHierVerilation(const V3HierBlockPlan* planp); diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp index aa53317dd..664f6ddbd 100644 --- a/src/V3EmitV.cpp +++ b/src/V3EmitV.cpp @@ -28,7 +28,7 @@ //###################################################################### // Emit statements and math operators -class EmitVBaseVisitor : public EmitCBaseVisitor { +class EmitVBaseVisitor VL_NOT_FINAL : public EmitCBaseVisitor { // MEMBERS bool m_suppressSemi = false; bool m_suppressUnknown = false; @@ -613,7 +613,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor { if (nodep->varScopep()) { putfs(nodep, nodep->varScopep()->prettyName()); } else { - putfs(nodep, nodep->hiername()); + putfs(nodep, nodep->hiernameToUnprot()); + puts(nodep->hiernameToProt()); puts(nodep->varp()->prettyName()); } } @@ -667,13 +668,13 @@ public: explicit EmitVBaseVisitor(bool suppressUnknown, AstSenTree* domainp) : m_suppressUnknown{suppressUnknown} , m_sensesp{domainp} {} - virtual ~EmitVBaseVisitor() override {} + virtual ~EmitVBaseVisitor() override = default; }; //###################################################################### // Emit to an output file -class EmitVFileVisitor : public EmitVBaseVisitor { +class EmitVFileVisitor final : public EmitVBaseVisitor { // MEMBERS V3OutFile* m_ofp; // METHODS @@ -693,13 +694,13 @@ public: m_suppressVarSemi = suppressVarSemi; iterate(nodep); } - virtual ~EmitVFileVisitor() override {} + virtual ~EmitVFileVisitor() override = default; }; //###################################################################### // Emit to a stream (perhaps stringstream) -class EmitVStreamVisitor : public EmitVBaseVisitor { +class EmitVStreamVisitor final : public EmitVBaseVisitor { // MEMBERS std::ostream& m_os; // METHODS @@ -715,13 +716,13 @@ public: , m_os(os) { // Need () or GCC 4.8 false warning iterate(nodep); } - virtual ~EmitVStreamVisitor() override {} + virtual ~EmitVStreamVisitor() override = default; }; //###################################################################### // Emit to a stream (perhaps stringstream) -class EmitVPrefixedFormatter : public V3OutFormatter { +class EmitVPrefixedFormatter final : public V3OutFormatter { std::ostream& m_os; string m_prefix; // What to print at beginning of each line int m_flWidth; // Padding of fileline @@ -763,7 +764,7 @@ public: } }; -class EmitVPrefixedVisitor : public EmitVBaseVisitor { +class EmitVPrefixedVisitor final : public EmitVBaseVisitor { // MEMBERS EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the // inheritance is another unused V3OutFormatter) @@ -792,7 +793,7 @@ public: if (user3mark) { AstUser3InUse::check(); } iterate(nodep); } - virtual ~EmitVPrefixedVisitor() override {} + virtual ~EmitVPrefixedVisitor() override = default; }; //###################################################################### diff --git a/src/V3EmitV.h b/src/V3EmitV.h index 4a4900895..98f8b3cbb 100644 --- a/src/V3EmitV.h +++ b/src/V3EmitV.h @@ -25,7 +25,7 @@ //============================================================================ -class V3EmitV { +class V3EmitV final { public: static void verilogForTree(AstNode* nodep, std::ostream& os = std::cout); static void verilogPrefixedTree(AstNode* nodep, std::ostream& os, const string& prefix, diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp index da2d26720..b39a30f43 100644 --- a/src/V3EmitXml.cpp +++ b/src/V3EmitXml.cpp @@ -28,7 +28,7 @@ //###################################################################### // Emit statements and math operators -class EmitXmlFileVisitor : public AstNVisitor { +class EmitXmlFileVisitor final : public AstNVisitor { // NODE STATE // Entire netlist: // AstNode::user1 -> uint64_t, number to connect crossrefs @@ -250,13 +250,13 @@ public: : m_ofp{ofp} { iterate(nodep); } - virtual ~EmitXmlFileVisitor() override {} + virtual ~EmitXmlFileVisitor() override = default; }; //###################################################################### // List of module files xml visitor -class ModuleFilesXmlVisitor : public AstNVisitor { +class ModuleFilesXmlVisitor final : public AstNVisitor { private: // MEMBERS std::ostream& m_os; @@ -298,13 +298,13 @@ public: } m_os << "\n"; } - virtual ~ModuleFilesXmlVisitor() override {} + virtual ~ModuleFilesXmlVisitor() override = default; }; //###################################################################### // Hierarchy of Cells visitor -class HierCellsXmlVisitor : public AstNVisitor { +class HierCellsXmlVisitor final : public AstNVisitor { private: // MEMBERS std::ostream& m_os; @@ -363,7 +363,7 @@ public: // Operate on whole netlist nodep->accept(*this); } - virtual ~HierCellsXmlVisitor() override {} + virtual ~HierCellsXmlVisitor() override = default; }; //###################################################################### diff --git a/src/V3EmitXml.h b/src/V3EmitXml.h index 14d1a3e9e..18555891f 100644 --- a/src/V3EmitXml.h +++ b/src/V3EmitXml.h @@ -25,7 +25,7 @@ //============================================================================ -class V3EmitXml { +class V3EmitXml final { public: static void emitxml(); }; diff --git a/src/V3Error.cpp b/src/V3Error.cpp index e60ce5667..e8f8c6e18 100644 --- a/src/V3Error.cpp +++ b/src/V3Error.cpp @@ -36,9 +36,9 @@ std::ostringstream V3Error::s_errorStr; // Error string being formed V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL; bool V3Error::s_errorContexted = false; bool V3Error::s_errorSuppressed = false; -bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; +std::array V3Error::s_describedEachWarn; +std::array V3Error::s_pretendError; bool V3Error::s_describedWarnings = false; -bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX]; V3Error::MessagesSet V3Error::s_messages; V3Error::ErrorExitCb V3Error::s_errorExitCb = nullptr; @@ -234,7 +234,7 @@ void V3Error::v3errorEnd(std::ostringstream& sstr, const string& locationStr) { s_describedWarnings = true; } if (s_errorCode.dangerous()) { - std::cerr << warnMore() << "*** See the manual before disabling this," << endl; + std::cerr << warnMore() << "*** See the manual before disabling this,\n"; std::cerr << warnMore() << "else you may end up with different sim results." << endl; } diff --git a/src/V3Error.h b/src/V3Error.h index a1846e8e4..5e88ba6c2 100644 --- a/src/V3Error.h +++ b/src/V3Error.h @@ -23,6 +23,7 @@ // Limited V3 headers here - this is a base class for Vlc etc #include "V3String.h" +#include #include #include #include @@ -32,7 +33,7 @@ //###################################################################### -class V3ErrorCode { +class V3ErrorCode final { public: // clang-format off enum en: uint8_t { @@ -51,6 +52,7 @@ public: I_DEF_NETTYPE_WIRE, // `default_nettype is WIRE (false=NONE) // Error codes: E_DETECTARRAY, // Error: Unsupported: Can't detect changes on arrayed variable + E_ENCAPSULATED, // Error: local/protected violation E_PORTSHORT, // Error: Output port is connected to a constant, electrical short E_UNSUPPORTED, // Error: Unsupported (generally) E_TASKNSVAR, // Error: Task I/O not simple @@ -146,7 +148,7 @@ public: // Boolean " I_CELLDEFINE", " I_COVERAGE", " I_TRACING", " I_LINT", " I_DEF_NETTYPE_WIRE", // Errors - "DETECTARRAY", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", + "DETECTARRAY", "ENCAPSULATED", "PORTSHORT", "UNSUPPORTED", "TASKNSVAR", // Warnings " EC_FIRST_WARN", "ALWCOMBORDER", "ASSIGNDLY", "ASSIGNIN", @@ -216,7 +218,7 @@ inline std::ostream& operator<<(std::ostream& os, const V3ErrorCode& rhs) { //###################################################################### -class V3Error { +class V3Error final { // Base class for any object that wants debugging and error reporting typedef std::set MessagesSet; @@ -224,9 +226,10 @@ class V3Error { private: static bool s_describedWarnings; // Told user how to disable warns - static bool - s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning - static bool s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error + static std::array + s_describedEachWarn; // Told user specifics about this warning + static std::array + s_pretendError; // Pretend this warning is an error static int s_debugDefault; // Option: --debugi Default debugging level static int s_errorLimit; // Option: --error-limit Number of errors before exit static bool s_warnFatal; // Option: --warnFatal Warnings are fatal diff --git a/src/V3Expand.cpp b/src/V3Expand.cpp index fb6bc7c43..f594434b2 100644 --- a/src/V3Expand.cpp +++ b/src/V3Expand.cpp @@ -37,7 +37,7 @@ //###################################################################### // Expand state, as a visitor of each AstNode -class ExpandVisitor : public AstNVisitor { +class ExpandVisitor final : public AstNVisitor { private: // NODE STATE // AstNode::user1() -> bool. Processed @@ -879,7 +879,7 @@ private: public: // CONSTRUCTORS explicit ExpandVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ExpandVisitor() override {} + virtual ~ExpandVisitor() override = default; }; //---------------------------------------------------------------------- diff --git a/src/V3Expand.h b/src/V3Expand.h index f0eb83608..7080ecbcd 100644 --- a/src/V3Expand.h +++ b/src/V3Expand.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Expand { +class V3Expand final { public: static void expandAll(AstNetlist* nodep); }; diff --git a/src/V3File.cpp b/src/V3File.cpp index ed7749481..66f82abbb 100644 --- a/src/V3File.cpp +++ b/src/V3File.cpp @@ -62,23 +62,22 @@ constexpr int INFILTER_CACHE_MAX = (64 * 1024); // Maximum bytes to cache if sa //###################################################################### // V3File Internal state -class V3FileDependImp { +class V3FileDependImp final { // TYPES - class DependFile { + class DependFile final { // A single file bool m_target; // True if write, else read - bool m_exists; + bool m_exists = true; string m_filename; // Filename struct stat m_stat; // Stat information public: DependFile(const string& filename, bool target) : m_target{target} - , m_exists{true} , m_filename{filename} { m_stat.st_ctime = 0; m_stat.st_mtime = 0; } - ~DependFile() {} + ~DependFile() = default; const string& filename() const { return m_filename; } bool target() const { return m_target; } bool exists() const { return m_exists; } @@ -160,12 +159,12 @@ inline void V3FileDependImp::writeDepend(const string& filename) { if (!i.target()) *ofp << i.filename() << " "; } - *ofp << endl; + *ofp << '\n'; if (v3Global.opt.makePhony()) { - *ofp << endl; + *ofp << '\n'; for (const DependFile& i : m_filenameList) { - if (!i.target()) *ofp << i.filename() << ":" << endl; + if (!i.target()) *ofp << i.filename() << ":\n"; } } } @@ -184,9 +183,8 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm string cmdline = stripQuotes(cmdlineIn); *ofp << "# DESCR" - << "IPTION: Verilator output: Timestamp data for --skip-identical. Delete at will." - << endl; - *ofp << "C \"" << cmdline << "\"" << endl; + << "IPTION: Verilator output: Timestamp data for --skip-identical. Delete at will.\n"; + *ofp << "C \"" << cmdline << "\"\n"; for (std::set::iterator iter = m_filenameList.begin(); iter != m_filenameList.end(); ++iter) { @@ -210,7 +208,7 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm *ofp << " " << std::setw(11) << iter->mstime(); *ofp << " " << std::setw(11) << iter->mnstime(); *ofp << " \"" << iter->filename() << "\""; - *ofp << endl; + *ofp << '\n'; } } @@ -329,7 +327,7 @@ void V3File::createMakeDir() { //###################################################################### // VInFilterImp -class VInFilterImp { +class VInFilterImp final { typedef std::map FileContentsMap; typedef VInFilter::StrList StrList; @@ -951,7 +949,7 @@ void V3OutCFile::putsGuard() { //###################################################################### // VIdProtect -class VIdProtectImp { +class VIdProtectImp final { // MEMBERS typedef std::map IdMap; IdMap m_nameMap; // Map of old name into new name @@ -972,7 +970,7 @@ public: passthru("vlTOPp"); passthru("vlSymsp"); } - ~VIdProtectImp() {} + ~VIdProtectImp() = default; // METHODS string passthru(const string& old) { if (!v3Global.opt.protectIds()) return old; diff --git a/src/V3File.h b/src/V3File.h index 98145475e..c4a176150 100644 --- a/src/V3File.h +++ b/src/V3File.h @@ -31,7 +31,7 @@ //============================================================================ // V3File: Create streams, recording dependency information -class V3File { +class V3File final { public: static std::ifstream* new_ifstream(const string& filename) { addSrcDepend(filename); @@ -76,7 +76,7 @@ public: class VInFilterImp; -class VInFilter { +class VInFilter final { public: // TYPES typedef std::list StrList; @@ -99,7 +99,7 @@ public: //============================================================================ // V3OutFormatter: A class for automatic indentation of C++ or Verilog code. -class V3OutFormatter { +class V3OutFormatter VL_NOT_FINAL { // TYPES static constexpr int MAXSPACE = 80; // After this indent, stop indenting more public: @@ -130,7 +130,7 @@ private: public: V3OutFormatter(const string& filename, Language lang); - virtual ~V3OutFormatter() {} + virtual ~V3OutFormatter() = default; // ACCESSORS string filename() const { return m_filename; } int column() const { return m_column; } @@ -176,7 +176,7 @@ public: //============================================================================ // V3OutFile: A class for printing to a file, with automatic indentation of C++ code. -class V3OutFile : public V3OutFormatter { +class V3OutFile VL_NOT_FINAL : public V3OutFormatter { // MEMBERS FILE* m_fp; @@ -190,7 +190,7 @@ private: virtual void putcOutput(char chr) override { fputc(chr, m_fp); } }; -class V3OutCFile : public V3OutFile { +class V3OutCFile VL_NOT_FINAL : public V3OutFile { int m_guard = false; // Created header guard int m_private; // 1 = Most recently emitted private:, 2 = public: public: @@ -198,7 +198,7 @@ public: : V3OutFile{filename, V3OutFormatter::LA_C} { resetPrivate(); } - virtual ~V3OutCFile() override {} + virtual ~V3OutCFile() override = default; virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); } virtual void putsIntTopInclude() { putsForceIncs(); } virtual void putsGuard(); @@ -218,11 +218,11 @@ public: } }; -class V3OutScFile : public V3OutCFile { +class V3OutScFile final : public V3OutCFile { public: explicit V3OutScFile(const string& filename) : V3OutCFile{filename} {} - virtual ~V3OutScFile() override {} + virtual ~V3OutScFile() override = default; virtual void putsHeader() override { puts("// Verilated -*- SystemC -*-\n"); } virtual void putsIntTopInclude() override { putsForceIncs(); @@ -231,29 +231,29 @@ public: } }; -class V3OutVFile : public V3OutFile { +class V3OutVFile final : public V3OutFile { public: explicit V3OutVFile(const string& filename) : V3OutFile{filename, V3OutFormatter::LA_VERILOG} {} - virtual ~V3OutVFile() override {} + virtual ~V3OutVFile() override = default; virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); } }; -class V3OutXmlFile : public V3OutFile { +class V3OutXmlFile final : public V3OutFile { public: explicit V3OutXmlFile(const string& filename) : V3OutFile{filename, V3OutFormatter::LA_XML} { blockIndent(2); } - virtual ~V3OutXmlFile() override {} + virtual ~V3OutXmlFile() override = default; virtual void putsHeader() { puts("\n"); } }; -class V3OutMkFile : public V3OutFile { +class V3OutMkFile final : public V3OutFile { public: explicit V3OutMkFile(const string& filename) : V3OutFile{filename, V3OutFormatter::LA_MK} {} - virtual ~V3OutMkFile() override {} + virtual ~V3OutMkFile() override = default; virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); } // No automatic indentation yet. void puts(const char* strg) { putsNoTracking(strg); } @@ -265,7 +265,7 @@ public: class VIdProtectImp; -class VIdProtect { +class VIdProtect final { public: // METHODS // Rename to a new encoded string (unless earlier passthru'ed) diff --git a/src/V3FileLine.cpp b/src/V3FileLine.cpp index 5d048f101..a68d2348d 100644 --- a/src/V3FileLine.cpp +++ b/src/V3FileLine.cpp @@ -143,14 +143,7 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp) { // FileLine class functions // Sort of a singleton -FileLine::FileLine(FileLine::EmptySecret) - : m_firstLineno{0} - , m_firstColumn{0} - , m_lastLineno{0} - , m_lastColumn{0} - , m_contentLineno{0} - , m_contentp{nullptr} - , m_parent{nullptr} { +FileLine::FileLine(FileLine::EmptySecret) { m_filenameno = singleton().nameToNumber(FileLine::builtInFilename()); m_warnOn = 0; diff --git a/src/V3FileLine.h b/src/V3FileLine.h index 757a4275c..0e992d311 100644 --- a/src/V3FileLine.h +++ b/src/V3FileLine.h @@ -37,7 +37,7 @@ class FileLine; //! This singleton class contains tables of data that are unchanging in each //! source file (each with its own unique filename number). -class FileLineSingleton { +class FileLineSingleton final { // TYPES typedef std::map FileNameNumMap; // MEMBERS @@ -45,8 +45,8 @@ class FileLineSingleton { std::deque m_names; // filename text for each filenameno std::deque m_languages; // language for each filenameno // CONSTRUCTORS - FileLineSingleton() {} - ~FileLineSingleton() {} + FileLineSingleton() = default; + ~FileLineSingleton() = default; protected: friend class FileLine; @@ -64,7 +64,7 @@ protected: }; //! All source lines from a file/stream, to enable errors to show sources -class VFileContent { +class VFileContent final { // MEMBERS int m_id; // Content ID number std::deque m_lines; // Source text lines @@ -73,7 +73,7 @@ public: static int s_id = 0; m_id = ++s_id; } - ~VFileContent() {} + ~VFileContent() = default; // METHODS void pushText(const string& text); // Add arbitrary text (need not be line-by-line) string getLine(int lineno) const; @@ -87,22 +87,22 @@ std::ostream& operator<<(std::ostream& os, VFileContent* contentp); //! This class is instantiated for every source code line (potentially //! millions). To save space, per-file information (e.g. filename, source //! language is held in tables in the FileLineSingleton class. -class FileLine { +class FileLine final { // CONSTANTS static constexpr unsigned SHOW_SOURCE_MAX_LENGTH = 400; // Don't show source lines > this long // MEMBERS // Columns here means number of chars from beginning (i.e. tabs count as one) - int m_firstLineno; // `line corrected token's first line number - int m_firstColumn; // `line corrected token's first column number - int m_lastLineno; // `line corrected token's last line number - int m_lastColumn; // `line corrected token's last column number + int m_firstLineno = 0; // `line corrected token's first line number + int m_firstColumn = 0; // `line corrected token's first column number + int m_lastLineno = 0; // `line corrected token's last line number + int m_lastColumn = 0; // `line corrected token's last column number int m_filenameno; // `line corrected filename number - int m_contentLineno; // Line number within source stream - VFileContent* m_contentp; // Source text contents line is within - FileLine* m_parent; // Parent line that included this line + int m_contentLineno = 0; // Line number within source stream + VFileContent* m_contentp = nullptr; // Source text contents line is within + FileLine* m_parent = nullptr; // Parent line that included this line std::bitset m_warnOn; - bool m_waive; // Waive warning + bool m_waive = false; // Waive warning protected: // User routines should never need to change line numbers @@ -126,16 +126,8 @@ private: public: explicit FileLine(const string& filename) - : m_firstLineno{0} - , m_firstColumn{0} - , m_lastLineno{0} - , m_lastColumn{0} - , m_filenameno{singleton().nameToNumber(filename)} - , m_contentLineno{0} - , m_contentp{nullptr} - , m_parent{nullptr} - , m_warnOn{defaultFileLine().m_warnOn} - , m_waive{false} {} + : m_filenameno{singleton().nameToNumber(filename)} + , m_warnOn{defaultFileLine().m_warnOn} {} explicit FileLine(FileLine* fromp) : m_firstLineno{fromp->m_firstLineno} , m_firstColumn{fromp->m_firstColumn} @@ -151,7 +143,7 @@ public: explicit FileLine(EmptySecret); FileLine* copyOrSameFileLine(); static void deleteAllRemaining(); - ~FileLine() {} + ~FileLine() = default; #ifdef VL_LEAK_CHECKS static void* operator new(size_t size); static void operator delete(void* obj, size_t size); diff --git a/src/V3Gate.cpp b/src/V3Gate.cpp index 3d53fb356..c14bb648d 100644 --- a/src/V3Gate.cpp +++ b/src/V3Gate.cpp @@ -43,7 +43,7 @@ constexpr int GATE_DEDUP_MAX_DEPTH = 20; //###################################################################### -class GateBaseVisitor : public AstNVisitor { +class GateBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: VL_DEBUG_FUNC; // Declare debug() }; @@ -52,12 +52,12 @@ public: class GateLogicVertex; class GateVarVertex; -class GateGraphBaseVisitor { +class GateGraphBaseVisitor VL_NOT_FINAL { public: V3Graph* m_graphp; // Graph this class is visiting explicit GateGraphBaseVisitor(V3Graph* graphp) : m_graphp{graphp} {} - virtual ~GateGraphBaseVisitor() {} + virtual ~GateGraphBaseVisitor() = default; virtual VNUser visit(GateLogicVertex* vertexp, VNUser vu = VNUser(0)) = 0; virtual VNUser visit(GateVarVertex* vertexp, VNUser vu = VNUser(0)) = 0; VL_DEBUG_FUNC; // Declare debug() @@ -66,7 +66,7 @@ public: //###################################################################### // Support classes -class GateEitherVertex : public V3GraphVertex { +class GateEitherVertex VL_NOT_FINAL : public V3GraphVertex { AstScope* m_scopep; // Scope vertex refers to bool m_reducible = true; // True if this node should be able to be eliminated bool m_dedupable = true; // True if this node should be able to be deduped @@ -75,7 +75,7 @@ public: GateEitherVertex(V3Graph* graphp, AstScope* scopep) : V3GraphVertex{graphp} , m_scopep{scopep} {} - virtual ~GateEitherVertex() override {} + virtual ~GateEitherVertex() override = default; // ACCESSORS virtual string dotStyle() const override { return m_consumed ? "" : "dotted"; } AstScope* scopep() const { return m_scopep; } @@ -123,7 +123,7 @@ public: } }; -class GateVarVertex : public GateEitherVertex { +class GateVarVertex final : public GateEitherVertex { AstVarScope* m_varScp; bool m_isTop = false; bool m_isClock = false; @@ -133,7 +133,7 @@ public: GateVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : GateEitherVertex{graphp, scopep} , m_varScp{varScp} {} - virtual ~GateVarVertex() override {} + virtual ~GateVarVertex() override = default; // ACCESSORS AstVarScope* varScp() const { return m_varScp; } virtual string name() const override { return (cvtToHex(m_varScp) + " " + varScp()->name()); } @@ -163,7 +163,7 @@ public: } }; -class GateLogicVertex : public GateEitherVertex { +class GateLogicVertex final : public GateEitherVertex { AstNode* m_nodep; AstActive* m_activep; // Under what active; nullptr is ok (under cfunc or such) bool m_slow; // In slow block @@ -174,7 +174,7 @@ public: , m_nodep{nodep} , m_activep{activep} , m_slow{slow} {} - virtual ~GateLogicVertex() override {} + virtual ~GateLogicVertex() override = default; // ACCESSORS virtual string name() const override { return (cvtToHex(m_nodep) + "@" + scopep()->prettyName()); @@ -192,7 +192,7 @@ public: //###################################################################### // Is this a simple math expression with a single input and single output? -class GateOkVisitor : public GateBaseVisitor { +class GateOkVisitor final : public GateBaseVisitor { private: // RETURN STATE bool m_isSimple = true; // Set false when we know it isn't simple @@ -291,7 +291,7 @@ public: } if (debug() >= 9 && !m_isSimple) nodep->dumpTree(cout, " gate!Ok: "); } - virtual ~GateOkVisitor() override {} + virtual ~GateOkVisitor() override = default; // PUBLIC METHODS bool isSimple() const { return m_isSimple; } AstNode* substTree() const { return m_substTreep; } @@ -301,7 +301,7 @@ public: //###################################################################### // Gate class functions -class GateVisitor : public GateBaseVisitor { +class GateVisitor final : public GateBaseVisitor { private: // NODE STATE // Entire netlist: @@ -467,9 +467,6 @@ private: } } } - virtual void visit(AstAlways* nodep) override { - iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), nullptr); - } virtual void visit(AstAlwaysPublic* nodep) override { VL_RESTORER(m_inSlow); { @@ -489,10 +486,10 @@ private: } m_inSenItem = false; } - virtual void visit(AstInitial* nodep) override { + virtual void visit(AstNodeProcedure* nodep) override { VL_RESTORER(m_inSlow); { - m_inSlow = true; + m_inSlow = VN_IS(nodep, Initial) || VN_IS(nodep, Final); iterateNewStmt(nodep, (nodep->isJustOneBodyStmt() ? nullptr : "Multiple Stmts"), nullptr); } @@ -810,10 +807,10 @@ void GateVisitor::warnSignals() { vscp->varp()->user2(true); // Warn only once per signal vscp->v3warn(SYNCASYNCNET, "Signal flopped as both synchronous and async: " - << vscp->prettyNameQ() << endl - << ap->warnOther() << "... Location of async usage" << endl - << ap->warnContextPrimary() << endl - << sp->warnOther() << "... Location of sync usage" << endl + << vscp->prettyNameQ() << '\n' + << ap->warnOther() << "... Location of async usage\n" + << ap->warnContextPrimary() << '\n' + << sp->warnOther() << "... Location of sync usage\n" << sp->warnContextSecondary()); } } @@ -826,7 +823,7 @@ void GateVisitor::warnSignals() { class GateDedupeVarVisitor; -class GateElimVisitor : public GateBaseVisitor { +class GateElimVisitor final : public GateBaseVisitor { private: // NODE STATE // STATE @@ -870,7 +867,7 @@ private: public: // CONSTRUCTORS - virtual ~GateElimVisitor() override {} + virtual ~GateElimVisitor() override = default; GateElimVisitor(AstNode* nodep, AstVarScope* varscp, AstNode* replaceTreep, GateDedupeVarVisitor* varVisp) { UINFO(9, " elimvisitor " << nodep << endl); @@ -903,10 +900,10 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode* //###################################################################### // Auxiliary hash class for GateDedupeVarVisitor -class GateDedupeHash : public V3HashedUserSame { +class GateDedupeHash final : public V3HashedUserSame { public: // TYPES - typedef std::set NodeSet; + typedef std::unordered_set NodeSet; private: // NODE STATE @@ -939,7 +936,7 @@ private: } public: - GateDedupeHash() {} + GateDedupeHash() = default; virtual ~GateDedupeHash() override { if (v3Global.opt.debugCheck()) check(); } @@ -1021,7 +1018,7 @@ public: //###################################################################### // Have we seen the rhs of this assign before? -class GateDedupeVarVisitor : public GateBaseVisitor { +class GateDedupeVarVisitor final : public GateBaseVisitor { // Given a node, it is visited to try to find the AstNodeAssign under // it that can used for dedupe. // Right now, only the following node trees are supported for dedupe. @@ -1086,8 +1083,8 @@ private: public: // CONSTRUCTORS - GateDedupeVarVisitor() {} - virtual ~GateDedupeVarVisitor() override {} + GateDedupeVarVisitor() = default; + virtual ~GateDedupeVarVisitor() override = default; // PUBLIC METHODS AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) { m_assignp = nullptr; @@ -1121,7 +1118,7 @@ void GateElimVisitor::hashReplace(AstNode* oldp, AstNode* newp) { //###################################################################### // Recurse through the graph, looking for duplicate expressions on the rhs of an assign -class GateDedupeGraphVisitor : public GateGraphBaseVisitor { +class GateDedupeGraphVisitor final : public GateGraphBaseVisitor { private: // NODE STATE // AstVarScope::user2p -> bool: already visited @@ -1248,7 +1245,7 @@ void GateVisitor::dedupe() { //###################################################################### // Recurse through the graph, try to merge assigns -class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor { +class GateMergeAssignsGraphVisitor final : public GateGraphBaseVisitor { private: // NODE STATE AstNodeAssign* m_assignp = nullptr; @@ -1378,7 +1375,7 @@ void GateVisitor::mergeAssigns() { //###################################################################### // Find a var's offset in a concatenation -class GateConcatVisitor : public GateBaseVisitor { +class GateConcatVisitor final : public GateBaseVisitor { private: // STATE AstVarScope* m_vscp = nullptr; // Varscope we're trying to find @@ -1409,8 +1406,8 @@ private: public: // CONSTRUCTORS - GateConcatVisitor() {} - virtual ~GateConcatVisitor() override {} + GateConcatVisitor() = default; + virtual ~GateConcatVisitor() override = default; // PUBLIC METHODS bool concatOffset(AstConcat* concatp, AstVarScope* vscp, int& offsetr) { m_vscp = vscp; @@ -1429,17 +1426,17 @@ public: //###################################################################### // Recurse through the graph, looking for clock vectors to bypass -class GateClkDecompState { +class GateClkDecompState final { public: int m_offset; AstVarScope* m_last_vsp; GateClkDecompState(int offset, AstVarScope* vsp) : m_offset{offset} , m_last_vsp{vsp} {} - virtual ~GateClkDecompState() {} + virtual ~GateClkDecompState() = default; }; -class GateClkDecompGraphVisitor : public GateGraphBaseVisitor { +class GateClkDecompGraphVisitor final : public GateGraphBaseVisitor { private: // NODE STATE // AstVarScope::user2p -> bool: already visited @@ -1571,7 +1568,7 @@ void GateVisitor::decomposeClkVectors() { //###################################################################### // Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default) -class GateDeassignVisitor : public GateBaseVisitor { +class GateDeassignVisitor final : public GateBaseVisitor { private: // VISITORS virtual void visit(AstVarScope* nodep) override { @@ -1591,7 +1588,7 @@ private: public: // CONSTRUCTORS explicit GateDeassignVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~GateDeassignVisitor() override {} + virtual ~GateDeassignVisitor() override = default; }; //###################################################################### diff --git a/src/V3Gate.h b/src/V3Gate.h index 4248ce6f8..18ab97f16 100644 --- a/src/V3Gate.h +++ b/src/V3Gate.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Gate { +class V3Gate final { public: static void gateAll(AstNetlist* nodep); }; diff --git a/src/V3GenClk.cpp b/src/V3GenClk.cpp index 0aa972080..b8acc7430 100644 --- a/src/V3GenClk.cpp +++ b/src/V3GenClk.cpp @@ -29,7 +29,7 @@ //###################################################################### // GenClk state, as a visitor of each AstNode -class GenClkBaseVisitor : public AstNVisitor { +class GenClkBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: VL_DEBUG_FUNC; // Declare debug() }; @@ -37,7 +37,7 @@ protected: //###################################################################### // GenClk Read -class GenClkRenameVisitor : public GenClkBaseVisitor { +class GenClkRenameVisitor final : public GenClkBaseVisitor { private: // NODE STATE // Cleared on top scope @@ -121,13 +121,13 @@ public: : m_topModp{topModp} { iterate(nodep); } - virtual ~GenClkRenameVisitor() override {} + virtual ~GenClkRenameVisitor() override = default; }; //###################################################################### // GenClk Read -class GenClkReadVisitor : public GenClkBaseVisitor { +class GenClkReadVisitor final : public GenClkBaseVisitor { private: // NODE STATE // Cleared on top scope @@ -214,7 +214,7 @@ private: public: // CONSTRUCTORS explicit GenClkReadVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~GenClkReadVisitor() override {} + virtual ~GenClkReadVisitor() override = default; }; //###################################################################### diff --git a/src/V3GenClk.h b/src/V3GenClk.h index 38d4c7ec6..850f0cec0 100644 --- a/src/V3GenClk.h +++ b/src/V3GenClk.h @@ -25,7 +25,7 @@ //============================================================================ -class V3GenClk { +class V3GenClk final { public: static void genClkAll(AstNetlist* nodep); }; diff --git a/src/V3Global.h b/src/V3Global.h index ec4b6d0f1..f9fff4eb6 100644 --- a/src/V3Global.h +++ b/src/V3Global.h @@ -61,16 +61,16 @@ public: //###################################################################### -class VWidthMinUsage { +class VWidthMinUsage final { public: enum en : uint8_t { LINT_WIDTH, MATCHES_WIDTH, VERILOG_WIDTH }; enum en m_e; - inline VWidthMinUsage() + VWidthMinUsage() : m_e{LINT_WIDTH} {} // cppcheck-suppress noExplicitConstructor - inline VWidthMinUsage(en _e) + VWidthMinUsage(en _e) : m_e{_e} {} - explicit inline VWidthMinUsage(int _e) + explicit VWidthMinUsage(int _e) : m_e(static_cast(_e)) {} // Need () or GCC 4.8 false warning operator en() const { return m_e; } }; @@ -87,7 +87,7 @@ inline bool operator==(VWidthMinUsage::en lhs, const VWidthMinUsage& rhs) { //###################################################################### // V3Global - The top level class for the entire program -class V3Global { +class V3Global final { // Globals AstNetlist* m_rootp; // Root of entire netlist V3HierBlockPlan* m_hierPlanp; // Hierarchical verilation plan, nullptr unless hier_block @@ -95,6 +95,7 @@ class V3Global { int m_debugFileNumber = 0; // Number to append to debug files created bool m_assertDTypesResolved = false; // Tree should have dtypep()'s + bool m_assertScoped = false; // Tree is scoped bool m_constRemoveXs = false; // Const needs to strip any Xs bool m_needHeavy = false; // Need verilated_heavy.h include bool m_needTraceDumper = false; // Need __Vm_dumperp in symbols @@ -125,6 +126,7 @@ public: AstNetlist* rootp() const { return m_rootp; } VWidthMinUsage widthMinUsage() const { return m_widthMinUsage; } bool assertDTypesResolved() const { return m_assertDTypesResolved; } + bool assertScoped() const { return m_assertScoped; } // METHODS void readFiles(); @@ -132,6 +134,7 @@ public: static void dumpCheckGlobalTree(const string& stagename, int newNumber = 0, bool doDump = true); void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; } + void assertScoped(bool flag) { m_assertScoped = flag; } void widthMinUsage(const VWidthMinUsage& flag) { m_widthMinUsage = flag; } bool constRemoveXs() const { return m_constRemoveXs; } void constRemoveXs(bool flag) { m_constRemoveXs = flag; } diff --git a/src/V3Graph.cpp b/src/V3Graph.cpp index 8001d55b6..518c1ce70 100644 --- a/src/V3Graph.cpp +++ b/src/V3Graph.cpp @@ -279,7 +279,7 @@ void V3Graph::dump(std::ostream& os) { for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp = vertexp->verticesNextp()) { os << "\tNode: " << vertexp->name(); if (vertexp->color()) os << " color=" << vertexp->color(); - os << endl; + os << '\n'; // Print edges for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) { dumpEdge(os, vertexp, edgep); @@ -296,7 +296,7 @@ void V3Graph::dumpEdge(std::ostream& os, V3GraphVertex* vertexp, V3GraphEdge* ed if (edgep->fromp() == vertexp) os << "-> " << edgep->top()->name(); if (edgep->top() == vertexp) os << "<- " << edgep->fromp()->name(); if (edgep->cutable()) os << " [CUTABLE]"; - os << endl; + os << '\n'; } } @@ -335,7 +335,7 @@ void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) const { // We use a map here, as we don't want to corrupt anything (userp) in the graph, // and we don't care if this is slow. - std::map numMap; + std::unordered_map numMap; // Print vertices int n = 0; diff --git a/src/V3Graph.h b/src/V3Graph.h index c8d0b2431..4ac788646 100644 --- a/src/V3Graph.h +++ b/src/V3Graph.h @@ -45,7 +45,7 @@ typedef bool (*V3EdgeFuncP)(const V3GraphEdge* edgep); // it's useful to have algorithms that can walk in either direction, hence // some methods take GraphWay to programmatically select the direction. -class GraphWay { +class GraphWay final { public: enum en : uint8_t { FORWARD = 0, @@ -77,7 +77,7 @@ inline bool operator==(GraphWay::en lhs, const GraphWay& rhs) { return lhs == rh //============================================================================ -class V3Graph { +class V3Graph VL_NOT_FINAL { private: // MEMBERS V3List m_vertices; // All vertices @@ -185,7 +185,7 @@ public: //============================================================================ -class V3GraphVertex { +class V3GraphVertex VL_NOT_FINAL { // Vertices may be a 'gate'/wire statement OR a variable protected: friend class V3Graph; @@ -218,7 +218,7 @@ public: virtual V3GraphVertex* clone(V3Graph* graphp) const { return new V3GraphVertex(graphp, *this); } - virtual ~V3GraphVertex() {} + virtual ~V3GraphVertex() = default; void unlinkEdges(V3Graph* graphp); void unlinkDelete(V3Graph* graphp); @@ -273,7 +273,7 @@ std::ostream& operator<<(std::ostream& os, V3GraphVertex* vertexp); //============================================================================ -class V3GraphEdge { +class V3GraphEdge VL_NOT_FINAL { // Wires/variables aren't edges. Edges have only a single to/from vertex public: // ENUMS @@ -317,7 +317,7 @@ public: virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const { return new V3GraphEdge(graphp, fromp, top, *this); } - virtual ~V3GraphEdge() {} + virtual ~V3GraphEdge() = default; // METHODS virtual string name() const { return m_fromp->name() + "->" + m_top->name(); } virtual string dotLabel() const { return ""; } diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp index 57fc442e6..858e4c22d 100644 --- a/src/V3GraphAcyc.cpp +++ b/src/V3GraphAcyc.cpp @@ -29,7 +29,7 @@ // Algorithms - acyclic // Break the minimal number of backward edges to make the graph acyclic -class GraphAcycVertex : public V3GraphVertex { +class GraphAcycVertex final : public V3GraphVertex { // user() is used for various sub-algorithm pieces V3GraphVertex* m_origVertexp; // Pointer to first vertex this represents protected: @@ -42,7 +42,7 @@ public: GraphAcycVertex(V3Graph* graphp, V3GraphVertex* origVertexp) : V3GraphVertex{graphp} , m_origVertexp{origVertexp} {} - virtual ~GraphAcycVertex() override {} + virtual ~GraphAcycVertex() override = default; V3GraphVertex* origVertexp() const { return m_origVertexp; } void setDelete() { m_deleted = true; } bool isDelete() const { return m_deleted; } @@ -53,13 +53,13 @@ public: //-------------------------------------------------------------------- -class GraphAcycEdge : public V3GraphEdge { +class GraphAcycEdge final : public V3GraphEdge { // userp() is always used to point to the head original graph edge private: typedef std::list OrigEdgeList; // List of orig edges, see also GraphAcyc's decl V3GraphEdge* origEdgep() const { OrigEdgeList* oEListp = static_cast(userp()); - if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this << endl); + if (!oEListp) v3fatalSrc("No original edge associated with acyc edge " << this); return (oEListp->front()); } @@ -67,7 +67,7 @@ public: GraphAcycEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = false) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~GraphAcycEdge() override {} + virtual ~GraphAcycEdge() override = default; // yellow=we might still cut it, else oldEdge: yellowGreen=made uncutable, red=uncutable virtual string dotColor() const override { return (cutable() ? "yellow" : origEdgep()->dotColor()); @@ -77,7 +77,7 @@ public: //-------------------------------------------------------------------- struct GraphAcycEdgeCmp { - inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { + 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 return false; @@ -87,7 +87,7 @@ struct GraphAcycEdgeCmp { //-------------------------------------------------------------------- // CLASSES -class GraphAcyc { +class GraphAcyc final { private: typedef std::list OrigEdgeList; // List of orig edges, see also GraphAcycEdge's decl @@ -155,7 +155,7 @@ private: breakEdgep->cut(); OrigEdgeList* oEListp = static_cast(breakEdgep->userp()); if (!oEListp) { - v3fatalSrc("No original edge associated with cutting edge " << breakEdgep << endl); + v3fatalSrc("No original edge associated with cutting edge " << breakEdgep); } // The breakGraph edge may represent multiple real edges; cut them all for (const auto& origEdgep : *oEListp) { diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp index 504c719cf..e0046bd21 100644 --- a/src/V3GraphAlg.cpp +++ b/src/V3GraphAlg.cpp @@ -69,7 +69,7 @@ void V3Graph::deleteCutableOnlyEdges() { //###################################################################### // Algorithms - weakly connected components -class GraphRemoveRedundant : GraphAlg<> { +class GraphRemoveRedundant final : GraphAlg<> { bool m_sumWeights; ///< Sum, rather then maximize weights private: void main() { @@ -123,7 +123,7 @@ public: , m_sumWeights{sumWeights} { main(); } - ~GraphRemoveRedundant() {} + ~GraphRemoveRedundant() = default; }; void V3Graph::removeRedundantEdges(V3EdgeFuncP edgeFuncp) { @@ -137,7 +137,7 @@ void V3Graph::removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp) { //###################################################################### // Algorithms - remove transitive -class GraphAlgRemoveTransitiveEdges : GraphAlg<> { +class GraphAlgRemoveTransitiveEdges final : GraphAlg<> { public: explicit GraphAlgRemoveTransitiveEdges(V3Graph* graphp) : GraphAlg<>(graphp, nullptr) {} @@ -168,7 +168,7 @@ void V3Graph::removeTransitiveEdges() { GraphAlgRemoveTransitiveEdges(this).go() //###################################################################### // Algorithms - weakly connected components -class GraphAlgWeakly : GraphAlg<> { +class GraphAlgWeakly final : GraphAlg<> { private: void main() { // Initialize state @@ -200,7 +200,7 @@ public: : GraphAlg<>(graphp, edgeFuncp) { main(); } - ~GraphAlgWeakly() {} + ~GraphAlgWeakly() = default; }; void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgWeakly(this, edgeFuncp); } @@ -209,7 +209,7 @@ void V3Graph::weaklyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgWeakly(this, edge //###################################################################### // Algorithms - strongly connected components -class GraphAlgStrongly : GraphAlg<> { +class GraphAlgStrongly final : GraphAlg<> { private: uint32_t m_currentDfs; // DFS count std::vector m_callTrace; // List of everything we hit processing so far @@ -288,7 +288,7 @@ public: m_currentDfs = 0; main(); } - ~GraphAlgStrongly() {} + ~GraphAlgStrongly() = default; }; void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgStrongly(this, edgeFuncp); } @@ -297,7 +297,7 @@ void V3Graph::stronglyConnected(V3EdgeFuncP edgeFuncp) { GraphAlgStrongly(this, //###################################################################### // Algorithms - ranking -class GraphAlgRank : GraphAlg<> { +class GraphAlgRank final : GraphAlg<> { private: void main() { // Rank each vertex, ignoring cutable edges @@ -339,7 +339,7 @@ public: : GraphAlg<>{graphp, edgeFuncp} { main(); } - ~GraphAlgRank() {} + ~GraphAlgRank() = default; }; void V3Graph::rank() { GraphAlgRank(this, &V3GraphEdge::followAlwaysTrue); } @@ -350,7 +350,7 @@ void V3Graph::rank(V3EdgeFuncP edgeFuncp) { GraphAlgRank(this, edgeFuncp); } //###################################################################### // Algorithms - ranking -class GraphAlgRLoops : GraphAlg<> { +class GraphAlgRLoops final : GraphAlg<> { private: std::vector m_callTrace; // List of everything we hit processing so far bool m_done; // Exit algorithm @@ -393,7 +393,7 @@ public: m_done = false; main(vertexp); } - ~GraphAlgRLoops() {} + ~GraphAlgRLoops() = default; }; void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { @@ -404,7 +404,7 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) { //###################################################################### // Algorithms - subtrees -class GraphAlgSubtrees : GraphAlg<> { +class GraphAlgSubtrees final : GraphAlg<> { private: V3Graph* m_loopGraphp; @@ -441,7 +441,7 @@ public: m_graphp->userClearEdges(); (void)vertexIterateAll(vertexp); } - ~GraphAlgSubtrees() {} + ~GraphAlgSubtrees() = default; }; //! Report the entire connected graph with a loop or loops @@ -469,12 +469,12 @@ void V3Graph::makeEdgesNonCutable(V3EdgeFuncP edgeFuncp) { // Algorithms - sorting struct GraphSortVertexCmp { - inline bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { + bool operator()(const V3GraphVertex* lhsp, const V3GraphVertex* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } }; struct GraphSortEdgeCmp { - inline bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { + bool operator()(const V3GraphEdge* lhsp, const V3GraphEdge* rhsp) const { return lhsp->sortCmp(rhsp) < 0; } }; diff --git a/src/V3GraphAlg.h b/src/V3GraphAlg.h index 3d7abaea5..b25b785f8 100644 --- a/src/V3GraphAlg.h +++ b/src/V3GraphAlg.h @@ -28,7 +28,7 @@ // For internal use, most graph algorithms use this as a base class template // Or sometimes const V3Graph -class GraphAlg { +class GraphAlg VL_NOT_FINAL { protected: T_Graph* m_graphp; // Graph we're operating upon V3EdgeFuncP m_edgeFuncp; // Function that says we follow this edge @@ -36,7 +36,7 @@ protected: GraphAlg(T_Graph* graphp, V3EdgeFuncP edgeFuncp) : m_graphp{graphp} , m_edgeFuncp{edgeFuncp} {} - ~GraphAlg() {} + ~GraphAlg() = default; // METHODS inline bool followEdge(V3GraphEdge* edgep) { return (edgep->weight() && (m_edgeFuncp)(edgep)); diff --git a/src/V3GraphDfa.cpp b/src/V3GraphDfa.cpp index 2c8f0bb48..3d193aca3 100644 --- a/src/V3GraphDfa.cpp +++ b/src/V3GraphDfa.cpp @@ -51,7 +51,7 @@ DfaVertex* DfaGraph::findStart() { // Algorithms - convert NFA to a DFA // Uses the Subset Construction Algorithm -class GraphNfaToDfa : GraphAlg<> { +class GraphNfaToDfa final : GraphAlg<> { // We have two types of nodes in one graph, NFA and DFA nodes. // Edges from NFA to NFA come from the user, and indicate input or epsilon transitions // Edges from DFA to NFA indicate the NFA from which that DFA was formed. @@ -294,7 +294,7 @@ private: UINFO(9, " On dfaState " << dfaStatep << endl); // From this dfaState, what corresponding nfaStates have what inputs? - std::set inputs; + std::unordered_set inputs; // Foreach NFA state (this DFA state was formed from) for (V3GraphEdge* dfaEdgep = dfaStatep->outBeginp(); dfaEdgep; dfaEdgep = dfaEdgep->outNextp()) { @@ -368,7 +368,7 @@ public: m_step = 0; main(); } - ~GraphNfaToDfa() {} + ~GraphNfaToDfa() = default; }; void DfaGraph::nfaToDfa() { GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); } @@ -379,7 +379,7 @@ void DfaGraph::nfaToDfa() { GraphNfaToDfa(this, &V3GraphEdge::followAlwaysTrue); // // Scan the DFA, cleaning up trailing states. -class DfaGraphReduce : GraphAlg<> { +class DfaGraphReduce final : GraphAlg<> { private: // METHODS #ifdef VL_CPPCHECK @@ -502,7 +502,7 @@ public: optimize_no_outbound(); if (debug() >= 6) m_graphp->dumpDotFilePrefixed("opt_noout"); } - ~DfaGraphReduce() {} + ~DfaGraphReduce() = default; }; void DfaGraph::dfaReduce() { DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue); } @@ -527,7 +527,7 @@ void DfaGraph::dfaReduce() { DfaGraphReduce(this, &V3GraphEdge::followAlwaysTrue // The user's old accept is now the new accept. This is important as // we want the virtual type of it to be intact. -class DfaGraphComplement : GraphAlg<> { +class DfaGraphComplement final : GraphAlg<> { private: // MEMBERS DfaVertex* m_tempNewerReject; @@ -598,7 +598,7 @@ public: VL_DO_CLEAR(m_tempNewerReject->unlinkDelete(graphp()), m_tempNewerReject = nullptr); if (debug() >= 6) m_graphp->dumpDotFilePrefixed("comp_out"); } - ~DfaGraphComplement() {} + ~DfaGraphComplement() = default; VL_UNCOPYABLE(DfaGraphComplement); }; diff --git a/src/V3GraphDfa.h b/src/V3GraphDfa.h index a2ec64bd8..3c726995d 100644 --- a/src/V3GraphDfa.h +++ b/src/V3GraphDfa.h @@ -58,11 +58,11 @@ class DfaEdge; /// | ^\----[epsilon]<-------/ | /// \->[epsilon]-----------------------------------------/ -class DfaGraph : public V3Graph { +class DfaGraph final : public V3Graph { public: // CONSTRUCTORS - DfaGraph() {} - virtual ~DfaGraph() override {} + DfaGraph() = default; + virtual ~DfaGraph() override = default; // METHODS /// Find start node DfaVertex* findStart(); @@ -77,7 +77,7 @@ public: //============================================================================= // Vertex -class DfaVertex : public V3GraphVertex { +class DfaVertex VL_NOT_FINAL : public V3GraphVertex { // Each DFA state is captured in this vertex. // Start and accepting are members, rather than the more intuitive // subclasses, as subclassing them would make it harder to inherit from here. @@ -93,7 +93,7 @@ public: virtual DfaVertex* clone(DfaGraph* graphp) { return new DfaVertex(graphp, start(), accepting()); } - virtual ~DfaVertex() override {} + virtual ~DfaVertex() override = default; // ACCESSORS virtual string dotShape() const override { return (accepting() ? "doublecircle" : ""); } virtual string dotColor() const override { @@ -113,7 +113,7 @@ typedef VNUser DfaInput; //============================================================================ // Edge types -class DfaEdge : public V3GraphEdge { +class DfaEdge final : public V3GraphEdge { DfaInput m_input; bool m_complement; // Invert value when doing compare public: @@ -128,7 +128,7 @@ public: : V3GraphEdge{graphp, fromp, top, copyfrom->weight()} , m_input{copyfrom->input()} , m_complement{copyfrom->complement()} {} - virtual ~DfaEdge() override {} + virtual ~DfaEdge() override = default; // METHODS virtual string dotColor() const override { return (na() ? "yellow" : epsilon() ? "green" : "black"); diff --git a/src/V3GraphPathChecker.cpp b/src/V3GraphPathChecker.cpp index 2497f35ca..8867d2cfa 100644 --- a/src/V3GraphPathChecker.cpp +++ b/src/V3GraphPathChecker.cpp @@ -32,7 +32,7 @@ struct GraphPCNode { // // Unlike the LogicMTasks's, we have no cost info for the generic graph // accepted by GraphPathChecker, so assume each node has unit cost. - vluint32_t m_cp[GraphWay::NUM_WAYS]; + std::array m_cp; // Detect if we've seen this node before in a given recursive // operation. We'll use this in pathExistsInternal() to avoid checking @@ -44,15 +44,14 @@ struct GraphPCNode { GraphPCNode() { for (unsigned int& w : m_cp) w = 0; } - ~GraphPCNode() {} + ~GraphPCNode() = default; }; //###################################################################### // GraphPathChecker implementation GraphPathChecker::GraphPathChecker(const V3Graph* graphp, V3EdgeFuncP edgeFuncp) - : GraphAlg{graphp, edgeFuncp} - , m_generation{0} { + : GraphAlg{graphp, edgeFuncp} { for (V3GraphVertex* vxp = graphp->verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { // Setup tracking structure for each node. If delete a vertex // there would be a leak, but ok as accept only const V3Graph*'s. diff --git a/src/V3GraphPathChecker.h b/src/V3GraphPathChecker.h index e50daf064..104aa719d 100644 --- a/src/V3GraphPathChecker.h +++ b/src/V3GraphPathChecker.h @@ -29,12 +29,12 @@ /// /// The graph (or at least, the subset the algorithm sees through /// edgeFuncp) must not change during the lifetime of the checker. -class GraphPathChecker : GraphAlg { +class GraphPathChecker final : GraphAlg { // Count "generations" which increases on operations that scan through // the graph. Each node is marked with the last generation that scanned // it, to enable asserting there are no cycles, and to avoid recursing // through the same node twice while searching for a path. - vluint64_t m_generation; + vluint64_t m_generation = 0; public: // CONSTRUCTORS diff --git a/src/V3GraphStream.h b/src/V3GraphStream.h index 233184397..f7bd78cb5 100644 --- a/src/V3GraphStream.h +++ b/src/V3GraphStream.h @@ -40,7 +40,7 @@ template class GraphStream { private: // TYPES - class VxHolder { + class VxHolder final { public: // MEMBERS const V3GraphVertex* m_vxp; // [mtask] Vertex @@ -62,7 +62,7 @@ private: } }; - class VxHolderCmp { + class VxHolderCmp final { public: // MEMBERS T_Compare m_lessThan; // Sorting functor @@ -81,7 +81,7 @@ private: }; typedef std::set ReadyVertices; - typedef std::unordered_map WaitingVertices; + typedef std::map WaitingVertices; // MEMBERS VxHolderCmp m_vxHolderCmp; // Vertext comparison functor @@ -132,7 +132,7 @@ public: } } } - ~GraphStream() {} + ~GraphStream() = default; // METHODS diff --git a/src/V3GraphTest.cpp b/src/V3GraphTest.cpp index ac2f66f48..67340c5ec 100644 --- a/src/V3GraphTest.cpp +++ b/src/V3GraphTest.cpp @@ -25,7 +25,7 @@ //###################################################################### // Test class -class V3GraphTest { +class V3GraphTest VL_NOT_FINAL { protected: // MEMBERS DfaGraph m_graph; @@ -40,8 +40,8 @@ protected: } public: - V3GraphTest() {} - virtual ~V3GraphTest() {} + V3GraphTest() = default; + virtual ~V3GraphTest() = default; VL_DEBUG_FUNC; // Declare debug() void run() { runTest(); } }; @@ -50,23 +50,23 @@ public: //###################################################################### // Vertices and nodes -class V3GraphTestVertex : public V3GraphVertex { +class V3GraphTestVertex VL_NOT_FINAL : public V3GraphVertex { string m_name; public: V3GraphTestVertex(V3Graph* graphp, const string& name) : V3GraphVertex{graphp} , m_name{name} {} - virtual ~V3GraphTestVertex() override {} + virtual ~V3GraphTestVertex() override = default; // ACCESSORS virtual string name() const override { return m_name; } }; -class V3GraphTestVarVertex : public V3GraphTestVertex { +class V3GraphTestVarVertex final : public V3GraphTestVertex { public: V3GraphTestVarVertex(V3Graph* graphp, const string& name) : V3GraphTestVertex{graphp, name} {} - virtual ~V3GraphTestVarVertex() override {} + virtual ~V3GraphTestVarVertex() override = default; // ACCESSORS virtual string dotColor() const override { return "blue"; } }; @@ -75,7 +75,7 @@ public: //###################################################################### // Test vertices and nodes -class V3GraphTestStrong : public V3GraphTest { +class V3GraphTestStrong final : public V3GraphTest { public: virtual string name() override { return "strong"; } virtual void runTest() override { @@ -113,7 +113,7 @@ public: } }; -class V3GraphTestAcyc : public V3GraphTest { +class V3GraphTestAcyc final : public V3GraphTest { public: virtual string name() override { return "acyc"; } virtual void runTest() override { @@ -141,7 +141,7 @@ public: } }; -class V3GraphTestVars : public V3GraphTest { +class V3GraphTestVars final : public V3GraphTest { public: virtual string name() override { return "vars"; } virtual void runTest() override { @@ -260,19 +260,19 @@ public: //====================================================================== -class DfaTestVertex : public DfaVertex { +class DfaTestVertex final : public DfaVertex { string m_name; public: DfaTestVertex(DfaGraph* graphp, const string& name) : DfaVertex{graphp} , m_name{name} {} - virtual ~DfaTestVertex() override {} + virtual ~DfaTestVertex() override = default; // ACCESSORS virtual string name() const override { return m_name; } }; -class V3GraphTestDfa : public V3GraphTest { +class V3GraphTestDfa final : public V3GraphTest { public: virtual string name() override { return "dfa"; } @@ -321,7 +321,7 @@ public: //====================================================================== -class V3GraphTestImport : public V3GraphTest { +class V3GraphTestImport final : public V3GraphTest { #ifdef GRAPH_IMPORT void dotImport(); diff --git a/src/V3Hashed.cpp b/src/V3Hashed.cpp index 14579bc87..a72e45106 100644 --- a/src/V3Hashed.cpp +++ b/src/V3Hashed.cpp @@ -37,7 +37,7 @@ //###################################################################### // Hashed state, as a visitor of each AstNode -class HashedVisitor : public AstNVisitor { +class HashedVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -102,7 +102,7 @@ public: nodeHashIterate(const_cast(nodep)); } V3Hash finalHash() const { return m_lowerHash; } - virtual ~HashedVisitor() override {} + virtual ~HashedVisitor() override = default; }; //###################################################################### @@ -153,7 +153,7 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { const std::unique_ptr logp(V3File::new_ofstream(filename)); if (logp->fail()) v3fatal("Can't write " << filename); - std::map dist; + std::unordered_map dist; V3Hash lasthash; int num_in_bucket = 0; @@ -172,19 +172,19 @@ void V3Hashed::dumpFile(const string& filename, bool tree) { if (it == end()) break; num_in_bucket++; } - *logp << "\n*** STATS:\n" << endl; + *logp << "\n*** STATS:\n\n"; *logp << " #InBucket Occurrences\n"; for (const auto& i : dist) { - *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << endl; + *logp << " " << std::setw(9) << i.first << " " << std::setw(12) << i.second << '\n'; } - *logp << "\n*** Dump:\n" << endl; + *logp << "\n*** Dump:\n\n"; for (const auto& itr : *this) { if (lasthash != itr.first) { lasthash = itr.first; - *logp << " " << itr.first << endl; + *logp << " " << itr.first << '\n'; } - *logp << "\t" << itr.second << endl; + *logp << "\t" << itr.second << '\n'; // Dumping the entire tree may make nearly N^2 sized dumps, // because the nodes under this one may also be in the hash table! if (tree) itr.second->dumpTree(*logp, " "); diff --git a/src/V3Hashed.h b/src/V3Hashed.h index 0fc0ace5a..e8d7b6fdc 100644 --- a/src/V3Hashed.h +++ b/src/V3Hashed.h @@ -24,11 +24,11 @@ //============================================================================ -class VHashedBase { +class VHashedBase VL_NOT_FINAL { public: // CONSTRUCTORS - VHashedBase() {} - ~VHashedBase() {} + VHashedBase() = default; + ~VHashedBase() = default; // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -39,11 +39,11 @@ public: struct V3HashedUserSame { // Functor for V3Hashed::findDuplicate virtual bool isSame(AstNode*, AstNode*) = 0; - V3HashedUserSame() {} - virtual ~V3HashedUserSame() {} + V3HashedUserSame() = default; + virtual ~V3HashedUserSame() = default; }; -class V3Hashed : public VHashedBase { +class V3Hashed final : public VHashedBase { // NODE STATE // AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal) AstUser4InUse m_inuser4; @@ -60,7 +60,7 @@ private: public: // CONSTRUCTORS V3Hashed() { clear(); } - ~V3Hashed() {} + ~V3Hashed() = default; // ACCESSORS HashMmap& mmap() { return m_hashMmap; } // Return map for iteration diff --git a/src/V3HierBlock.cpp b/src/V3HierBlock.cpp index f605723fc..41f647826 100644 --- a/src/V3HierBlock.cpp +++ b/src/V3HierBlock.cpp @@ -234,13 +234,13 @@ string V3HierBlock::commandArgsFileName(bool forCMake) const { //###################################################################### // Collect how hierarchical blocks are used -class HierBlockUsageCollectVisitor : public AstNVisitor { +class HierBlockUsageCollectVisitor final : public AstNVisitor { // NODE STATE // AstNode::user1() -> bool. Processed AstUser1InUse m_inuser1; // STATE - typedef std::set ModuleSet; + typedef std::unordered_set ModuleSet; V3HierBlockPlan* const m_planp; AstModule* m_modp = nullptr; // The current module AstModule* m_hierBlockp = nullptr; // The nearest parent module that is a hierarchical block @@ -304,8 +304,6 @@ public: //###################################################################### -V3HierBlockPlan::V3HierBlockPlan() {} - bool V3HierBlockPlan::isHierBlock(const AstNodeModule* modp) const { return m_blocks.find(modp) != m_blocks.end(); } @@ -357,7 +355,8 @@ void V3HierBlockPlan::createPlan(AstNetlist* nodep) { } V3HierBlockPlan::HierVector V3HierBlockPlan::hierBlocksSorted() const { - typedef std::map> ChildrenMap; + typedef std::unordered_map> + ChildrenMap; ChildrenMap childrenOfHierBlock; HierVector sorted; diff --git a/src/V3HierBlock.h b/src/V3HierBlock.h index d5898dc34..7ce652a74 100644 --- a/src/V3HierBlock.h +++ b/src/V3HierBlock.h @@ -29,6 +29,7 @@ #include #include #include +#include #include class AstNodeModule; @@ -37,11 +38,11 @@ class AstVar; //###################################################################### -class V3HierBlock { +class V3HierBlock final { public: typedef std::vector GParams; - typedef std::set HierBlockSet; - typedef std::set NodeModuleSet; + typedef std::unordered_set HierBlockSet; + typedef std::unordered_set NodeModuleSet; private: // TYPES @@ -95,11 +96,11 @@ public: //###################################################################### // Holds relashonship between AstNodeModule and V3HierBlock -class V3HierBlockPlan { - typedef std::map HierMap; +class V3HierBlockPlan final { + typedef std::unordered_map HierMap; HierMap m_blocks; - V3HierBlockPlan(); + V3HierBlockPlan() = default; VL_UNCOPYABLE(V3HierBlockPlan); public: diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp index 01ef648fd..c72990a3a 100644 --- a/src/V3Inline.cpp +++ b/src/V3Inline.cpp @@ -44,7 +44,7 @@ static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can //###################################################################### // Inline state, as a visitor of each AstNode -class InlineMarkVisitor : public AstNVisitor { +class InlineMarkVisitor final : public AstNVisitor { private: // NODE STATE // Output @@ -74,10 +74,10 @@ private: // Within the context of a given module, LocalInstanceMap maps // from child modules to the count of each child's local instantiations. - typedef std::map LocalInstanceMap; + typedef std::unordered_map LocalInstanceMap; // We keep a LocalInstanceMap for each module in the design - std::map m_instances; + std::unordered_map m_instances; // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -153,7 +153,7 @@ private: virtual void visit(AstNodeFTaskRef* nodep) override { // Cleanup link until V3LinkDot can correct it // MethodCalls not currently supported by inliner, so keep linked - if (!nodep->packagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(nullptr); + if (!nodep->classOrPackagep() && !VN_IS(nodep, MethodCall)) nodep->taskp(nullptr); iterateChildren(nodep); } virtual void visit(AstAlways* nodep) override { @@ -233,7 +233,7 @@ public: // Using clonep(), find cell cross references. // clone() must not be called inside this visitor -class InlineCollectVisitor : public AstNVisitor { +class InlineCollectVisitor final : public AstNVisitor { private: // NODE STATE // Output: @@ -254,13 +254,13 @@ public: explicit InlineCollectVisitor(AstNodeModule* nodep) { // passed OLD module, not new one iterate(nodep); } - virtual ~InlineCollectVisitor() override {} + virtual ~InlineCollectVisitor() override = default; }; //###################################################################### // After cell is cloned, relink the new module's contents -class InlineRelinkVisitor : public AstNVisitor { +class InlineRelinkVisitor final : public AstNVisitor { private: typedef std::unordered_set StringSet; @@ -474,13 +474,13 @@ public: , m_cellp{cellp} { iterate(cloneModp); } - virtual ~InlineRelinkVisitor() override {} + virtual ~InlineRelinkVisitor() override = default; }; //###################################################################### // Inline state, as a visitor of each AstNode -class InlineVisitor : public AstNVisitor { +class InlineVisitor final : public AstNVisitor { private: // NODE STATE // Cleared entire netlist @@ -621,7 +621,7 @@ public: //###################################################################### // Track interface references under the Cell they reference -class InlineIntfRefVisitor : public AstNVisitor { +class InlineIntfRefVisitor final : public AstNVisitor { private: // NODE STATE // AstVar::user1p() // AstCell which this Var points to @@ -702,7 +702,7 @@ private: public: // CONSTRUCTORS explicit InlineIntfRefVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~InlineIntfRefVisitor() override {} + virtual ~InlineIntfRefVisitor() override = default; }; //###################################################################### diff --git a/src/V3Inline.h b/src/V3Inline.h index a45cfbe1a..dd5b591f7 100644 --- a/src/V3Inline.h +++ b/src/V3Inline.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Inline { +class V3Inline final { public: static void inlineAll(AstNetlist* nodep); }; diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp index adc210e24..c9bb8acc8 100644 --- a/src/V3Inst.cpp +++ b/src/V3Inst.cpp @@ -34,7 +34,7 @@ //###################################################################### // Inst state, as a visitor of each AstNode -class InstVisitor : public AstNVisitor { +class InstVisitor final : public AstNVisitor { private: // NODE STATE // Cleared each Cell: @@ -132,12 +132,12 @@ private: public: // CONSTRUCTORS explicit InstVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~InstVisitor() override {} + virtual ~InstVisitor() override = default; }; //###################################################################### -class InstDeModVarVisitor : public AstNVisitor { +class InstDeModVarVisitor final : public AstNVisitor { // Expand all module variables, and save names for later reference private: // STATE @@ -178,18 +178,18 @@ public: } // CONSTRUCTORS - explicit InstDeModVarVisitor() {} + InstDeModVarVisitor() = default; + virtual ~InstDeModVarVisitor() override = default; void main(AstNodeModule* nodep) { UINFO(8, " dmMODULE " << nodep << endl); m_modVarNameMap.clear(); iterate(nodep); } - virtual ~InstDeModVarVisitor() override {} }; //###################################################################### -class InstDeVisitor : public AstNVisitor { +class InstDeVisitor final : public AstNVisitor { // Find all cells with arrays, and convert to non-arrayed private: // STATE @@ -383,7 +383,7 @@ private: varrefp->name() + "__BRA__" + index + "__KET__", "", VAccess::WRITE); newp->dtypep(nodep->modVarp()->dtypep()); - newp->packagep(varrefp->packagep()); + newp->classOrPackagep(varrefp->classOrPackagep()); arrselp->addNextHere(newp); VL_DO_DANGLING(arrselp->unlinkFrBack()->deleteTree(), arrselp); } @@ -466,16 +466,16 @@ private: public: // CONSTRUCTORS explicit InstDeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~InstDeVisitor() override {} + virtual ~InstDeVisitor() override = default; }; //###################################################################### // Inst static function -class InstStatic { +class InstStatic final { private: VL_DEBUG_FUNC; // Declare debug() - InstStatic() {} // Static class + InstStatic() = default; // Static class static AstNode* extendOrSel(FileLine* fl, AstNode* rhsp, AstNode* cmpWidthp) { if (cmpWidthp->width() > rhsp->width()) { diff --git a/src/V3Inst.h b/src/V3Inst.h index 7fa389256..5b68d0a31 100644 --- a/src/V3Inst.h +++ b/src/V3Inst.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Inst { +class V3Inst final { public: static void instAll(AstNetlist* nodep); static void dearrayAll(AstNetlist* nodep); diff --git a/src/V3InstrCount.cpp b/src/V3InstrCount.cpp index 85ca8f3c9..5da14c211 100644 --- a/src/V3InstrCount.cpp +++ b/src/V3InstrCount.cpp @@ -29,7 +29,7 @@ /// we'll count instructions from either the 'if' or the 'else' branch, /// whichever is larger. We know we won't run both. -class InstrCountVisitor : public AstNVisitor { +class InstrCountVisitor final : public AstNVisitor { private: // NODE STATE // AstNode::user4() -> int. Path cost + 1, 0 means don't dump @@ -46,7 +46,7 @@ private: // TYPES // Little class to cleanly call startVisitBase/endVisitBase - class VisitBase { + class VisitBase final { private: // MEMBERS uint32_t m_savedCount; @@ -74,7 +74,7 @@ public: , m_osp{osp} { if (nodep) iterate(nodep); } - virtual ~InstrCountVisitor() override {} + virtual ~InstrCountVisitor() override = default; // METHODS uint32_t instrCount() const { return m_instrCount; } @@ -258,7 +258,7 @@ private: }; // Iterate the graph printing the critical path marked by previous visitation -class InstrCountDumpVisitor : public AstNVisitor { +class InstrCountDumpVisitor final : public AstNVisitor { private: // NODE STATE // AstNode::user4() -> int. Path cost, 0 means don't dump @@ -275,7 +275,7 @@ public: UASSERT_OBJ(osp, nodep, "Don't call if not dumping"); if (nodep) iterate(nodep); } - virtual ~InstrCountDumpVisitor() override {} + virtual ~InstrCountDumpVisitor() override = default; private: // METHODS @@ -284,7 +284,7 @@ private: ++m_depth; if (unsigned costPlus1 = nodep->user4()) { *m_osp << " " << indent() << "cost " << std::setw(6) << std::left << (costPlus1 - 1) - << " " << nodep << endl; + << " " << nodep << '\n'; iterateChildren(nodep); } --m_depth; diff --git a/src/V3InstrCount.h b/src/V3InstrCount.h index 697a69cb6..8e3d109f1 100644 --- a/src/V3InstrCount.h +++ b/src/V3InstrCount.h @@ -23,7 +23,7 @@ class AstNode; -class V3InstrCount { +class V3InstrCount final { public: // Return the estimate count of instructions we'd incur while running // code in and under nodep. diff --git a/src/V3LangCode.h b/src/V3LangCode.h index e9eb7ae4e..cdb68b03e 100644 --- a/src/V3LangCode.h +++ b/src/V3LangCode.h @@ -28,7 +28,7 @@ //! Class for the different languages supported. //! A separate file, since used both in V3Options (globally) and FileLine 9per //! file). -class V3LangCode { +class V3LangCode final { public: enum en : uint8_t { L_ERROR, // Must be first. diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h index 3764f2dce..37cc5bee9 100644 --- a/src/V3LanguageWords.h +++ b/src/V3LanguageWords.h @@ -24,7 +24,7 @@ //============================================================================ -class V3LanguageWords { +class V3LanguageWords final { // List of common reserved keywords private: typedef std::map KeywordMap; diff --git a/src/V3Life.cpp b/src/V3Life.cpp index a2ea3efd8..daa9028f5 100644 --- a/src/V3Life.cpp +++ b/src/V3Life.cpp @@ -38,7 +38,7 @@ //###################################################################### // Structure for global state -class LifeState { +class LifeState final { // NODE STATE // See below AstUser1InUse m_inuser1; @@ -50,7 +50,7 @@ public: std::vector m_unlinkps; // CONSTRUCTORS - LifeState() {} + LifeState() = default; ~LifeState() { V3Stats::addStatSum("Optimizations, Lifetime assign deletions", m_statAssnDel); V3Stats::addStatSum("Optimizations, Lifetime constant prop", m_statAssnCon); @@ -66,7 +66,7 @@ public: //###################################################################### // Structure for each variable encountered -class LifeVarEntry { +class LifeVarEntry final { // Last assignment to this varscope, nullptr if no longer relevant AstNodeAssign* m_assignp = nullptr; AstConst* m_constp = nullptr; // Known constant value @@ -92,7 +92,7 @@ public: : m_setBeforeUse{false} { consumed(); } - ~LifeVarEntry() {} + ~LifeVarEntry() = default; inline void simpleAssign(AstNodeAssign* assp) { // New simple A=.... assignment m_assignp = assp; m_constp = nullptr; @@ -116,14 +116,14 @@ public: //###################################################################### // Structure for all variables under a given meta-basic block -class LifeBlock { +class LifeBlock final { // NODE STATE // Cleared each AstIf: // AstVarScope::user1() -> int. Used in combining to detect duplicates // LIFE MAP // For each basic block, we'll make a new map of what variables that if/else is changing - typedef std::map LifeMap; + typedef std::unordered_map LifeMap; LifeMap m_map; // Current active lifetime map for current scope LifeBlock* m_aboveLifep; // Upper life, or nullptr LifeState* m_statep; // Current global state @@ -135,7 +135,7 @@ public: m_aboveLifep = aboveLifep; // Null if top m_statep = statep; } - ~LifeBlock() {} + ~LifeBlock() = default; // METHODS void checkRemoveAssign(const LifeMap::iterator& it) { AstVar* varp = it->first->varp(); @@ -268,7 +268,7 @@ public: //###################################################################### // Life state, as a visitor of each AstNode -class LifeVisitor : public AstNVisitor { +class LifeVisitor final : public AstNVisitor { private: // STATE LifeState* m_statep; // Current state @@ -278,7 +278,7 @@ private: // LIFE MAP // For each basic block, we'll make a new map of what variables that if/else is changing - typedef std::map LifeMap; + typedef std::unordered_map LifeMap; // cppcheck-suppress memleak // cppcheck bug - it is deleted LifeBlock* m_lifep; // Current active lifetime map for current scope @@ -450,7 +450,7 @@ public: //###################################################################### -class LifeTopVisitor : public AstNVisitor { +class LifeTopVisitor final : public AstNVisitor { // Visit all top nodes searching for functions that are entry points we want to start // finding code within. private: @@ -479,7 +479,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~LifeTopVisitor() override {} + virtual ~LifeTopVisitor() override = default; }; //###################################################################### diff --git a/src/V3Life.h b/src/V3Life.h index 44a44f020..7e8141329 100644 --- a/src/V3Life.h +++ b/src/V3Life.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Life { +class V3Life final { public: static void lifeAll(AstNetlist* nodep); }; diff --git a/src/V3LifePost.cpp b/src/V3LifePost.cpp index 4e254a991..b3bc39795 100644 --- a/src/V3LifePost.cpp +++ b/src/V3LifePost.cpp @@ -40,7 +40,7 @@ //###################################################################### // LifePost class functions -class LifePostElimVisitor : public AstNVisitor { +class LifePostElimVisitor final : public AstNVisitor { private: bool m_tracingCall = false; // Iterating into a CCall to a CFunc @@ -91,7 +91,7 @@ private: public: // CONSTRUCTORS explicit LifePostElimVisitor(AstTopScope* nodep) { iterate(nodep); } - virtual ~LifePostElimVisitor() override {} + virtual ~LifePostElimVisitor() override = default; }; //###################################################################### @@ -103,7 +103,7 @@ struct LifeLocation { uint32_t sequence = 0; public: - LifeLocation() {} + LifeLocation() = default; LifeLocation(const ExecMTask* mtaskp_, uint32_t sequence_) : mtaskp{mtaskp_} , sequence{sequence_} {} @@ -119,7 +119,7 @@ public: struct LifePostLocation { LifeLocation loc; AstAssignPost* nodep = nullptr; - LifePostLocation() {} + LifePostLocation() = default; LifePostLocation(LifeLocation loc_, AstAssignPost* nodep_) : loc{loc_} , nodep{nodep_} {} @@ -128,7 +128,7 @@ struct LifePostLocation { //###################################################################### // LifePost delay elimination -class LifePostDlyVisitor : public AstNVisitor { +class LifePostDlyVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on entire tree diff --git a/src/V3LifePost.h b/src/V3LifePost.h index 1aa9fae02..426270a70 100644 --- a/src/V3LifePost.h +++ b/src/V3LifePost.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LifePost { +class V3LifePost final { public: static void lifepostAll(AstNetlist* nodep); }; diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp index b97e1261b..df9d24582 100644 --- a/src/V3LinkCells.cpp +++ b/src/V3LinkCells.cpp @@ -41,21 +41,21 @@ //###################################################################### // Graph subclasses -class LinkCellsGraph : public V3Graph { +class LinkCellsGraph final : public V3Graph { public: - LinkCellsGraph() {} - virtual ~LinkCellsGraph() override {} + LinkCellsGraph() = default; + virtual ~LinkCellsGraph() override = default; virtual void loopsMessageCb(V3GraphVertex* vertexp) override; }; -class LinkCellsVertex : public V3GraphVertex { +class LinkCellsVertex final : public V3GraphVertex { AstNodeModule* m_modp; public: LinkCellsVertex(V3Graph* graphp, AstNodeModule* modp) : V3GraphVertex{graphp} , m_modp{modp} {} - virtual ~LinkCellsVertex() override {} + virtual ~LinkCellsVertex() override = default; AstNodeModule* modp() const { return m_modp; } virtual string name() const override { return modp()->name(); } virtual FileLine* fileline() const override { return modp()->fileline(); } @@ -65,11 +65,11 @@ public: } }; -class LibraryVertex : public V3GraphVertex { +class LibraryVertex final : public V3GraphVertex { public: explicit LibraryVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~LibraryVertex() override {} + virtual ~LibraryVertex() override = default; virtual string name() const override { return "*LIBRARY*"; } }; @@ -78,7 +78,7 @@ void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { vvertexp->modp()->v3warn(E_UNSUPPORTED, "Unsupported: Recursive multiple modules (module instantiates " "something leading back to itself): " - << vvertexp->modp()->prettyNameQ() << endl + << vvertexp->modp()->prettyNameQ() << '\n' << V3Error::warnMore() << "... note: self-recursion (module instantiating itself " "directly) is supported."); @@ -91,7 +91,7 @@ void LinkCellsGraph::loopsMessageCb(V3GraphVertex* vertexp) { //###################################################################### // Link state, as a visitor of each AstNode -class LinkCellsVisitor : public AstNVisitor { +class LinkCellsVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -457,6 +457,13 @@ private: UINFO(4, " Link Cell done: " << nodep << endl); } + virtual void visit(AstRefDType* nodep) override { + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + pinp->param(true); + if (pinp->name() == "") pinp->name("__paramNumber" + cvtToStr(pinp->pinNum())); + } + } + // Accelerate the recursion // Must do statements to support Generates, math though... virtual void visit(AstNodeMath*) override {} @@ -482,10 +489,10 @@ private: || nodep->fileline()->warnIsOff(V3ErrorCode::MODDUP) || hierBlocks.find(nodep->name()) != hierBlocks.end())) { nodep->v3warn(MODDUP, "Duplicate declaration of module: " - << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << foundp->warnOther() - << "... Location of original declaration" << endl + << "... Location of original declaration\n" << foundp->warnContextSecondary()); } nodep->unlinkFrBack(); @@ -517,7 +524,7 @@ public: } iterate(nodep); } - virtual ~LinkCellsVisitor() override {} + virtual ~LinkCellsVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkCells.h b/src/V3LinkCells.h index b79b94a01..c1cd4b817 100644 --- a/src/V3LinkCells.h +++ b/src/V3LinkCells.h @@ -28,7 +28,7 @@ class V3ParseSym; //============================================================================ -class V3LinkCells { +class V3LinkCells final { public: static void link(AstNetlist* nodep, VInFilter* filterp, V3ParseSym* parseSymp); }; diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp index 7877f7b17..c82b3dba5 100644 --- a/src/V3LinkDot.cpp +++ b/src/V3LinkDot.cpp @@ -78,25 +78,25 @@ //###################################################################### // Matcher classes (for suggestion matching) -class LinkNodeMatcherClass : public VNodeMatcher { +class LinkNodeMatcherClass final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Class); } }; -class LinkNodeMatcherFTask : public VNodeMatcher { +class LinkNodeMatcherFTask final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, NodeFTask); } }; -class LinkNodeMatcherModport : public VNodeMatcher { +class LinkNodeMatcherModport final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Modport); } }; -class LinkNodeMatcherVar : public VNodeMatcher { +class LinkNodeMatcherVar final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { return VN_IS(nodep, Var) || VN_IS(nodep, LambdaArgRef); } }; -class LinkNodeMatcherVarIO : public VNodeMatcher { +class LinkNodeMatcherVarIO final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { const AstVar* varp = VN_CAST_CONST(nodep, Var); @@ -104,7 +104,7 @@ public: return varp->isIO(); } }; -class LinkNodeMatcherVarParam : public VNodeMatcher { +class LinkNodeMatcherVarParam final : public VNodeMatcher { public: virtual bool nodeMatch(const AstNode* nodep) const override { const AstVar* varp = VN_CAST_CONST(nodep, Var); @@ -116,7 +116,7 @@ public: //###################################################################### // LinkDot state, as a visitor of each AstNode -class LinkDotState { +class LinkDotState final { private: // NODE STATE // Cleared on Netlist @@ -141,7 +141,7 @@ public: private: // TYPES typedef std::multimap NameScopeSymMap; - typedef std::map ScopeAliasMap; + typedef std::unordered_map ScopeAliasMap; typedef std::set> ImplicitNameSet; typedef std::vector IfaceVarSyms; typedef std::vector> IfaceModSyms; @@ -153,7 +153,7 @@ private: VSymEnt* m_dunitEntp; // $unit entry NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it - ScopeAliasMap m_scopeAliasMap[SAMN__MAX]; // Map of aliases + std::array m_scopeAliasMap; // Map of aliases IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed bool m_forPrimary; // First link @@ -180,7 +180,7 @@ public: // left side is what we will import into os << "\t" << samn << "\t" << it->first << " (" << it->first->nodep()->typeName() << ") <- " << it->second << " " - << it->second->nodep() << endl; + << it->second->nodep() << '\n'; } } } @@ -269,15 +269,15 @@ public: UINFO(4, "Var2 " << fnodep << endl); if (nodep->type() == fnodep->type()) { nodep->v3error("Duplicate declaration of " - << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << fnodep->warnOther() << "... Location of original declaration\n" << fnodep->warnContextSecondary()); } else { nodep->v3error("Unsupported in C: " << ucfirst(nodeTextType(nodep)) << " has the same name as " - << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodeTextType(fnodep) << ": " << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << fnodep->warnOther() << "... Location of original declaration\n" << fnodep->warnContextSecondary()); } @@ -355,7 +355,7 @@ public: return symp; } VSymEnt* insertBlock(VSymEnt* abovep, const string& name, AstNode* nodep, - AstNodeModule* packagep) { + AstNodeModule* classOrPackagep) { // A fake point in the hierarchy, corresponding to a begin or function/task block // After we remove begins these will go away // Note we fallback to the symbol table of the parent, as we want to find variables there @@ -363,9 +363,10 @@ public: UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); UINFO(9, " INSERTblk se" << cvtToHex(symp) << " above=se" << cvtToHex(abovep) - << " node=" << nodep << endl); + << " pkg=" << cvtToHex(classOrPackagep) << " node=" << nodep + << endl); symp->parentp(abovep); - symp->packagep(packagep); + symp->classOrPackagep(classOrPackagep); symp->fallbackp(abovep); nodep->user1p(symp); if (name != "") { checkDuplicate(abovep, nodep, name); } @@ -374,14 +375,15 @@ public: return symp; } VSymEnt* insertSym(VSymEnt* abovep, const string& name, AstNode* nodep, - AstNodeModule* packagep) { + AstNodeModule* classOrPackagep) { UASSERT_OBJ(abovep, nodep, "Null symbol table inserting node"); VSymEnt* symp = new VSymEnt(&m_syms, nodep); UINFO(9, " INSERTsym se" << cvtToHex(symp) << " name='" << name << "' above=se" - << cvtToHex(abovep) << " node=" << nodep << endl); + << cvtToHex(abovep) << " pkg=" << cvtToHex(classOrPackagep) + << " node=" << nodep << endl); // We don't remember the ent associated with each node, because we // need a unique scope entry for each instantiation - symp->packagep(packagep); + symp->classOrPackagep(classOrPackagep); symp->parentp(abovep); symp->fallbackp(abovep); nodep->user1p(symp); @@ -481,7 +483,7 @@ public: ifacerefp->modportFileline()->v3error( "Modport not found under interface " << ifacerefp->prettyNameQ(ifacerefp->ifaceName()) << ": " - << ifacerefp->prettyNameQ(ifacerefp->modportName()) << endl + << ifacerefp->prettyNameQ(ifacerefp->modportName()) << '\n' << (suggest.empty() ? "" : ifacerefp->warnMore() + suggest)); } } @@ -705,10 +707,10 @@ LinkDotState* LinkDotState::s_errorThisp = nullptr; //====================================================================== -class LinkDotFindVisitor : public AstNVisitor { +class LinkDotFindVisitor final : public AstNVisitor { // STATE LinkDotState* m_statep; // State to pass between visitors, including symbol table - AstNodeModule* m_packagep = nullptr; // Current package + AstNodeModule* m_classOrPackagep = nullptr; // Current package VSymEnt* m_modSymp = nullptr; // Symbol Entry for current module VSymEnt* m_curSymp = nullptr; // Symbol Entry for current table, where to lookup/insert string m_scope; // Scope text @@ -729,7 +731,7 @@ class LinkDotFindVisitor : public AstNVisitor { newp->isConstructor(true); nodep->addMembersp(newp); UINFO(8, "Made implicit new for " << nodep->name() << ": " << nodep << endl); - m_statep->insertBlock(m_curSymp, newp->name(), newp, m_packagep); + m_statep->insertBlock(m_curSymp, newp->name(), newp, m_classOrPackagep); } bool isHierBlockWrapper(const string& name) const { @@ -777,6 +779,7 @@ class LinkDotFindVisitor : public AstNVisitor { bool standalonePkg = !m_modSymp && (m_statep->forPrearray() && VN_IS(nodep, Package)); bool doit = (m_modSymp || standalonePkg); VL_RESTORER(m_scope); + VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_modSymp); VL_RESTORER(m_curSymp); VL_RESTORER(m_paramNum); @@ -793,7 +796,7 @@ class LinkDotFindVisitor : public AstNVisitor { UASSERT_OBJ(!nodep->dead(), nodep, "Module in cell tree mislabeled as dead?"); VSymEnt* upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp(); AstPackage* pkgp = VN_CAST(nodep, Package); - m_packagep = pkgp; + m_classOrPackagep = pkgp; if (standalonePkg) { if (pkgp->isDollarUnit()) { m_curSymp = m_modSymp = m_statep->dunitEntp(); @@ -801,7 +804,7 @@ class LinkDotFindVisitor : public AstNVisitor { } else { m_scope = nodep->name(); m_curSymp = m_modSymp = m_statep->insertBlock( - upperSymp, nodep->name() + "::", nodep, m_packagep); + upperSymp, nodep->name() + "::", nodep, m_classOrPackagep); UINFO(9, "New module scope " << m_curSymp << endl); } } @@ -825,7 +828,7 @@ class LinkDotFindVisitor : public AstNVisitor { m_scope = nodep->name(); VSymEnt* upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp(); m_curSymp = m_modSymp - = m_statep->insertBlock(upperSymp, nodep->name() + "::", nodep, m_packagep); + = m_statep->insertBlock(upperSymp, nodep->name() + "::", nodep, m_classOrPackagep); iterateChildren(nodep); nodep->user4(true); } else { // !doit @@ -833,13 +836,12 @@ class LinkDotFindVisitor : public AstNVisitor { // Can't remove now, as our backwards iterator will throw up UINFO(5, "Module not under any CELL or top - dead module: " << nodep << endl); } - // Prep for next - m_packagep = nullptr; } virtual void visit(AstClass* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Class not under module/package/$unit"); UINFO(8, " " << nodep << endl); VL_RESTORER(m_scope); + VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_modSymp); VL_RESTORER(m_curSymp); VL_RESTORER(m_paramNum); @@ -850,8 +852,9 @@ class LinkDotFindVisitor : public AstNVisitor { UINFO(4, " Link Class: " << nodep << endl); VSymEnt* upperSymp = m_curSymp; m_scope = m_scope + "." + nodep->name(); + m_classOrPackagep = nodep; m_curSymp = m_modSymp - = m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_packagep); + = m_statep->insertBlock(upperSymp, nodep->name(), nodep, m_classOrPackagep); m_statep->insertMap(m_curSymp, m_scope); UINFO(9, "New module scope " << m_curSymp << endl); // @@ -966,7 +969,8 @@ class LinkDotFindVisitor : public AstNVisitor { { m_blockNum = 0; m_blockp = nodep; - m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_packagep); + m_curSymp + = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, m_classOrPackagep); m_curSymp->fallbackp(oldCurSymp); // Iterate iterateChildren(nodep); @@ -979,12 +983,14 @@ class LinkDotFindVisitor : public AstNVisitor { UASSERT_OBJ(m_curSymp && m_modSymp, nodep, "Function/Task not under module?"); if (nodep->name() == "new") m_explicitNew = true; // Remember the existing symbol table scope + VL_RESTORER(m_classOrPackagep); VL_RESTORER(m_curSymp); - VSymEnt* const oldCurSymp = m_curSymp; + VSymEnt* upSymp = m_curSymp; { // Change to appropriate package if extern declaration (vs definition) - if (nodep->packagep()) { - AstClassOrPackageRef* cpackagerefp = VN_CAST(nodep->packagep(), ClassOrPackageRef); + if (nodep->classOrPackagep()) { + AstClassOrPackageRef* cpackagerefp + = VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef); if (!cpackagerefp) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: extern function definition with class-in-class"); @@ -994,25 +1000,25 @@ class LinkDotFindVisitor : public AstNVisitor { nodep->v3error("Extern declaration's scope is not a defined class"); } else { m_curSymp = m_statep->getNodeSym(classp); + upSymp = m_curSymp; if (!nodep->isExternDef()) { // Move it to proper spot under the target class nodep->unlinkFrBack(); classp->addStmtp(nodep); nodep->isExternDef(true); // So we check there's a matching extern - nodep->packagep()->unlinkFrBack()->deleteTree(); + nodep->classOrPackagep()->unlinkFrBack()->deleteTree(); } } } } + // Set the class as package for iteration + if (VN_IS(m_curSymp->nodep(), Class)) { + m_classOrPackagep = VN_CAST(m_curSymp->nodep(), Class); + } // Create symbol table for the task's vars string name = string{nodep->isExternProto() ? "extern " : ""} + nodep->name(); - auto pkgp = m_packagep; - // Set the class as package for static class methods - if (nodep->lifetime().isStatic() && VN_IS(m_curSymp->nodep(), Class)) { - pkgp = VN_CAST(m_curSymp->nodep(), Class); - } - m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, pkgp); - m_curSymp->fallbackp(oldCurSymp); + m_curSymp = m_statep->insertBlock(m_curSymp, name, nodep, m_classOrPackagep); + m_curSymp->fallbackp(upSymp); // Convert the func's range to the output variable // This should probably be done in the Parser instead, as then we could // just attach normal signal attributes to it. @@ -1034,7 +1040,8 @@ class LinkDotFindVisitor : public AstNVisitor { newvarp->attrIsolateAssign(nodep->attrIsolateAssign()); nodep->addFvarp(newvarp); // Explicit insert required, as the var name shadows the upper level's task name - m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, nullptr /*packagep*/); + m_statep->insertSym(m_curSymp, newvarp->name(), newvarp, + nullptr /*classOrPackagep*/); } m_ftaskp = nodep; iterateChildren(nodep); @@ -1081,15 +1088,15 @@ class LinkDotFindVisitor : public AstNVisitor { if (didAnsiWarn++) ansiWarn = false; } nodep->v3error("Duplicate declaration of signal: " - << nodep->prettyNameQ() << endl + << nodep->prettyNameQ() << '\n' << (ansiWarn ? nodep->warnMore() + "... note: ANSI ports must have" " type declared with the I/O (IEEE " "1800-2017 23.2.2.2)\n" : "") - << nodep->warnContextPrimary() << endl + << nodep->warnContextPrimary() << '\n' << findvarp->warnOther() - << "... Location of original declaration" << endl + << "... Location of original declaration\n" << findvarp->warnContextSecondary()); // Combining most likely reduce other errors findvarp->combineType(nodep); @@ -1119,8 +1126,8 @@ class LinkDotFindVisitor : public AstNVisitor { && !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { nodep->v3warn(VARHIDDEN, "Declaration of signal hides declaration in upper scope: " - << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << foundp->nodep()->warnOther() << "... Location of original declaration\n" << foundp->nodep()->warnContextSecondary()); @@ -1151,11 +1158,13 @@ class LinkDotFindVisitor : public AstNVisitor { } } } - VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); + VSymEnt* insp + = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); if (m_statep->forPrimary() && nodep->isGParam()) { m_paramNum++; - VSymEnt* symp = m_statep->insertSym( - m_curSymp, "__paramNumber" + cvtToStr(m_paramNum), nodep, m_packagep); + VSymEnt* symp + = m_statep->insertSym(m_curSymp, "__paramNumber" + cvtToStr(m_paramNum), + nodep, m_classOrPackagep); symp->exported(false); } AstIfaceRefDType* ifacerefp = LinkDotState::ifaceRefFromArray(nodep->subDTypep()); @@ -1170,7 +1179,7 @@ class LinkDotFindVisitor : public AstNVisitor { virtual void visit(AstTypedef* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit"); iterateChildren(nodep); - m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); + m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); } virtual void visit(AstTypedefFwd* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Typedef not under module/package/$unit"); @@ -1181,7 +1190,7 @@ class LinkDotFindVisitor : public AstNVisitor { virtual void visit(AstParamTypeDType* nodep) override { UASSERT_OBJ(m_curSymp, nodep, "Parameter type not under module/package/$unit"); iterateChildren(nodep); - m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); + m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); } virtual void visit(AstCFunc* nodep) override { // For dotted resolution, ignore all AstVars under functions, otherwise shouldn't exist @@ -1204,8 +1213,8 @@ class LinkDotFindVisitor : public AstNVisitor { if (foundp->parentp() == m_curSymp // Only when on same level && !foundp->imported()) { // and not from package nodep->v3error("Duplicate declaration of enum value: " - << nodep->prettyName() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyName() << '\n' + << nodep->warnContextPrimary() << '\n' << foundp->nodep()->warnOther() << "... Location of original declaration\n" << foundp->nodep()->warnContextSecondary()); @@ -1215,8 +1224,8 @@ class LinkDotFindVisitor : public AstNVisitor { && !foundp->nodep()->fileline()->warnIsOff(V3ErrorCode::VARHIDDEN)) { nodep->v3warn(VARHIDDEN, "Declaration of enum value hides declaration in upper scope: " - << nodep->prettyName() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyName() << '\n' + << nodep->warnContextPrimary() << '\n' << foundp->nodep()->warnOther() << "... Location of original declaration\n" << nodep->warnContextSecondary()); @@ -1224,7 +1233,7 @@ class LinkDotFindVisitor : public AstNVisitor { ins = true; } } - if (ins) m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep); + if (ins) m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_classOrPackagep); } virtual void visit(AstPackageImport* nodep) override { UINFO(4, " Link: " << nodep << endl); @@ -1281,10 +1290,13 @@ class LinkDotFindVisitor : public AstNVisitor { VL_DO_DANGLING(argp->unlinkFrBackWithNext()->deleteTree(), argp); } // Type depends on the method used, let V3Width figure it out later - auto* argrefp = new AstLambdaArgRef(argFl, name); - auto* newp - = new AstWith(nodep->fileline(), argrefp, nodep->exprp()->unlinkFrBackWithNext()); - funcrefp->addPinsp(newp); + const auto indexArgRefp = new AstLambdaArgRef(argFl, name + "__DOT__index", true); + const auto valueArgRefp = new AstLambdaArgRef(argFl, name, false); + if (nodep->exprp()) { // Else empty expression and pretend no "with" + const auto newp = new AstWith(nodep->fileline(), indexArgRefp, valueArgRefp, + nodep->exprp()->unlinkFrBackWithNext()); + funcrefp->addPinsp(newp); + } nodep->replaceWith(funcrefp->unlinkFrBack()); VL_DO_DANGLING(nodep->deleteTree(), nodep); } @@ -1296,11 +1308,13 @@ class LinkDotFindVisitor : public AstNVisitor { { ++m_modWithNum; m_curSymp = m_statep->insertBlock(m_curSymp, "__Vwith" + cvtToStr(m_modWithNum), nodep, - m_packagep); + m_classOrPackagep); m_curSymp->fallbackp(oldCurSymp); - UASSERT_OBJ(nodep->argrefp(), nodep, "Missing lambda argref"); + UASSERT_OBJ(nodep->indexArgRefp(), nodep, "Missing lambda argref"); + UASSERT_OBJ(nodep->valueArgRefp(), nodep, "Missing lambda argref"); // Insert argref's name into symbol table - m_statep->insertSym(m_curSymp, nodep->argrefp()->name(), nodep->argrefp(), nullptr); + m_statep->insertSym(m_curSymp, nodep->valueArgRefp()->name(), nodep->valueArgRefp(), + nullptr); } } @@ -1314,12 +1328,12 @@ public: iterate(rootp); } - virtual ~LinkDotFindVisitor() override {} + virtual ~LinkDotFindVisitor() override = default; }; //====================================================================== -class LinkDotParamVisitor : public AstNVisitor { +class LinkDotParamVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on global @@ -1417,15 +1431,15 @@ private: } else { if (refp->user4()) { nodep->v3error("Duplicate declaration of port: " - << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << refp->warnOther() << "... Location of original declaration\n" << refp->warnContextSecondary()); } refp->user4(true); VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp), "__pinNumber" + cvtToStr(nodep->pinNum()), refp, - nullptr /*packagep*/); + nullptr /*classOrPackagep*/); symp->exported(false); } // Ports not needed any more @@ -1479,12 +1493,12 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotParamVisitor() override {} + virtual ~LinkDotParamVisitor() override = default; }; //====================================================================== -class LinkDotScopeVisitor : public AstNVisitor { +class LinkDotScopeVisitor final : public AstNVisitor { // STATE LinkDotState* m_statep; // State to pass between visitors, including symbol table @@ -1637,13 +1651,13 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotScopeVisitor() override {} + virtual ~LinkDotScopeVisitor() override = default; }; //====================================================================== // Iterate an interface to resolve modports -class LinkDotIfaceVisitor : public AstNVisitor { +class LinkDotIfaceVisitor final : public AstNVisitor { // STATE LinkDotState* m_statep; // State to pass between visitors, including symbol table VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert @@ -1722,7 +1736,7 @@ public: m_statep = statep; iterate(nodep); } - virtual ~LinkDotIfaceVisitor() override {} + virtual ~LinkDotIfaceVisitor() override = default; }; void LinkDotState::computeIfaceModSyms() { @@ -1736,7 +1750,7 @@ void LinkDotState::computeIfaceModSyms() { //====================================================================== -class LinkDotResolveVisitor : public AstNVisitor { +class LinkDotResolveVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on global @@ -1777,7 +1791,7 @@ private: bool m_dotErr; // Error found in dotted resolution, ignore upwards string m_dotText; // String of dotted names found in below parseref DotStates() { init(nullptr); } - ~DotStates() {} + ~DotStates() = default; void init(VSymEnt* curSymp) { m_dotPos = DP_NONE; m_dotSymp = curSymp; @@ -1811,7 +1825,7 @@ private: LinkNodeMatcherVar()); nodep->v3error("Signal definition not found, and implicit disabled with " "`default_nettype: " - << nodep->prettyNameQ() << endl + << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } @@ -1822,7 +1836,7 @@ private: LinkNodeMatcherVar()); nodep->v3warn(IMPLICIT, "Signal definition not found, creating implicitly: " - << nodep->prettyNameQ() << endl + << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } } @@ -1833,7 +1847,7 @@ private: modp->addStmtp(newp); // Link it to signal list, must add the variable under the module; // current scope might be lower now - m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*packagep*/); + m_statep->insertSym(moduleSymp, newp->name(), newp, nullptr /*classOrPackagep*/); } } AstVar* foundToVarp(const VSymEnt* symp, AstNode* nodep, VAccess access) { @@ -1876,8 +1890,8 @@ private: } void markAndCheckPinDup(AstNode* nodep, AstNode* refp, const char* whatp) { if (refp->user5p() && refp->user5p() != nodep) { - nodep->v3error("Duplicate " << whatp << " connection: " << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + nodep->v3error("Duplicate " << whatp << " connection: " << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << refp->user5p()->warnOther() << "... Location of original " << whatp << " connection\n" << refp->user5p()->warnContextSecondary()); @@ -1927,11 +1941,13 @@ private: virtual void visit(AstCell* nodep) override { // Cell: Recurse inside or cleanup not founds checkNoDot(nodep); - m_cellp = nodep; AstNode::user5ClearTree(); UASSERT_OBJ(nodep->modp(), nodep, "Cell has unlinked module"); // V3LinkCell should have errored out + VL_RESTORER(m_cellp); + VL_RESTORER(m_pinSymp); { + m_cellp = nodep; if (VN_IS(nodep->modp(), NotFoundModule)) { // Prevent warnings about missing pin connects if (nodep->pinsp()) nodep->pinsp()->unlinkFrBackWithNext()->deleteTree(); @@ -1946,13 +1962,26 @@ private: // if (debug()) nodep->dumpTree(cout, "linkcell:"); // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); iterateChildren(nodep); - m_pinSymp = nullptr; } } - m_cellp = nullptr; // Parent module inherits child's publicity // This is done bottom up in the LinkBotupVisitor stage } + virtual void visit(AstClassRefDType* nodep) override { + // Cell: Recurse inside or cleanup not founds + checkNoDot(nodep); + AstNode::user5ClearTree(); + UASSERT_OBJ(nodep->classp(), nodep, "ClassRef has unlinked class"); + VL_RESTORER(m_pinSymp); + { + // ClassRef's have pins, so track + m_pinSymp = m_statep->getNodeSym(nodep->classp()); + UINFO(4, "(Backto) Link ClassRefDType: " << nodep << endl); + // if (debug()) nodep->dumpTree(cout, "linkcell:"); + // if (debug()) nodep->modp()->dumpTree(cout, "linkcemd:"); + iterateChildren(nodep); + } + } virtual void visit(AstPin* nodep) override { // Pin: Link to submodule's port checkNoDot(nodep); @@ -1962,7 +1991,8 @@ private: VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name()); const char* whatp = nodep->param() ? "parameter pin" : "pin"; if (!foundp) { - if (nodep->name() == "__paramNumber1" && VN_IS(m_cellp->modp(), Primitive)) { + if (nodep->name() == "__paramNumber1" && m_cellp + && VN_IS(m_cellp->modp(), Primitive)) { // Primitive parameter is really a delay we can just ignore VL_DO_DANGLING(nodep->unlinkFrBack()->deleteTree(), nodep); return; @@ -1973,7 +2003,7 @@ private: : m_statep->suggestSymFlat(m_pinSymp, nodep->name(), LinkNodeMatcherVarIO())); nodep->v3error(ucfirst(whatp) - << " not found: " << nodep->prettyNameQ() << endl + << " not found: " << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } else if (AstVar* refp = VN_CAST(foundp->nodep(), Var)) { if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) { @@ -2013,12 +2043,36 @@ private: if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "this") { VSymEnt* classSymp = m_ds.m_dotSymp; do { - classSymp = classSymp->fallbackp(); + classSymp = classSymp->parentp(); } while (classSymp && !VN_IS(classSymp->nodep(), Class)); - m_ds.m_dotSymp = classSymp; if (!classSymp) { - nodep->v3error("'this' used outside class"); + nodep->v3error("'this' used outside class (IEEE 1800-2017 8.11)"); m_ds.m_dotErr = true; + } else { + m_ds.m_dotSymp = classSymp; + UINFO(8, " this. " << m_ds.ascii() << endl); + } + } else if (VN_IS(nodep->lhsp(), ParseRef) && nodep->lhsp()->name() == "super") { + VSymEnt* classSymp = m_ds.m_dotSymp; + do { + classSymp = classSymp->parentp(); + } while (classSymp && !VN_IS(classSymp->nodep(), Class)); + if (!classSymp) { + nodep->v3error("'super' used outside class (IEEE 1800-2017 8.15)"); + m_ds.m_dotErr = true; + } else { + auto classp = VN_CAST(classSymp->nodep(), Class); + if (!classp->extendsp()) { + nodep->v3error("'super' used on non-extended class (IEEE 1800-2017 8.15)"); + m_ds.m_dotErr = true; + } else { + auto cextp = VN_CAST(classp->extendsp(), ClassExtends); + UASSERT_OBJ(cextp, nodep, "Bad super extends link"); + auto classp = cextp->classp(); + UASSERT_OBJ(classp, nodep, "Bad superclass"); + m_ds.m_dotSymp = m_statep->getNodeSym(classp); + UINFO(8, " super. " << m_ds.ascii() << endl); + } } } else if (VN_IS(nodep->lhsp(), ClassOrPackageRef)) { // m_ds.m_dotText communicates the cell prefix between stages @@ -2034,6 +2088,7 @@ private: && (VN_IS(nodep->lhsp(), CellRef) || VN_IS(nodep->lhsp(), CellArrayRef))) { m_ds.m_unlinkedScopep = nodep->lhsp(); } + if (VN_IS(nodep->lhsp(), LambdaArgRef)) { m_ds.m_unlinkedScopep = nodep->lhsp(); } if (!m_ds.m_dotErr) { // Once something wrong, give up // Top 'final' dot RHS is final RHS, else it's a // DOT(DOT(x,*here*),real-rhs) which we consider a RHS @@ -2044,7 +2099,7 @@ private: if (start) { AstNode* newp; if (m_ds.m_dotErr) { - newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + newp = new AstConst(nodep->fileline(), AstConst::BitFalse()); } else { // RHS is what we're left with newp = nodep->rhsp()->unlinkFrBack(); @@ -2089,7 +2144,16 @@ private: nodep->v3warn(E_UNSUPPORTED, "Unsupported: super"); m_ds.m_dotErr = true; } - if (m_ds.m_dotPos == DP_MEMBER) { + if (m_ds.m_dotPos == DP_FINAL && VN_IS(m_ds.m_unlinkedScopep, LambdaArgRef) + && nodep->name() == "index") { + // 'with' statement's 'item.index' + iterateChildren(nodep); + auto newp = new AstLambdaArgRef(nodep->fileline(), + m_ds.m_unlinkedScopep->name() + "__DOT__index", true); + nodep->replaceWith(newp); + VL_DO_DANGLING(pushDeletep(nodep), nodep); + return; + } else if (m_ds.m_dotPos == DP_MEMBER) { // Found a Var, everything following is membership. {scope}.{var}.HERE {member} AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack(); AstNode* newp @@ -2107,7 +2171,7 @@ private: bool allowVar = false; if (m_ds.m_dotPos == DP_PACKAGE) { // {package}::{a} - AstNodeModule* packagep = nullptr; + AstNodeModule* classOrPackagep = nullptr; expectWhat = "scope/variable"; allowScope = true; allowVar = true; @@ -2115,9 +2179,9 @@ private: "Bad package link"); AstClassOrPackageRef* cpackagerefp = VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef); - packagep = cpackagerefp->classOrPackagep(); - UASSERT_OBJ(packagep, m_ds.m_dotp->lhsp(), "Bad package link"); - m_ds.m_dotSymp = m_statep->getNodeSym(packagep); + classOrPackagep = cpackagerefp->classOrPackagep(); + UASSERT_OBJ(classOrPackagep, m_ds.m_dotp->lhsp(), "Bad package link"); + m_ds.m_dotSymp = m_statep->getNodeSym(classOrPackagep); m_ds.m_dotPos = DP_SCOPE; } else if (m_ds.m_dotPos == DP_SCOPE) { // {a}.{b}, where {a} maybe a module name @@ -2234,7 +2298,7 @@ private: AstVarRef* refp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); // lvalue'ness computed later - refp->packagep(foundp->packagep()); + refp->classOrPackagep(foundp->classOrPackagep()); newp = refp; } UINFO(9, " new " << newp << endl); @@ -2293,7 +2357,7 @@ private: } else if (AstEnumItem* valuep = VN_CAST(foundp->nodep(), EnumItem)) { if (allowVar) { AstNode* newp - = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep()); + = new AstEnumItemRef(nodep->fileline(), valuep, foundp->classOrPackagep()); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); ok = true; @@ -2301,7 +2365,7 @@ private: } } else if (AstLambdaArgRef* argrefp = VN_CAST(foundp->nodep(), LambdaArgRef)) { if (allowVar) { - AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name()); + AstNode* newp = new AstLambdaArgRef(nodep->fileline(), argrefp->name(), false); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); ok = true; @@ -2327,7 +2391,7 @@ private: string suggest = m_statep->suggestSymFallback( m_ds.m_dotSymp, nodep->name(), VNodeMatcher()); nodep->v3error("Can't find definition of " - << expectWhat << ": " << nodep->prettyNameQ() << endl + << expectWhat << ": " << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } else { nodep->v3error("Can't find definition of " @@ -2367,7 +2431,7 @@ private: if (AstVar* varp = foundp ? foundToVarp(foundp, nodep, nodep->access()) : nullptr) { nodep->varp(varp); // Generally set by parse, but might be an import - nodep->packagep(foundp->packagep()); + nodep->classOrPackagep(foundp->classOrPackagep()); } if (!nodep->varp()) { nodep->v3error("Can't find definition of signal, again: " << nodep->prettyNameQ()); @@ -2482,6 +2546,7 @@ private: virtual void visit(AstNodeFTaskRef* nodep) override { if (nodep->user3SetOnce()) return; UINFO(8, " " << nodep << endl); + UINFO(8, " " << m_ds.ascii() << endl); if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); @@ -2491,10 +2556,10 @@ private: "Unsupported: " << AstNode::prettyNameQ(cpackagerefp->name())); } if (cpackagerefp->paramsp()) { - nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages"); + nodep->v3warn(E_UNSUPPORTED, "Unsupported: parameterized packages for task calls"); } UASSERT_OBJ(cpackagerefp->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); - nodep->packagep(cpackagerefp->classOrPackagep()); + nodep->classOrPackagep(cpackagerefp->classOrPackagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) { @@ -2524,7 +2589,7 @@ private: } else { checkNoDot(nodep); } - if (nodep->packagep() && nodep->taskp()) { + if (nodep->classOrPackagep() && nodep->taskp()) { // References into packages don't care about cell hierarchy. } else if (!m_modSymp) { // Module that is not in hierarchy. We'll be dead code eliminating it later. @@ -2536,12 +2601,15 @@ private: } else { string baddot; VSymEnt* okSymp = nullptr; - VSymEnt* dotSymp = m_curSymp; // Start search at module, as a variable + VSymEnt* dotSymp = nodep->dotted().empty() + ? m_ds.m_dotSymp // Non-'super.' dotted reference + : m_curSymp; // Start search at dotted point // of same name under a subtask isn't a relevant hit however a // function under a begin/end is. So we want begins, but not // the function - if (nodep->packagep()) { // Look only in specified package - dotSymp = m_statep->getNodeSym(nodep->packagep()); + if (nodep->classOrPackagep()) { // Look only in specified package + dotSymp = m_statep->getNodeSym(nodep->classOrPackagep()); + UINFO(8, " Override classOrPackage " << dotSymp << endl); } else { if (nodep->inlinedDots() != "") { // Correct for current scope // Dotted lookup is always relative to module, as maybe @@ -2567,7 +2635,7 @@ private: = foundp ? VN_CAST(foundp->nodep(), NodeFTask) : nullptr; // Maybe nullptr if (taskp) { nodep->taskp(taskp); - nodep->packagep(foundp->packagep()); + nodep->classOrPackagep(foundp->classOrPackagep()); UINFO(7, " Resolved " << nodep << endl); // Also prints taskp } else { // Note ParseRef has similar error handling/message output @@ -2605,14 +2673,14 @@ private: VL_DO_DANGLING(nodep->deleteTree(), nodep); return; } else { - nodep->v3error("Unsupported or unknown PLI call: " - << nodep->prettyNameQ() << endl); + nodep->v3error( + "Unsupported or unknown PLI call: " << nodep->prettyNameQ()); } } else { string suggest = m_statep->suggestSymFallback(dotSymp, nodep->name(), LinkNodeMatcherFTask()); nodep->v3error("Can't find definition of task/function: " - << nodep->prettyNameQ() << endl + << nodep->prettyNameQ() << '\n' << (suggest.empty() ? "" : nodep->warnMore() + suggest)); } } else { @@ -2730,6 +2798,11 @@ private: } m_ds.m_dotSymp = m_curSymp = oldCurSymp; } + virtual void visit(AstLambdaArgRef* nodep) override { + UINFO(5, " " << nodep << endl); + // No checknodot(nodep), visit(AstScope) will check for LambdaArgRef + iterateChildren(nodep); + } virtual void visit(AstClass* nodep) override { UINFO(5, " " << nodep << endl); checkNoDot(nodep); @@ -2756,15 +2829,22 @@ private: if (AstClass* classp = VN_CAST(foundp->nodep(), Class)) { UINFO(8, "Import to " << nodep << " from export class " << classp << endl); - AstClassRefDType* newp - = new AstClassRefDType{nodep->fileline(), classp}; - cextp->childDTypep(newp); - classp->isExtended(true); - nodep->isExtended(true); - VSymEnt* srcp = m_statep->getNodeSym(classp); - m_curSymp->importFromClass(m_statep->symsp(), srcp); - VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), - cpackagerefp); + if (classp == nodep) { + cextp->v3error("Attempting to extend class " + << nodep->prettyNameQ() << " from itself"); + } else { + AstNode* paramsp = cpackagerefp->paramsp(); + if (paramsp) paramsp = paramsp->cloneTree(true); + const auto newp + = new AstClassRefDType{nodep->fileline(), classp, paramsp}; + cextp->childDTypep(newp); + classp->isExtended(true); + nodep->isExtended(true); + VSymEnt* srcp = m_statep->getNodeSym(classp); + m_curSymp->importFromClass(m_statep->symsp(), srcp); + VL_DO_DANGLING(cpackagerefp->unlinkFrBack()->deleteTree(), + cpackagerefp); + } ok = true; } } @@ -2773,7 +2853,7 @@ private: m_curSymp, cpackagerefp->name(), LinkNodeMatcherClass{}); cpackagerefp->v3error( "Class to extend not found: " - << cpackagerefp->prettyNameQ() << endl + << cpackagerefp->prettyNameQ() << '\n' << (suggest.empty() ? "" : cpackagerefp->warnMore() + suggest)); } } @@ -2790,7 +2870,7 @@ private: if (!nodep->findMember(it->first)) { if (AstEnumItem* aitemp = VN_CAST(itemp, EnumItem)) { AstEnumItemRef* newp = new AstEnumItemRef(aitemp->fileline(), aitemp, - it->second->packagep()); + it->second->classOrPackagep()); UINFO(8, "Class import noderef '" << it->first << "' " << newp << endl); nodep->addMembersp(newp); } @@ -2801,18 +2881,15 @@ private: virtual void visit(AstRefDType* nodep) override { // Resolve its reference if (nodep->user3SetOnce()) return; - if (AstNode* cpackagep = nodep->classOrPackagep()) { + if (AstNode* cpackagep = nodep->classOrPackageOpp()) { if (AstClassOrPackageRef* cpackagerefp = VN_CAST(cpackagep, ClassOrPackageRef)) { - if (cpackagerefp->packagep()) { - nodep->packagep(cpackagerefp->packagep()); - } else { - nodep->packagep(cpackagerefp->classOrPackagep()); - if (!VN_IS(nodep->packagep(), Class) && !VN_IS(nodep->packagep(), Package)) { - cpackagerefp->v3error( - "'::' expected to reference a class/package but referenced " - << nodep->packagep()->prettyTypeName() << endl - << cpackagerefp->warnMore() + "... Suggest '.' instead of '::'"); - } + nodep->classOrPackagep(cpackagerefp->classOrPackagep()); + if (!VN_IS(nodep->classOrPackagep(), Class) + && !VN_IS(nodep->classOrPackagep(), Package)) { + cpackagerefp->v3error( + "'::' expected to reference a class/package but referenced " + << nodep->classOrPackagep()->prettyTypeName() << '\n' + << cpackagerefp->warnMore() + "... Suggest '.' instead of '::'"); } } else { cpackagep->v3warn(E_UNSUPPORTED, @@ -2825,9 +2902,10 @@ private: if (m_ds.m_dotp && m_ds.m_dotPos == DP_PACKAGE) { UASSERT_OBJ(VN_IS(m_ds.m_dotp->lhsp(), ClassOrPackageRef), m_ds.m_dotp->lhsp(), "Bad package link"); - UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep(), + UASSERT_OBJ(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->classOrPackagep(), m_ds.m_dotp->lhsp(), "Bad package link"); - nodep->packagep(VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->packagep()); + nodep->classOrPackagep( + VN_CAST(m_ds.m_dotp->lhsp(), ClassOrPackageRef)->classOrPackagep()); m_ds.m_dotPos = DP_SCOPE; m_ds.m_dotp = nullptr; } else { @@ -2836,21 +2914,23 @@ private: if (nodep->typeofp()) { // Really is a typeof not a reference } else if (!nodep->typedefp() && !nodep->subDTypep()) { VSymEnt* foundp; - if (nodep->packagep()) { - foundp = m_statep->getNodeSym(nodep->packagep())->findIdFlat(nodep->name()); + if (nodep->classOrPackagep()) { + foundp = m_statep->getNodeSym(nodep->classOrPackagep())->findIdFlat(nodep->name()); } else { foundp = m_curSymp->findIdFallback(nodep->name()); } if (AstTypedef* defp = foundp ? VN_CAST(foundp->nodep(), Typedef) : nullptr) { nodep->typedefp(defp); - nodep->packagep(foundp->packagep()); + nodep->classOrPackagep(foundp->classOrPackagep()); } else if (AstParamTypeDType* defp = foundp ? VN_CAST(foundp->nodep(), ParamTypeDType) : nullptr) { nodep->refDTypep(defp); - nodep->packagep(foundp->packagep()); + nodep->classOrPackagep(foundp->classOrPackagep()); } else if (AstClass* defp = foundp ? VN_CAST(foundp->nodep(), Class) : nullptr) { - AstClassRefDType* newp = new AstClassRefDType(nodep->fileline(), defp); - newp->packagep(foundp->packagep()); + AstNode* paramsp = nodep->paramsp(); + if (paramsp) paramsp->unlinkFrBackWithNext(); + AstClassRefDType* newp = new AstClassRefDType{nodep->fileline(), defp, paramsp}; + newp->classOrPackagep(foundp->classOrPackagep()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); return; @@ -2919,7 +2999,7 @@ public: UINFO(4, __FUNCTION__ << ": " << endl); iterate(rootp); } - virtual ~LinkDotResolveVisitor() override {} + virtual ~LinkDotResolveVisitor() override = default; }; //###################################################################### @@ -2947,6 +3027,7 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) { // Well after the initial link when we're ready to operate on the flat design, // process AstScope's. This needs to be separate pass after whole hierarchy graph created. LinkDotScopeVisitor visitors(rootp, &state); + v3Global.assertScoped(true); if (LinkDotState::debug() >= 5 || v3Global.opt.dumpTree() >= 9) { v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree")); } diff --git a/src/V3LinkDot.h b/src/V3LinkDot.h index e0d829a01..026ba0e2b 100644 --- a/src/V3LinkDot.h +++ b/src/V3LinkDot.h @@ -27,7 +27,7 @@ enum VLinkDotStep : uint8_t { LDS_PRIMARY, LDS_PARAMED, LDS_ARRAYED, LDS_SCOPED }; -class V3LinkDot { +class V3LinkDot final { private: static int debug(); static void linkDotGuts(AstNetlist* rootp, VLinkDotStep step); diff --git a/src/V3LinkInc.cpp b/src/V3LinkInc.cpp index c7cf6298a..89ea48649 100644 --- a/src/V3LinkInc.cpp +++ b/src/V3LinkInc.cpp @@ -47,7 +47,7 @@ //###################################################################### -class LinkIncVisitor : public AstNVisitor { +class LinkIncVisitor final : public AstNVisitor { private: // TYPES enum InsertMode : uint8_t { @@ -238,7 +238,7 @@ private: public: // CONSTRUCTORS explicit LinkIncVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LinkIncVisitor() override {} + virtual ~LinkIncVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkInc.h b/src/V3LinkInc.h index a1679e6d3..ebb9194e7 100644 --- a/src/V3LinkInc.h +++ b/src/V3LinkInc.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkInc { +class V3LinkInc final { public: static void linkIncrements(AstNetlist* nodep); diff --git a/src/V3LinkJump.cpp b/src/V3LinkJump.cpp index 0bccce54a..e4bbc3c0e 100644 --- a/src/V3LinkJump.cpp +++ b/src/V3LinkJump.cpp @@ -41,7 +41,7 @@ //###################################################################### -class LinkJumpVisitor : public AstNVisitor { +class LinkJumpVisitor final : public AstNVisitor { private: // TYPES typedef std::vector BlockStack; @@ -282,7 +282,7 @@ private: public: // CONSTRUCTORS explicit LinkJumpVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LinkJumpVisitor() override {} + virtual ~LinkJumpVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkJump.h b/src/V3LinkJump.h index fba121e9c..af1e88ba0 100644 --- a/src/V3LinkJump.h +++ b/src/V3LinkJump.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkJump { +class V3LinkJump final { public: static void linkJump(AstNetlist* nodep); }; diff --git a/src/V3LinkLValue.cpp b/src/V3LinkLValue.cpp index d5a26d0f5..b1e365f10 100644 --- a/src/V3LinkLValue.cpp +++ b/src/V3LinkLValue.cpp @@ -30,7 +30,7 @@ //###################################################################### // Link state, as a visitor of each AstNode -class LinkLValueVisitor : public AstNVisitor { +class LinkLValueVisitor final : public AstNVisitor { private: // NODE STATE @@ -290,7 +290,7 @@ public: : m_setRefLvalue{start} { iterate(nodep); } - virtual ~LinkLValueVisitor() override {} + virtual ~LinkLValueVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkLValue.h b/src/V3LinkLValue.h index 101e06514..1a534d649 100644 --- a/src/V3LinkLValue.h +++ b/src/V3LinkLValue.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkLValue { +class V3LinkLValue final { public: static void linkLValue(AstNetlist* nodep); static void linkLValueSet(AstNode* nodep); diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp index da3904efb..4a5bc93b7 100644 --- a/src/V3LinkLevel.cpp +++ b/src/V3LinkLevel.cpp @@ -34,7 +34,7 @@ // Levelizing class functions struct CmpLevel { - inline bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const { + bool operator()(const AstNodeModule* lhsp, const AstNodeModule* rhsp) const { return lhsp->level() < rhsp->level(); } }; diff --git a/src/V3LinkLevel.h b/src/V3LinkLevel.h index 4143efa4e..ca9a51a26 100644 --- a/src/V3LinkLevel.h +++ b/src/V3LinkLevel.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkLevel { +class V3LinkLevel final { private: typedef std::vector ModVec; diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp index 14cc8d494..a3883b91c 100644 --- a/src/V3LinkParse.cpp +++ b/src/V3LinkParse.cpp @@ -34,7 +34,7 @@ //###################################################################### // Link state, as a visitor of each AstNode -class LinkParseVisitor : public AstNVisitor { +class LinkParseVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on netlist @@ -45,7 +45,7 @@ private: // TYPES typedef std::map, AstTypedef*> ImplTypedefMap; - typedef std::set FileLineSet; + typedef std::unordered_set FileLineSet; // STATE AstVar* m_varp = nullptr; // Variable we're under @@ -606,7 +606,7 @@ private: public: // CONSTRUCTORS explicit LinkParseVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkParseVisitor() override {} + virtual ~LinkParseVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkParse.h b/src/V3LinkParse.h index 10425842c..bd600daab 100644 --- a/src/V3LinkParse.h +++ b/src/V3LinkParse.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkParse { +class V3LinkParse final { public: static void linkParse(AstNetlist* rootp); }; diff --git a/src/V3LinkResolve.cpp b/src/V3LinkResolve.cpp index 190c4c4a8..9d8ba6828 100644 --- a/src/V3LinkResolve.cpp +++ b/src/V3LinkResolve.cpp @@ -38,7 +38,7 @@ //###################################################################### // Link state, as a visitor of each AstNode -class LinkResolveVisitor : public AstNVisitor { +class LinkResolveVisitor final : public AstNVisitor { private: // NODE STATE // Entire netlist: @@ -472,10 +472,10 @@ private: } varoutp = varp; // Tie off - m_modp->addStmtp(new AstAssignW( - varp->fileline(), - new AstVarRef(varp->fileline(), varp, VAccess::WRITE), - new AstConst(varp->fileline(), AstConst::LogicFalse()))); + m_modp->addStmtp( + new AstAssignW(varp->fileline(), + new AstVarRef(varp->fileline(), varp, VAccess::WRITE), + new AstConst(varp->fileline(), AstConst::BitFalse()))); } else { varp->v3error("Only inputs and outputs are allowed in udp modules"); } @@ -517,7 +517,7 @@ private: public: // CONSTRUCTORS explicit LinkResolveVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkResolveVisitor() override {} + virtual ~LinkResolveVisitor() override = default; }; //###################################################################### @@ -525,7 +525,7 @@ public: // Recurses cells backwards, so we can pick up those things that propagate // from child cells up to the top module. -class LinkBotupVisitor : public AstNVisitor { +class LinkBotupVisitor final : public AstNVisitor { private: // STATE AstNodeModule* m_modp = nullptr; // Current module @@ -556,7 +556,7 @@ private: public: // CONSTRUCTORS explicit LinkBotupVisitor(AstNetlist* rootp) { iterate(rootp); } - virtual ~LinkBotupVisitor() override {} + virtual ~LinkBotupVisitor() override = default; }; //###################################################################### diff --git a/src/V3LinkResolve.h b/src/V3LinkResolve.h index f33ff91d7..a998c0500 100644 --- a/src/V3LinkResolve.h +++ b/src/V3LinkResolve.h @@ -25,7 +25,7 @@ //============================================================================ -class V3LinkResolve { +class V3LinkResolve final { public: static void linkResolve(AstNetlist* rootp); }; diff --git a/src/V3List.h b/src/V3List.h index 5022e6d38..0b4bc399b 100644 --- a/src/V3List.h +++ b/src/V3List.h @@ -36,8 +36,8 @@ private: friend class V3ListEnt; public: - V3List() {} - ~V3List() {} + V3List() = default; + ~V3List() = default; // METHODS T begin() const { return m_headp; } T end() const { return nullptr; } @@ -65,7 +65,7 @@ private: } public: - V3ListEnt() {} + V3ListEnt() = default; ~V3ListEnt() { #ifdef VL_DEBUG // Load bogus pointers so we can catch deletion bugs diff --git a/src/V3Localize.cpp b/src/V3Localize.cpp index f412649cf..372f4d188 100644 --- a/src/V3Localize.cpp +++ b/src/V3Localize.cpp @@ -35,7 +35,7 @@ //###################################################################### // Localize base class -class LocalizeBaseVisitor : public AstNVisitor { +class LocalizeBaseVisitor VL_NOT_FINAL : public AstNVisitor { protected: // NODE STATE // Cleared on entire tree @@ -66,7 +66,7 @@ protected: //###################################################################### // Localize class functions -class LocalizeDehierVisitor : public LocalizeBaseVisitor { +class LocalizeDehierVisitor final : public LocalizeBaseVisitor { private: // NODE STATE/TYPES // See above @@ -76,7 +76,8 @@ private: // cppcheck-suppress unreadVariable // cppcheck 1.90 bug VarFlags flags(nodep->varp()); if (flags.m_done) { - nodep->hiername(""); // Remove this-> + nodep->hiernameToProt(""); // Remove this-> + nodep->hiernameToUnprot(""); // Remove this-> nodep->hierThis(true); } } @@ -85,13 +86,13 @@ private: public: // CONSTRUCTORS explicit LocalizeDehierVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~LocalizeDehierVisitor() override {} + virtual ~LocalizeDehierVisitor() override = default; }; //###################################################################### // Localize class functions -class LocalizeVisitor : public LocalizeBaseVisitor { +class LocalizeVisitor final : public LocalizeBaseVisitor { private: // NODE STATE/TYPES // See above diff --git a/src/V3Localize.h b/src/V3Localize.h index 8fdf5fe5c..3db73dec4 100644 --- a/src/V3Localize.h +++ b/src/V3Localize.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Localize { +class V3Localize final { public: static void localizeAll(AstNetlist* nodep); }; diff --git a/src/V3MergeCond.cpp b/src/V3MergeCond.cpp index e7dcb3955..771096200 100644 --- a/src/V3MergeCond.cpp +++ b/src/V3MergeCond.cpp @@ -52,7 +52,7 @@ //###################################################################### -class CheckMergeableVisitor : public AstNVisitor { +class CheckMergeableVisitor final : public AstNVisitor { private: // STATE bool m_mergeable @@ -86,7 +86,7 @@ private: } public: - CheckMergeableVisitor() {} + CheckMergeableVisitor() = default; // Return false if this node should not be merged at all because: // - It contains an impure expression @@ -98,7 +98,7 @@ public: } }; -class MarkVarsVisitor : public AstNVisitor { +class MarkVarsVisitor final : public AstNVisitor { private: // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -115,7 +115,7 @@ public: void mark(AstNode* node) { iterate(node); } }; -class MergeCondVisitor : public AstNVisitor { +class MergeCondVisitor final : public AstNVisitor { private: // NODE STATE // AstVar::user1 -> Flag set for variables referenced by m_mgCondp @@ -161,7 +161,7 @@ private: // rarely required (only when trying to merge a "cond & value" with an // earlier ternary), we will just always mask it for safety. AstNode* maskLsb(AstNode* nodep) { - AstNode* const maskp = new AstConst(nodep->fileline(), AstConst::LogicTrue()); + AstNode* const maskp = new AstConst(nodep->fileline(), AstConst::BitTrue()); return new AstAnd(nodep->fileline(), nodep, maskp); } @@ -170,8 +170,7 @@ private: // of the RHS is expected to be deleted by the caller. AstNode* foldAndUnlink(AstNode* rhsp, bool condTrue) { if (rhsp->sameTree(m_mgCondp)) { - return condTrue ? new AstConst(rhsp->fileline(), AstConst::LogicTrue()) - : new AstConst(rhsp->fileline(), AstConst::LogicFalse()); + return new AstConst(rhsp->fileline(), AstConst::BitTrue{}, condTrue); } else if (AstNodeCond* const condp = extractCond(rhsp)) { AstNode* const resp = condTrue ? condp->expr1p()->unlinkFrBack() : condp->expr2p()->unlinkFrBack(); @@ -183,12 +182,12 @@ private: } else if (AstAnd* const andp = VN_CAST(rhsp, And)) { if (andp->lhsp()->sameTree(m_mgCondp)) { return condTrue ? maskLsb(andp->rhsp()->unlinkFrBack()) - : new AstConst(rhsp->fileline(), AstConst::LogicFalse()); + : new AstConst(rhsp->fileline(), AstConst::BitFalse()); } else { UASSERT_OBJ(andp->rhsp()->sameTree(m_mgCondp), rhsp, "AstAnd doesn't hold condition expression"); return condTrue ? maskLsb(andp->lhsp()->unlinkFrBack()) - : new AstConst(rhsp->fileline(), AstConst::LogicFalse()); + : new AstConst(rhsp->fileline(), AstConst::BitFalse()); } } rhsp->v3fatalSrc("Don't know how to fold expression"); diff --git a/src/V3MergeCond.h b/src/V3MergeCond.h index 52232bd0b..3366963e7 100644 --- a/src/V3MergeCond.h +++ b/src/V3MergeCond.h @@ -25,7 +25,7 @@ //============================================================================ -class V3MergeCond { +class V3MergeCond final { public: static void mergeAll(AstNetlist* nodep); }; diff --git a/src/V3Name.cpp b/src/V3Name.cpp index 0d5401bf5..9c3c745dc 100644 --- a/src/V3Name.cpp +++ b/src/V3Name.cpp @@ -30,7 +30,7 @@ //###################################################################### // Name state, as a visitor of each AstNode -class NameVisitor : public AstNVisitor { +class NameVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on Netlist @@ -136,7 +136,7 @@ private: public: // CONSTRUCTORS explicit NameVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~NameVisitor() override {} + virtual ~NameVisitor() override = default; }; //###################################################################### diff --git a/src/V3Name.h b/src/V3Name.h index e998b5eb7..526858787 100644 --- a/src/V3Name.h +++ b/src/V3Name.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Name { +class V3Name final { public: static void nameAll(AstNetlist* nodep); }; diff --git a/src/V3Number.cpp b/src/V3Number.cpp index cf6ef219b..a2073dff7 100644 --- a/src/V3Number.cpp +++ b/src/V3Number.cpp @@ -227,7 +227,7 @@ void V3Number::V3NumberCreate(AstNode* nodep, const char* sourcep, FileLine* fl) if (product.bitsValue(width(), 4)) { // Overflowed static int warned = 0; v3error("Too many digits for " - << width() << " bit number: " << sourcep << std::endl + << width() << " bit number: " << sourcep << '\n' << ((!m_sized && !warned++) ? ( V3Error::warnMore() + "... As that number was unsized" + " ('d...) it is limited to 32 bits (IEEE 1800-2017 " @@ -937,10 +937,11 @@ bool V3Number::isAnyX() const { } return false; } -bool V3Number::isAnyXZ() const { +bool V3Number::isAnyXZ() const { return isAnyX() || isAnyZ(); } +bool V3Number::isAnyZ() const { if (isDouble() || isString()) return false; for (int bit = 0; bit < width(); bit++) { - if (bitIsX(bit) || bitIsZ(bit)) return true; + if (bitIsZ(bit)) return true; } return false; } @@ -1775,16 +1776,6 @@ V3Number& V3Number::opShiftL(const V3Number& lhs, const V3Number& rhs) { //====================================================================== // Ops - Arithmetic -V3Number& V3Number::opAbsS(const V3Number& lhs) { - // op i, L(lhs) bit return - NUM_ASSERT_OP_ARGS1(lhs); - if (lhs.isFourState()) return setAllBitsX(); - if (lhs.isNegative()) { - return opNegate(lhs); - } else { - return opAssign(lhs); - } -} V3Number& V3Number::opNegate(const V3Number& lhs) { // op i, L(lhs) bit return NUM_ASSERT_OP_ARGS1(lhs); diff --git a/src/V3Number.h b/src/V3Number.h index e19f4a767..240858ea9 100644 --- a/src/V3Number.h +++ b/src/V3Number.h @@ -37,7 +37,7 @@ inline bool v3EpsilonEqual(double a, double b) { class AstNode; -class V3Number { +class V3Number final { // Large 4-state number handling int m_width; // Width as specified/calculated. bool m_sized : 1; // True if the user specified the width, else we track it. @@ -273,6 +273,7 @@ public: void isSigned(bool ssigned) { m_signed = ssigned; } bool isAnyX() const; bool isAnyXZ() const; + bool isAnyZ() const; bool isMsbXZ() const { return bitIsXZ(m_width); } uint32_t toUInt() const; vlsint32_t toSInt() const; @@ -348,7 +349,6 @@ public: V3Number& opLogOr(const V3Number& lhs, const V3Number& rhs); V3Number& opLogEq(const V3Number& lhs, const V3Number& rhs); V3Number& opLogIf(const V3Number& lhs, const V3Number& rhs); - V3Number& opAbsS(const V3Number& lhs); V3Number& opNegate(const V3Number& lhs); V3Number& opAdd(const V3Number& lhs, const V3Number& rhs); V3Number& opSub(const V3Number& lhs, const V3Number& rhs); diff --git a/src/V3Options.cpp b/src/V3Options.cpp index 799c7ed87..8ccbd5c56 100644 --- a/src/V3Options.cpp +++ b/src/V3Options.cpp @@ -50,7 +50,7 @@ //###################################################################### // V3 Internal state -class V3OptionsImp { +class V3OptionsImp final { public: // TYPES typedef std::map> DirMap; // Directory listing @@ -99,8 +99,8 @@ public: m_libExtVs.push_back(libext); } } - V3OptionsImp() {} - ~V3OptionsImp() {} + V3OptionsImp() = default; + ~V3OptionsImp() = default; }; //###################################################################### @@ -547,8 +547,7 @@ void V3Options::filePathLookedMsg(FileLine* fl, const string& modname) { } else if (!shown_notfound_msg) { shown_notfound_msg = true; if (m_impp->m_incDirUsers.empty()) { - fl->v3error("This may be because there's no search path specified with -I." - << endl); + fl->v3error("This may be because there's no search path specified with -I."); } std::cerr << V3Error::warnMore() << "... Looked in:" << endl; for (const string& dir : m_impp->m_incDirUsers) { @@ -604,7 +603,11 @@ string V3Options::getenvBuiltins(const string& var) { } } +#ifdef __FreeBSD__ +string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "gmake"); } +#else string V3Options::getenvMAKE() { return V3Os::getenvStr("MAKE", "make"); } +#endif string V3Options::getenvPERL() { // return V3Os::getenvStr("PERL", "perl"); @@ -1102,7 +1105,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char } else if (onoff(sw, "-structs-unpacked", flag /*ref*/)) { m_structsPacked = flag; } else if (!strcmp(sw, "-sv")) { - m_defaultLanguage = V3LangCode::L1800_2005; + m_defaultLanguage = V3LangCode::L1800_2017; } else if (onoff(sw, "-threads-coarsen", flag /*ref*/)) { // Undocumented, debug m_threadsCoarsen = flag; } else if (onoff(sw, "-trace", flag /*ref*/)) { diff --git a/src/V3Options.h b/src/V3Options.h index da8bc0eb2..1c5b05ad5 100644 --- a/src/V3Options.h +++ b/src/V3Options.h @@ -33,7 +33,7 @@ class FileLine; //###################################################################### -class VOptionBool { +class VOptionBool final { // Class to track options that are either not specified (and default // true/false), versus user setting the option to true or false public: @@ -69,7 +69,7 @@ inline std::ostream& operator<<(std::ostream& os, const VOptionBool& rhs) { //###################################################################### -class VTimescale { +class VTimescale final { public: enum en : uint8_t { // clang-format off @@ -167,7 +167,7 @@ inline std::ostream& operator<<(std::ostream& os, const VTimescale& rhs) { //###################################################################### -class TraceFormat { +class TraceFormat final { public: enum en : uint8_t { VCD = 0, FST } m_e; // cppcheck-suppress noExplicitConstructor @@ -198,7 +198,7 @@ typedef std::set V3StringSet; //###################################################################### // Information given by --hierarchical-block option -class V3HierarchicalBlockOption { +class V3HierarchicalBlockOption final { public: // key:parameter name, value:value (as string) typedef std::map ParamStrMap; @@ -223,7 +223,7 @@ typedef std::map V3HierBlockOptSet; //###################################################################### // V3Options - Command line options -class V3Options { +class V3Options final { public: private: // TYPES diff --git a/src/V3Order.cpp b/src/V3Order.cpp index 7c555cd7f..4060c3c54 100644 --- a/src/V3Order.cpp +++ b/src/V3Order.cpp @@ -113,7 +113,7 @@ static bool domainsExclusive(const AstSenTree* fromp, const AstSenTree* top); // Functions for above graph classes void OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) { - if (debug()) cout << "-Info-Loop: " << vertexp << " " << endl; + if (debug()) cout << "-Info-Loop: " << vertexp << "\n"; if (OrderLogicVertex* vvertexp = dynamic_cast(vertexp)) { std::cerr << vvertexp->nodep()->fileline()->warnOther() << " Example path: " << vvertexp->nodep()->typeName() << endl; @@ -126,7 +126,7 @@ void OrderGraph::loopsVertexCb(V3GraphVertex* vertexp) { //###################################################################### -class OrderMoveDomScope { +class OrderMoveDomScope final { // Information stored for each unique loop, domain & scope trifecta public: V3ListEnt m_readyDomScopeE; // List of next ready dom scope @@ -186,11 +186,11 @@ inline std::ostream& operator<<(std::ostream& lhs, const OrderMoveDomScope& rhs) // Types of vertex we can create enum WhichVertex : uint8_t { WV_STD, WV_PRE, WV_PORD, WV_POST, WV_SETL, WV_MAX }; -class OrderUser { +class OrderUser final { // Stored in AstVarScope::user1p, a list of all the various vertices // that can exist for one given variable private: - OrderVarVertex* m_vertexp[WV_MAX]; // Vertex of each type (if non nullptr) + std::array m_vertexp; // Vertex of each type (if non nullptr) public: // METHODS OrderVarVertex* newVarUserVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varscp, @@ -219,7 +219,7 @@ public: OrderUser() { for (auto& vertexp : m_vertexp) vertexp = nullptr; } - ~OrderUser() {} + ~OrderUser() = default; }; //###################################################################### @@ -252,7 +252,7 @@ struct OrderVarFanoutCmp { // In addition it also check whether clock and data signals are mixed, and // produce a CLKDATA warning if so. // -class OrderClkMarkVisitor : public AstNVisitor { +class OrderClkMarkVisitor final : public AstNVisitor { private: bool m_hasClk = false; // flag indicating whether there is clock signal on rhs bool m_inClocked = false; // Currently inside a sequential block @@ -273,7 +273,7 @@ private: if (m_inClocked) { varrefp->v3warn( CLKDATA, "Clock used as data (on rhs of assignment) in sequential block " - << varrefp->prettyNameQ() << endl); + << varrefp->prettyNameQ()); } else { m_hasClk = true; UINFO(5, "node is already marked as clocker " << varrefp << endl); @@ -290,8 +290,8 @@ private: // do the marking if (m_hasClk) { if (nodep->lhsp()->width() > m_rightClkWidth) { - nodep->v3warn(CLKDATA, "Clock is assigned to part of data signal " << nodep->lhsp() - << endl); + nodep->v3warn(CLKDATA, "Clock is assigned to part of data signal " + << nodep->lhsp()->prettyNameQ()); UINFO(4, "CLKDATA: lhs with width " << nodep->lhsp()->width() << endl); UINFO(4, " but rhs clock with width " << m_rightClkWidth << endl); return; // skip the marking @@ -366,13 +366,13 @@ public: iterate(nodep); } while (m_newClkMarked); } - virtual ~OrderClkMarkVisitor() override {} + virtual ~OrderClkMarkVisitor() override = default; }; //###################################################################### // The class checks if the assignment generates a clock. -class OrderClkAssVisitor : public AstNVisitor { +class OrderClkAssVisitor final : public AstNVisitor { private: bool m_clkAss = false; // There is signals marked as clocker in the assignment // METHODS @@ -397,7 +397,7 @@ private: public: // CONSTRUCTORS explicit OrderClkAssVisitor(AstNode* nodep) { iterate(nodep); } - virtual ~OrderClkAssVisitor() override {} + virtual ~OrderClkAssVisitor() override = default; // METHODS bool isClkAss() const { return m_clkAss; } }; @@ -429,7 +429,7 @@ template class ProcessMoveBuildGraph { typedef std::unordered_map Logic2Move; public: - class MoveVertexMaker { + class MoveVertexMaker VL_NOT_FINAL { public: // Clients of ProcessMoveBuildGraph must supply MoveVertexMaker // which creates new T_MoveVertex's. Each new vertex wraps lvertexp @@ -457,7 +457,7 @@ public: : m_graphp{logicGraphp} , m_outGraphp{outGraphp} , m_vxMakerp{vxMakerp} {} - virtual ~ProcessMoveBuildGraph() {} + virtual ~ProcessMoveBuildGraph() = default; // METHODS void build() { @@ -551,7 +551,7 @@ private: //###################################################################### // OrderMoveVertexMaker and related -class OrderMoveVertexMaker : public ProcessMoveBuildGraph::MoveVertexMaker { +class OrderMoveVertexMaker final : public ProcessMoveBuildGraph::MoveVertexMaker { // MEMBERS V3Graph* m_pomGraphp; V3List* m_pomWaitingp; @@ -579,7 +579,8 @@ private: VL_UNCOPYABLE(OrderMoveVertexMaker); }; -class OrderMTaskMoveVertexMaker : public ProcessMoveBuildGraph::MoveVertexMaker { +class OrderMTaskMoveVertexMaker final + : public ProcessMoveBuildGraph::MoveVertexMaker { V3Graph* m_pomGraphp; public: @@ -602,7 +603,7 @@ private: VL_UNCOPYABLE(OrderMTaskMoveVertexMaker); }; -class OrderVerticesByDomainThenScope { +class OrderVerticesByDomainThenScope final { PartPtrIdMap m_ids; public: @@ -619,10 +620,10 @@ public: } }; -class MTaskVxIdLessThan { +class MTaskVxIdLessThan final { public: - MTaskVxIdLessThan() {} - virtual ~MTaskVxIdLessThan() {} + MTaskVxIdLessThan() = default; + virtual ~MTaskVxIdLessThan() = default; // Sort vertex's, which must be AbstractMTask's, into a deterministic // order by comparing their serial IDs. @@ -636,7 +637,7 @@ public: //###################################################################### // Order class functions -class OrderVisitor : public AstNVisitor { +class OrderVisitor final : public AstNVisitor { private: // NODE STATE // Forming graph: @@ -672,6 +673,7 @@ private: bool m_inClkAss = false; // Underneath AstAssign bool m_inPre = false; // Underneath AstAssignPre bool m_inPost = false; // Underneath AstAssignPost + bool m_inPostponed = false; // Underneath AstAssignPostponed OrderLogicVertex* m_activeSenVxp = nullptr; // Sensitivity vertex std::deque m_orderUserps; // All created OrderUser's for later deletion. // STATE... for inside process @@ -686,7 +688,7 @@ protected: private: // STATS - VDouble0 m_statCut[OrderVEdgeType::_ENUM_END]; // Count of each edge type cut + std::array m_statCut; // Count of each edge type cut // TYPES enum VarUsage : uint8_t { VU_NONE = 0, VU_CON = 1, VU_GEN = 2 }; @@ -755,7 +757,7 @@ private: AstMTaskBody* m_mtaskBodyp = nullptr; Logics m_logics; ExecMTask* m_execMTaskp = nullptr; - MTaskState() {} + MTaskState() = default; }; void processMTasks(); typedef enum : uint8_t { LOGIC_INITIAL, LOGIC_SETTLE } InitialLogicE; @@ -870,7 +872,7 @@ private: m_graph.userClearVertices(); // May be very large vector, so only report the "most important" // elements. Up to 10 of the widest - std::cerr << V3Error::warnMore() << "... Widest candidate vars to split:" << endl; + std::cerr << V3Error::warnMore() << "... Widest candidate vars to split:\n"; std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp()); std::unordered_set canSplitList; int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10; @@ -885,10 +887,10 @@ private: std::cerr << ", can split_var"; canSplitList.insert(varp); } - std::cerr << std::endl; + std::cerr << '\n'; } // Up to 10 of the most fanned out - std::cerr << V3Error::warnMore() << "... Most fanned out candidate vars to split:" << endl; + std::cerr << V3Error::warnMore() << "... Most fanned out candidate vars to split:\n"; std::stable_sort(m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarFanoutCmp()); lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10; for (int i = 0; i < lim; i++) { @@ -902,7 +904,7 @@ private: std::cerr << ", can split_var"; canSplitList.insert(varp); } - std::cerr << endl; + std::cerr << '\n'; } if (!canSplitList.empty()) { std::cerr << V3Error::warnMore() @@ -1043,7 +1045,8 @@ private: // We don't want to add extra edges if the logic block has many usages of same var bool gen = false; bool con = false; - if (nodep->access().isWriteOrRW()) gen = !(varscp->user4() & VU_GEN); + if (nodep->access().isWriteOrRW() && !m_inPostponed) + gen = !(varscp->user4() & VU_GEN); if (nodep->access().isReadOrRW()) { con = !(varscp->user4() & VU_CON); if ((varscp->user4() & VU_GEN) && !m_inClocked) { @@ -1173,6 +1176,11 @@ private: iterateNewStmt(nodep); m_inPost = false; } + virtual void visit(AstAlwaysPostponed* nodep) override { + VL_RESTORER(m_inPostponed); + m_inPostponed = true; + iterateNewStmt(nodep); + } virtual void visit(AstAlways* nodep) override { iterateNewStmt(nodep); } virtual void visit(AstAlwaysPublic* nodep) override { iterateNewStmt(nodep); } virtual void visit(AstAssignAlias* nodep) override { iterateNewStmt(nodep); } @@ -1573,9 +1581,9 @@ void OrderVisitor::processEdgeReport() { } } - *logp << "Signals and their clock domains:" << endl; + *logp << "Signals and their clock domains:\n"; stable_sort(report.begin(), report.end()); - for (const string& i : report) *logp << i << endl; + for (const string& i : report) *logp << i << '\n'; } void OrderVisitor::processMoveClear() { diff --git a/src/V3Order.h b/src/V3Order.h index 92be224f0..35c04cc57 100644 --- a/src/V3Order.h +++ b/src/V3Order.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Order { +class V3Order final { public: static void orderAll(AstNetlist* nodep); }; diff --git a/src/V3OrderGraph.h b/src/V3OrderGraph.h index a0cc562ef..579ea70bb 100644 --- a/src/V3OrderGraph.h +++ b/src/V3OrderGraph.h @@ -110,10 +110,10 @@ inline bool operator==(OrderVEdgeType::en lhs, const OrderVEdgeType& rhs) { //###################################################################### // Graph types -class OrderGraph : public V3Graph { +class OrderGraph final : public V3Graph { public: - OrderGraph() {} - virtual ~OrderGraph() override {} + OrderGraph() = default; + virtual ~OrderGraph() override = default; // Methods virtual void loopsVertexCb(V3GraphVertex* vertexp) override; }; @@ -121,10 +121,10 @@ public: //###################################################################### // Vertex types -class OrderEitherVertex : public V3GraphVertex { +class OrderEitherVertex VL_NOT_FINAL : public V3GraphVertex { AstScope* m_scopep; // Scope the vertex is in AstSenTree* m_domainp; // Clock domain (nullptr = to be computed as we iterate) - bool m_isFromInput; // From input, or derived therefrom (conservatively false) + bool m_isFromInput = false; // From input, or derived therefrom (conservatively false) protected: OrderEitherVertex(V3Graph* graphp, const OrderEitherVertex& old) : V3GraphVertex{graphp, old} @@ -136,9 +136,8 @@ public: OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp) : V3GraphVertex{graphp} , m_scopep{scopep} - , m_domainp{domainp} - , m_isFromInput{false} {} - virtual ~OrderEitherVertex() override {} + , m_domainp{domainp} {} + virtual ~OrderEitherVertex() override = default; virtual OrderEitherVertex* clone(V3Graph* graphp) const override = 0; // Methods virtual OrderVEdgeType type() const = 0; @@ -152,7 +151,7 @@ public: bool isFromInput() const { return m_isFromInput; } }; -class OrderInputsVertex : public OrderEitherVertex { +class OrderInputsVertex final : public OrderEitherVertex { OrderInputsVertex(V3Graph* graphp, const OrderInputsVertex& old) : OrderEitherVertex{graphp, old} {} @@ -161,7 +160,7 @@ public: : OrderEitherVertex{graphp, nullptr, domainp} { isFromInput(true); // By definition } - virtual ~OrderInputsVertex() override {} + virtual ~OrderInputsVertex() override = default; virtual OrderInputsVertex* clone(V3Graph* graphp) const override { return new OrderInputsVertex(graphp, *this); } @@ -172,7 +171,7 @@ public: virtual bool domainMatters() override { return false; } }; -class OrderLogicVertex : public OrderEitherVertex { +class OrderLogicVertex final : public OrderEitherVertex { AstNode* m_nodep; protected: @@ -184,7 +183,7 @@ public: OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep) : OrderEitherVertex{graphp, scopep, domainp} , m_nodep{nodep} {} - virtual ~OrderLogicVertex() override {} + virtual ~OrderLogicVertex() override = default; virtual OrderLogicVertex* clone(V3Graph* graphp) const override { return new OrderLogicVertex(graphp, *this); } @@ -198,10 +197,10 @@ public: virtual string dotColor() const override { return "yellow"; } }; -class OrderVarVertex : public OrderEitherVertex { +class OrderVarVertex VL_NOT_FINAL : public OrderEitherVertex { AstVarScope* m_varScp; - bool m_isClock; // Used as clock - bool m_isDelayed; // Set in a delayed assignment + bool m_isClock = false; // Used as clock + bool m_isDelayed = false; // Set in a delayed assignment protected: OrderVarVertex(V3Graph* graphp, const OrderVarVertex& old) : OrderEitherVertex{graphp, old} @@ -212,10 +211,8 @@ protected: public: OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderEitherVertex{graphp, scopep, nullptr} - , m_varScp{varScp} - , m_isClock{false} - , m_isDelayed{false} {} - virtual ~OrderVarVertex() override {} + , m_varScp{varScp} {} + virtual ~OrderVarVertex() override = default; virtual OrderVarVertex* clone(V3Graph* graphp) const override = 0; virtual OrderVEdgeType type() const override = 0; virtual FileLine* fileline() const override { return varScp()->fileline(); } @@ -227,14 +224,14 @@ public: bool isDelayed() const { return m_isDelayed; } }; -class OrderVarStdVertex : public OrderVarVertex { +class OrderVarStdVertex final : public OrderVarVertex { OrderVarStdVertex(V3Graph* graphp, const OrderVarStdVertex& old) : OrderVarVertex{graphp, old} {} public: OrderVarStdVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarStdVertex() override {} + virtual ~OrderVarStdVertex() override = default; virtual OrderVarStdVertex* clone(V3Graph* graphp) const override { return new OrderVarStdVertex(graphp, *this); } @@ -245,14 +242,14 @@ public: virtual string dotColor() const override { return "skyblue"; } virtual bool domainMatters() override { return true; } }; -class OrderVarPreVertex : public OrderVarVertex { +class OrderVarPreVertex final : public OrderVarVertex { OrderVarPreVertex(V3Graph* graphp, const OrderVarPreVertex& old) : OrderVarVertex{graphp, old} {} public: OrderVarPreVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarPreVertex() override {} + virtual ~OrderVarPreVertex() override = default; virtual OrderVarPreVertex* clone(V3Graph* graphp) const override { return new OrderVarPreVertex(graphp, *this); } @@ -263,7 +260,7 @@ public: virtual string dotColor() const override { return "lightblue"; } virtual bool domainMatters() override { return false; } }; -class OrderVarPostVertex : public OrderVarVertex { +class OrderVarPostVertex final : public OrderVarVertex { OrderVarPostVertex(V3Graph* graphp, const OrderVarPostVertex& old) : OrderVarVertex{graphp, old} {} @@ -274,21 +271,21 @@ public: return new OrderVarPostVertex(graphp, *this); } virtual OrderVEdgeType type() const override { return OrderVEdgeType::VERTEX_VARPOST; } - virtual ~OrderVarPostVertex() override {} + virtual ~OrderVarPostVertex() override = default; virtual string name() const override { return (cvtToHex(varScp()) + " POST\\n " + varScp()->name()); } virtual string dotColor() const override { return "CadetBlue"; } virtual bool domainMatters() override { return false; } }; -class OrderVarPordVertex : public OrderVarVertex { +class OrderVarPordVertex final : public OrderVarVertex { OrderVarPordVertex(V3Graph* graphp, const OrderVarPordVertex& old) : OrderVarVertex{graphp, old} {} public: OrderVarPordVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarPordVertex() override {} + virtual ~OrderVarPordVertex() override = default; virtual OrderVarPordVertex* clone(V3Graph* graphp) const override { return new OrderVarPordVertex(graphp, *this); } @@ -299,14 +296,14 @@ public: virtual string dotColor() const override { return "NavyBlue"; } virtual bool domainMatters() override { return false; } }; -class OrderVarSettleVertex : public OrderVarVertex { +class OrderVarSettleVertex final : public OrderVarVertex { OrderVarSettleVertex(V3Graph* graphp, const OrderVarSettleVertex& old) : OrderVarVertex{graphp, old} {} public: OrderVarSettleVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp) : OrderVarVertex{graphp, scopep, varScp} {} - virtual ~OrderVarSettleVertex() override {} + virtual ~OrderVarSettleVertex() override = default; virtual OrderVarSettleVertex* clone(V3Graph* graphp) const override { return new OrderVarSettleVertex(graphp, *this); } @@ -321,7 +318,7 @@ public: //###################################################################### //--- Following only under the move graph, not the main graph -class OrderMoveVertex : public V3GraphVertex { +class OrderMoveVertex final : public V3GraphVertex { typedef enum : uint8_t { POM_WAIT, POM_READY, POM_MOVED } OrderMState; OrderLogicVertex* m_logicp; @@ -342,7 +339,7 @@ public: , m_logicp{logicp} , m_state{POM_WAIT} , m_domScopep{nullptr} {} - virtual ~OrderMoveVertex() override {} + virtual ~OrderMoveVertex() override = default; virtual OrderMoveVertex* clone(V3Graph* graphp) const override { v3fatalSrc("Unsupported"); return nullptr; @@ -390,7 +387,7 @@ public: }; // Similar to OrderMoveVertex, but modified for threaded code generation. -class MTaskMoveVertex : public V3GraphVertex { +class MTaskMoveVertex final : public V3GraphVertex { // This could be more compact, since we know m_varp and m_logicp // cannot both be set. Each MTaskMoveVertex represents a logic node // or a var node, it can't be both. @@ -412,7 +409,7 @@ public: , m_domainp{domainp} { UASSERT(!(logicp && varp), "MTaskMoveVertex: logicp and varp may not both be set!\n"); } - virtual ~MTaskMoveVertex() override {} + virtual ~MTaskMoveVertex() override = default; virtual MTaskMoveVertex* clone(V3Graph* graphp) const override { v3fatalSrc("Unsupported"); return nullptr; @@ -448,7 +445,7 @@ public: //###################################################################### // Edge types -class OrderEdge : public V3GraphEdge { +class OrderEdge VL_NOT_FINAL : public V3GraphEdge { protected: OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const OrderEdge& old) : V3GraphEdge{graphp, fromp, top, old} {} @@ -457,7 +454,7 @@ public: OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = false) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~OrderEdge() override {} + virtual ~OrderEdge() override = default; virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_STD; } virtual OrderEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const override { @@ -473,7 +470,7 @@ public: } }; -class OrderComboCutEdge : public OrderEdge { +class OrderComboCutEdge final : public OrderEdge { // Edge created from output of combo logic // Breakable if the output var is also a input, // in which case we'll need a change detect loop around this var. @@ -485,7 +482,7 @@ public: OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge{graphp, fromp, top, WEIGHT_COMBO, CUTABLE} {} virtual OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_COMBOCUT; } - virtual ~OrderComboCutEdge() override {} + virtual ~OrderComboCutEdge() override = default; virtual OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const override { return new OrderComboCutEdge(graphp, fromp, top, *this); @@ -494,7 +491,7 @@ public: virtual bool followComboConnected() const override { return true; } }; -class OrderPostCutEdge : public OrderEdge { +class OrderPostCutEdge final : public OrderEdge { // Edge created from output of post assignment // Breakable if the output var feeds back to input combo logic or another clock pin // in which case we'll need a change detect loop around this var. @@ -506,7 +503,7 @@ public: OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : OrderEdge{graphp, fromp, top, WEIGHT_COMBO, CUTABLE} {} virtual OrderVEdgeType type() const override { return OrderVEdgeType::EDGE_POSTCUT; } - virtual ~OrderPostCutEdge() override {} + virtual ~OrderPostCutEdge() override = default; virtual OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const override { return new OrderPostCutEdge(graphp, fromp, top, *this); @@ -515,7 +512,7 @@ public: virtual bool followComboConnected() const override { return false; } }; -class OrderPreCutEdge : public OrderEdge { +class OrderPreCutEdge final : public OrderEdge { // Edge created from var_PREVAR->consuming logic vertex // Always breakable, just results in performance loss // in which case we can't optimize away the pre/post delayed assignments @@ -531,7 +528,7 @@ public: V3GraphVertex* top) const override { return new OrderPreCutEdge(graphp, fromp, top, *this); } - virtual ~OrderPreCutEdge() override {} + virtual ~OrderPreCutEdge() override = default; virtual string dotColor() const override { return "khaki"; } virtual bool followComboConnected() const override { return false; } }; diff --git a/src/V3Os.cpp b/src/V3Os.cpp index 299d5c104..b6d7375e5 100644 --- a/src/V3Os.cpp +++ b/src/V3Os.cpp @@ -252,12 +252,12 @@ void V3Os::unlinkRegexp(const string& dir, const string& regexp) { //###################################################################### // METHODS (random) -vluint64_t V3Os::rand64(vluint64_t* statep) { +vluint64_t V3Os::rand64(std::array& stater) { // Xoroshiro128+ algorithm - vluint64_t result = statep[0] + statep[1]; - statep[1] ^= statep[0]; - statep[0] = (((statep[0] << 55) | (statep[0] >> 9)) ^ statep[1] ^ (statep[1] << 14)); - statep[1] = (statep[1] << 36) | (statep[1] >> 28); + vluint64_t result = stater[0] + stater[1]; + stater[1] ^= stater[0]; + stater[0] = (((stater[0] << 55) | (stater[0] >> 9)) ^ stater[1] ^ (stater[1] << 14)); + stater[1] = (stater[1] << 36) | (stater[1] >> 28); return result; } diff --git a/src/V3Os.h b/src/V3Os.h index a107f36dc..a1eef9b86 100644 --- a/src/V3Os.h +++ b/src/V3Os.h @@ -20,13 +20,15 @@ #include "config_build.h" #include "verilatedos.h" +#include + // Limited V3 headers here - this is a base class for Vlc etc #include "V3Error.h" //============================================================================ // V3Os: OS static class -class V3Os { +class V3Os final { public: // METHODS (environment) static string getenvStr(const string& envvar, const string& defaultValue); @@ -55,7 +57,7 @@ public: static void unlinkRegexp(const string& dir, const string& regexp); // METHODS (random) - static vluint64_t rand64(vluint64_t* statep); + static vluint64_t rand64(std::array& stater); static string trueRandom(size_t size); // METHODS (time & performance) diff --git a/src/V3Param.cpp b/src/V3Param.cpp index 8b03ed87a..df9e60c1e 100644 --- a/src/V3Param.cpp +++ b/src/V3Param.cpp @@ -65,7 +65,8 @@ //###################################################################### // Hierarchical block and parameter db (modules without parameter is also handled) -class ParameterizedHierBlocks { + +class ParameterizedHierBlocks final { typedef std::multimap HierBlockOptsByOrigName; typedef HierBlockOptsByOrigName::const_iterator HierMapIt; typedef std::map HierBlockModMap; @@ -195,17 +196,17 @@ public: }; //###################################################################### -// Param state, as a visitor of each AstNode +// Remove parameters from cells and build new modules -class ParamVisitor : public AstNVisitor { -private: - // NODE STATE - // AstNodeModule::user5() // bool True if processed - // AstGenFor::user5() // bool True if processed - // AstVar::user5() // bool True if constant propagated +class ParamProcessor final { + // NODE STATE - Local // AstVar::user4() // int Global parameter number (for naming new module) // // (0=not processed, 1=iterated, but no number, // // 65+ parameter numbered) + // NODE STATE - Shared with ParamVisitor + // AstNodeModule::user5() // bool True if processed + // AstGenFor::user5() // bool True if processed + // AstVar::user5() // bool True if constant propagated // AstCell::user5p() // string* Generate portion of hierarchical name AstUser4InUse m_inuser4; AstUser5InUse m_inuser5; @@ -216,7 +217,7 @@ private: typedef std::deque> IfaceRefRefs; // STATE - typedef std::map CloneMap; + typedef std::unordered_map CloneMap; struct ModInfo { AstNodeModule* m_modp; // Module with specified name CloneMap m_cloneMap; // Map of old-varp -> new cloned varp @@ -239,17 +240,7 @@ private: ValueMap m_valueMap; // Hash of node hash to (param value, name) int m_nextValue = 1; // Next value to use in m_valueMap - typedef std::multimap LevelModMap; - LevelModMap m_todoModps; // Modules left to process - - typedef std::deque CellList; - CellList m_cellps; // Cells left to process (in this module) - - AstNodeFTask* m_ftaskp = nullptr; // Function/task reference AstNodeModule* m_modp = nullptr; // Current module being processed - string m_unlinkedTxt; // Text for AstUnlinkedRef - UnrollStateful m_unroller; // Loop unroller - string m_generateHierName; // Generate portion of hierarchy name // Database to get protect-lib wrapper that matches parameters in hierarchical Verilation ParameterizedHierBlocks m_hierBlocks; @@ -316,6 +307,26 @@ private: } return string("z") + cvtToStr(num); } + string moduleCalcName(AstNodeModule* srcModp, AstPin* paramsp, const string& longname) { + string newname = longname; + if (longname.length() > 30 || srcModp->hierBlock()) { + const auto iter = m_longMap.find(longname); + if (iter != m_longMap.end()) { + newname = iter->second; + } else { + if (srcModp->hierBlock()) { + newname = parametrizedHierBlockName(srcModp, paramsp); + } else { + newname = srcModp->name(); + // We use all upper case above, so lower here can't conflict + newname += "__pi" + cvtToStr(++m_longId); + } + m_longMap.insert(make_pair(longname, newname)); + } + } + UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl); + return newname; + } AstNodeDType* arraySubDTypep(AstNodeDType* nodep) { // If an unpacked array, return the subDTypep under it if (AstUnpackArrayDType* adtypep = VN_CAST(nodep, UnpackArrayDType)) { @@ -348,7 +359,7 @@ private: } } } - void relinkPins(CloneMap* clonemapp, AstPin* startpinp) { + void relinkPins(const CloneMap* clonemapp, AstPin* startpinp) { for (AstPin* pinp = startpinp; pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { if (pinp->modVarp()) { // Find it in the clone structure @@ -409,6 +420,7 @@ private: if (m_modNameMap.find(modName) != m_modNameMap.end()) return true; return false; } + string parametrizedHierBlockName(const AstNodeModule* modp, AstPin* paramPinsp) const { VHashSha256 hash; // Calculate hash using module name, parameter name, and parameter value @@ -436,7 +448,318 @@ private: hash.insert(V3Os::trueRandom(64)); } } - void visitCell(AstCell* nodep, const string& hierName); + void deepCloneModule(AstNodeModule* srcModp, AstNode* cellp, AstPin* paramsp, + const string& newname, const IfaceRefRefs& ifaceRefRefs) { + // Deep clone of new module + // Note all module internal variables will be re-linked to the new modules by clone + // However links outside the module (like on the upper cells) will not. + AstNodeModule* newmodp = srcModp->cloneTree(false); + newmodp->name(newname); + newmodp->user5(false); // We need to re-recurse this module once changed + newmodp->recursive(false); + newmodp->recursiveClone(false); + // Only the first generation of clone holds this property + newmodp->hierBlock(srcModp->hierBlock() && !srcModp->recursiveClone()); + // Recursion may need level cleanups + if (newmodp->level() <= m_modp->level()) newmodp->level(m_modp->level() + 1); + if ((newmodp->level() - srcModp->level()) >= (v3Global.opt.moduleRecursionDepth() - 2)) { + cellp->v3error("Exceeded maximum --module-recursion-depth of " + << v3Global.opt.moduleRecursionDepth()); + } + // Keep tree sorted by level + AstNodeModule* insertp = srcModp; + while (VN_IS(insertp->nextp(), NodeModule) + && VN_CAST(insertp->nextp(), NodeModule)->level() < newmodp->level()) { + insertp = VN_CAST(insertp->nextp(), NodeModule); + } + insertp->addNextHere(newmodp); + + m_modNameMap.insert(make_pair(newmodp->name(), ModInfo(newmodp))); + auto iter = m_modNameMap.find(newname); + CloneMap* clonemapp = &(iter->second.m_cloneMap); + UINFO(4, " De-parameterize to new: " << newmodp << endl); + + // Grab all I/O so we can remap our pins later + // Note we allow multiple users of a parameterized model, + // thus we need to stash this info. + collectPins(clonemapp, newmodp); + // Relink parameter vars to the new module + relinkPins(clonemapp, paramsp); + // Fix any interface references + for (auto it = ifaceRefRefs.cbegin(); it != ifaceRefRefs.cend(); ++it) { + AstIfaceRefDType* portIrefp = it->first; + AstIfaceRefDType* pinIrefp = it->second; + AstIfaceRefDType* cloneIrefp = portIrefp->clonep(); + UINFO(8, " IfaceOld " << portIrefp << endl); + UINFO(8, " IfaceTo " << pinIrefp << endl); + UASSERT_OBJ(cloneIrefp, portIrefp, "parameter clone didn't hit AstIfaceRefDType"); + UINFO(8, " IfaceClo " << cloneIrefp << endl); + cloneIrefp->ifacep(pinIrefp->ifaceViaCellp()); + UINFO(8, " IfaceNew " << cloneIrefp << endl); + } + // Assign parameters to the constants specified + // DOES clone() so must be finished with module clonep() before here + for (AstPin* pinp = paramsp; pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + if (pinp->exprp()) { + if (newmodp->hierBlock()) checkSupportedParam(newmodp, pinp); + if (AstVar* modvarp = pinp->modVarp()) { + AstNode* newp = pinp->exprp(); // Const or InitArray + // Remove any existing parameter + if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); + // Set this parameter to value requested by cell + modvarp->valuep(newp->cloneTree(false)); + modvarp->overriddenParam(true); + } else if (AstParamTypeDType* modptp = pinp->modPTypep()) { + AstNodeDType* dtypep = VN_CAST(pinp->exprp(), NodeDType); + UASSERT_OBJ(dtypep, pinp, "unlinked param dtype"); + if (modptp->childDTypep()) modptp->childDTypep()->unlinkFrBack()->deleteTree(); + // Set this parameter to value requested by cell + modptp->childDTypep(dtypep->cloneTree(false)); + // Later V3LinkDot will convert the ParamDType to a Typedef + // Not done here as may be localparams, etc, that also need conversion + } + } + } + } + const ModInfo* moduleFindOrClone(AstNodeModule* srcModp, AstNode* cellp, AstPin* paramsp, + const string& newname, const IfaceRefRefs& ifaceRefRefs) { + // Already made this flavor? + auto it = m_modNameMap.find(newname); + if (it != m_modNameMap.end()) { + UINFO(4, " De-parameterize to old: " << it->second.m_modp << endl); + } else { + deepCloneModule(srcModp, cellp, paramsp, newname, ifaceRefRefs); + it = m_modNameMap.find(newname); + UASSERT(it != m_modNameMap.end(), "should find just-made module"); + } + const ModInfo* modInfop = &(it->second); + return modInfop; + } + + void cellPinCleanup(AstNode* nodep, AstPin* pinp, AstNodeModule* srcModp, string& longnamer, + bool& any_overridesr) { + if (!pinp->exprp()) return; // No-connect + if (AstVar* modvarp = pinp->modVarp()) { + if (!modvarp->isGParam()) { + pinp->v3error("Attempted parameter setting of non-parameter: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } else if (VN_IS(pinp->exprp(), InitArray) && arraySubDTypep(modvarp->subDTypep())) { + // Array assigned to array + AstNode* exprp = pinp->exprp(); + longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); + any_overridesr = true; + } else { + AstConst* exprp = VN_CAST(pinp->exprp(), Const); + AstConst* origp = VN_CAST(modvarp->valuep(), Const); + if (!exprp) { + // if (debug()) pinp->dumpTree(cout, "error:"); + pinp->v3error("Can't convert defparam value to constant: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + pinp->exprp()->replaceWith(new AstConst( + pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0)); + } else if (origp && exprp->sameTree(origp)) { + // Setting parameter to its default value. Just ignore it. + // This prevents making additional modules, and makes coverage more + // obvious as it won't show up under a unique module page name. + } else if (exprp->num().isDouble() || exprp->num().isString() + || exprp->num().isFourState() || exprp->num().width() != 32) { + longnamer + += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp)); + any_overridesr = true; + } else { + longnamer + += ("_" + paramSmallName(srcModp, modvarp) + exprp->num().ascii(false)); + any_overridesr = true; + } + } + } else if (AstParamTypeDType* modvarp = pinp->modPTypep()) { + AstNodeDType* exprp = VN_CAST(pinp->exprp(), NodeDType); + AstNodeDType* origp = modvarp->subDTypep(); + if (!exprp) { + pinp->v3error("Parameter type pin value isn't a type: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } else if (!origp) { + pinp->v3error("Parameter type variable isn't a type: Param " + << modvarp->prettyNameQ()); + } else { + UINFO(9, "Parameter type assignment expr=" << exprp << " to " << origp << endl); + if (exprp->sameTree(origp)) { + // Setting parameter to its default value. Just ignore it. + // This prevents making additional modules, and makes coverage more + // obvious as it won't show up under a unique module page name. + } else { + V3Const::constifyParamsEdit(exprp); + longnamer += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); + any_overridesr = true; + } + } + } else { + pinp->v3error("Parameter not found in sub-module: Param " + << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); + } + } + + void cellInterfaceCleanup(AstCell* nodep, AstNodeModule* srcModp, string& longnamer, + bool& any_overridesr, IfaceRefRefs& ifaceRefRefs) { + for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + AstVar* modvarp = pinp->modVarp(); + if (modvarp->isIfaceRef()) { + AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); + if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) { + portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType); + } + AstIfaceRefDType* pinIrefp = nullptr; + AstNode* exprp = pinp->exprp(); + AstVar* varp + = (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr; + if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) { + pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType); + } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep()) + && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) { + pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType); + } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) + && VN_CAST(exprp->op1p(), VarRef)->varp() + && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() + && arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()) + && VN_CAST( + arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType)) { + pinIrefp = VN_CAST( + arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), + IfaceRefDType); + } + + UINFO(9, " portIfaceRef " << portIrefp << endl); + + if (!portIrefp) { + pinp->v3error("Interface port " << modvarp->prettyNameQ() + << " is not an interface " << modvarp); + } else if (!pinIrefp) { + pinp->v3error("Interface port " + << modvarp->prettyNameQ() + << " is not connected to interface/modport pin expression"); + } else { + UINFO(9, " pinIfaceRef " << pinIrefp << endl); + if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { + UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl); + longnamer += ("_" + paramSmallName(srcModp, pinp->modVarp()) + + paramValueNumber(pinIrefp)); + any_overridesr = true; + ifaceRefRefs.push_back(make_pair(portIrefp, pinIrefp)); + if (portIrefp->ifacep() != pinIrefp->ifacep() + // Might be different only due to param cloning, so check names too + && portIrefp->ifaceName() != pinIrefp->ifaceName()) { + pinp->v3error("Port " << pinp->prettyNameQ() << " expects " + << AstNode::prettyNameQ(portIrefp->ifaceName()) + << " interface but pin connects " + << AstNode::prettyNameQ(pinIrefp->ifaceName()) + << " interface"); + } + } + } + } + } + } + +public: + void cellDeparam(AstCell* nodep, AstNodeModule* modp, const string& hierName) { + m_modp = modp; + // Cell: Check for parameters in the instantiation. + // We always run this, even if no parameters, as need to look for interfaces, + // and remove any recursive references + UINFO(4, "De-parameterize: " << nodep << endl); + // Create new module name with _'s between the constants + if (debug() >= 10) nodep->dumpTree(cout, "-cell: "); + // Evaluate all module constants + V3Const::constifyParamsEdit(nodep); + AstNodeModule* srcModp = nodep->modp(); + srcModp->hierName(hierName + "." + nodep->name()); + + // Make sure constification worked + // Must be a separate loop, as constant conversion may have changed some pointers. + // if (debug()) nodep->dumpTree(cout, "-cel2: "); + string longname = srcModp->name() + "_"; + bool any_overrides = false; + // Must always clone __Vrcm (recursive modules) + if (nodep->recursive()) any_overrides = true; + if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); + + for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { + cellPinCleanup(nodep, pinp, srcModp, longname /*ref*/, any_overrides /*ref*/); + } + IfaceRefRefs ifaceRefRefs; + cellInterfaceCleanup(nodep, srcModp, longname /*ref*/, any_overrides /*ref*/, + ifaceRefRefs /*ref*/); + + if (!any_overrides) { + UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); + } else if (AstNodeModule* modp + = m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) { + nodep->modp(modp); + nodep->modName(modp->name()); + modp->dead(false); + // We need to relink the pins to the new module + relinkPinsByName(nodep->pinsp(), modp); + } else { + string newname = moduleCalcName(srcModp, nodep->paramsp(), longname); + const ModInfo* modInfop + = moduleFindOrClone(srcModp, nodep, nodep->paramsp(), newname, ifaceRefRefs); + // Have child use this module instead. + nodep->modp(modInfop->m_modp); + nodep->modName(newname); + // We need to relink the pins to the new module + relinkPins(&(modInfop->m_cloneMap), nodep->pinsp()); + UINFO(8, " Done with " << modInfop->m_modp << endl); + } + + nodep->recursive(false); + + // Delete the parameters from the cell; they're not relevant any longer. + if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); + UINFO(8, " Done with " << nodep << endl); + // if (debug() >= 10) + // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); + } + + // CONSTRUCTORS + ParamProcessor(AstNetlist* nodep) + : m_hierBlocks{v3Global.opt.hierBlocks(), nodep} { + for (AstNodeModule* modp = nodep->modulesp(); modp; + modp = VN_CAST(modp->nextp(), NodeModule)) { + m_allModuleNames.insert(modp->name()); + } + } + ~ParamProcessor() = default; + VL_UNCOPYABLE(ParamProcessor); +}; + +//###################################################################### +// Process parameter visitor + +class ParamVisitor final : public AstNVisitor { + // STATE + ParamProcessor m_processor; // De-parameterize a cell, build modules + UnrollStateful m_unroller; // Loop unroller + + AstNodeModule* m_modp = nullptr; // Current module being processed + string m_generateHierName; // Generate portion of hierarchy name + string m_unlinkedTxt; // Text for AstUnlinkedRef + std::deque m_cellps; // Cells left to process (in this module) + + typedef std::multimap LevelModMap; + LevelModMap m_todoModps; // Modules left to process + + // METHODS + VL_DEBUG_FUNC; // Declare debug() + + void visitCellDeparam(AstCell* nodep, const string& hierName) { + // Cell: Check for parameters in the instantiation. + iterateChildren(nodep); + UASSERT_OBJ(nodep->modp(), nodep, "Not linked?"); + m_processor.cellDeparam(nodep, m_modp, hierName); + // Remember to process the child module at the end of the module + m_todoModps.insert(make_pair(nodep->modp()->level(), nodep->modp())); + } void visitModules() { // Loop on all modules left to process // Hitting a cell adds to the appropriate level of this level-sorted list, @@ -459,30 +782,25 @@ private: if ((nonIf == 0 && VN_IS(cellp->modp(), Iface)) || (nonIf == 1 && !VN_IS(cellp->modp(), Iface))) { string fullName(m_modp->hierName()); - if (string* genHierNamep = (string*)cellp->user5p()) { + if (const string* genHierNamep = (string*)cellp->user5p()) { fullName += *genHierNamep; } - visitCell(cellp, fullName); + visitCellDeparam(cellp, fullName); + if (const string* genHierNamep = (string*)cellp->user5p()) { + cellp->user5p(nullptr); + VL_DO_DANGLING(delete genHierNamep, genHierNamep); + } } } } - for (AstCell* cellp : m_cellps) { - if (string* genHierNamep = (string*)cellp->user5p()) { - cellp->user5p(nullptr); - VL_DO_DANGLING(delete genHierNamep, genHierNamep); - } - } m_cellps.clear(); m_modp = nullptr; + UINFO(4, " MOD-done\n"); } } } // VISITORS - virtual void visit(AstNetlist* nodep) override { - // Modules must be done in top-down-order - iterateChildren(nodep); - } virtual void visit(AstNodeModule* nodep) override { if (nodep->dead()) { UINFO(4, " MOD-dead. " << nodep << endl); // Marked by LinkDot @@ -490,6 +808,8 @@ private: // Fake, made for recursive elimination UINFO(4, " MOD-recursive-dead. " << nodep << endl); nodep->dead(true); // So Dead checks won't count references to it + } else if (m_modp) { + UINFO(4, " MOD-under-MOD. " << nodep << endl); } else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top || VN_IS(nodep, Package)) { // Likewise haven't done wrapTopPackages yet // Add request to END of modules left to process @@ -509,42 +829,35 @@ private: nodep->user5p(genHierNamep); m_cellps.push_back(nodep); } - virtual void visit(AstNodeFTask* nodep) override { - m_ftaskp = nodep; - iterateChildren(nodep); - m_ftaskp = nullptr; - } // Make sure all parameters are constantified virtual void visit(AstVar* nodep) override { - if (!nodep->user5SetOnce()) { // Process once - iterateChildren(nodep); - if (nodep->isParam()) { - if (!nodep->valuep()) { - nodep->v3error("Parameter without initial value is never given value" - << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ()); - } else { - V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init() - if (!VN_IS(nodep->valuep(), Const) - && !VN_IS(nodep->valuep(), Unbounded)) { // Complex init, like an array - // Make a new INITIAL to set the value. - // This allows the normal array/struct handling code to properly - // initialize the parameter. - nodep->addNext(new AstInitial( - nodep->fileline(), - new AstAssign(nodep->fileline(), - new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), - nodep->valuep()->cloneTree(true)))); - if (m_ftaskp) { - // We put the initial in wrong place under a function. We - // should move the parameter out of the function and to the - // module, with appropriate dotting, but this confuses LinkDot - // (as then name isn't found later), so punt - probably can - // treat as static function variable when that is supported. - nodep->v3warn( - E_UNSUPPORTED, - "Unsupported: Parameters in functions with complex assign"); - } + if (nodep->user5SetOnce()) return; // Process once + iterateChildren(nodep); + if (nodep->isParam()) { + if (!nodep->valuep()) { + nodep->v3error("Parameter without initial value is never given value" + << " (IEEE 1800-2017 6.20.1): " << nodep->prettyNameQ()); + } else { + V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init() + if (!VN_IS(nodep->valuep(), Const) + && !VN_IS(nodep->valuep(), Unbounded)) { // Complex init, like an array + // Make a new INITIAL to set the value. + // This allows the normal array/struct handling code to properly + // initialize the parameter. + nodep->addNext(new AstInitial( + nodep->fileline(), + new AstAssign(nodep->fileline(), + new AstVarRef(nodep->fileline(), nodep, VAccess::WRITE), + nodep->valuep()->cloneTree(true)))); + if (nodep->isFuncLocal()) { + // We put the initial in wrong place under a function. We + // should move the parameter out of the function and to the + // module, with appropriate dotting, but this confuses LinkDot + // (as then name isn't found later), so punt - probably can + // treat as static function variable when that is supported. + nodep->v3warn(E_UNSUPPORTED, + "Unsupported: Parameters in functions with complex assign"); } } } @@ -552,6 +865,7 @@ private: } // Make sure varrefs cause vars to constify before things above virtual void visit(AstVarRef* nodep) override { + // Might jump across functions, so beware if ever add a m_funcp if (nodep->varp()) iterate(nodep->varp()); } bool ifaceParamReplace(AstVarXRef* nodep, AstNode* candp) { @@ -777,312 +1091,14 @@ private: public: // CONSTRUCTORS explicit ParamVisitor(AstNetlist* nodep) - : m_hierBlocks{v3Global.opt.hierBlocks(), nodep} { - for (AstNodeModule* modp = nodep->modulesp(); modp; - modp = VN_CAST(modp->nextp(), NodeModule)) { - m_allModuleNames.insert(modp->name()); - } - // + : m_processor{nodep} { + // Relies on modules already being in top-down-order iterate(nodep); } - virtual ~ParamVisitor() override {} + virtual ~ParamVisitor() override = default; + VL_UNCOPYABLE(ParamVisitor); }; -//---------------------------------------------------------------------- -// VISITs - -void ParamVisitor::visitCell(AstCell* nodep, const string& hierName) { - // Cell: Check for parameters in the instantiation. - iterateChildren(nodep); - UASSERT_OBJ(nodep->modp(), nodep, "Not linked?"); - // We always run this, even if no parameters, as need to look for interfaces, - // and remove any recursive references - { - UINFO(4, "De-parameterize: " << nodep << endl); - // Create new module name with _'s between the constants - if (debug() >= 10) nodep->dumpTree(cout, "-cell: "); - // Evaluate all module constants - V3Const::constifyParamsEdit(nodep); - AstNodeModule* srcModp = nodep->modp(); - srcModp->hierName(hierName + "." + nodep->name()); - - // Make sure constification worked - // Must be a separate loop, as constant conversion may have changed some pointers. - // if (debug()) nodep->dumpTree(cout, "-cel2: "); - string longname = srcModp->name(); - bool any_overrides = false; - // Must always clone __Vrcm (recursive modules) - if (nodep->recursive()) any_overrides = true; - longname += "_"; - if (debug() > 8) nodep->paramsp()->dumpTreeAndNext(cout, "-cellparams: "); - for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - if (!pinp->exprp()) continue; // No-connect - if (AstVar* modvarp = pinp->modVarp()) { - if (!modvarp->isGParam()) { - pinp->v3error("Attempted parameter setting of non-parameter: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } else if (VN_IS(pinp->exprp(), InitArray) - && arraySubDTypep(modvarp->subDTypep())) { - // Array assigned to array - AstNode* exprp = pinp->exprp(); - longname += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); - any_overrides = true; - } else { - AstConst* exprp = VN_CAST(pinp->exprp(), Const); - AstConst* origp = VN_CAST(modvarp->valuep(), Const); - if (!exprp) { - // if (debug()) pinp->dumpTree(cout, "error:"); - pinp->v3error("Can't convert defparam value to constant: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - pinp->exprp()->replaceWith(new AstConst( - pinp->fileline(), AstConst::WidthedValue(), modvarp->width(), 0)); - } else if (origp && exprp->sameTree(origp)) { - // Setting parameter to its default value. Just ignore it. - // This prevents making additional modules, and makes coverage more - // obvious as it won't show up under a unique module page name. - } else if (exprp->num().isDouble() || exprp->num().isString() - || exprp->num().isFourState() || exprp->num().width() != 32) { - longname - += ("_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp)); - any_overrides = true; - } else { - longname += ("_" + paramSmallName(srcModp, modvarp) - + exprp->num().ascii(false)); - any_overrides = true; - } - } - } else if (AstParamTypeDType* modvarp = pinp->modPTypep()) { - AstNodeDType* exprp = VN_CAST(pinp->exprp(), NodeDType); - AstNodeDType* origp = modvarp->subDTypep(); - if (!exprp) { - pinp->v3error("Parameter type pin value isn't a type: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } else if (!origp) { - pinp->v3error("Parameter type variable isn't a type: Param " - << modvarp->prettyNameQ()); - } else { - UINFO(9, - "Parameter type assignment expr=" << exprp << " to " << origp << endl); - if (exprp->sameTree(origp)) { - // Setting parameter to its default value. Just ignore it. - // This prevents making additional modules, and makes coverage more - // obvious as it won't show up under a unique module page name. - } else { - V3Const::constifyParamsEdit(exprp); - longname - += "_" + paramSmallName(srcModp, modvarp) + paramValueNumber(exprp); - any_overrides = true; - } - } - } else { - pinp->v3error("Parameter not found in sub-module: Param " - << pinp->prettyNameQ() << " of " << nodep->prettyNameQ()); - } - } - IfaceRefRefs ifaceRefRefs; - for (AstPin* pinp = nodep->pinsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - AstVar* modvarp = pinp->modVarp(); - if (modvarp->isIfaceRef()) { - AstIfaceRefDType* portIrefp = VN_CAST(modvarp->subDTypep(), IfaceRefDType); - if (!portIrefp && arraySubDTypep(modvarp->subDTypep())) { - portIrefp = VN_CAST(arraySubDTypep(modvarp->subDTypep()), IfaceRefDType); - } - - AstIfaceRefDType* pinIrefp = nullptr; - AstNode* exprp = pinp->exprp(); - AstVar* varp - = (exprp && VN_IS(exprp, VarRef)) ? VN_CAST(exprp, VarRef)->varp() : nullptr; - if (varp && varp->subDTypep() && VN_IS(varp->subDTypep(), IfaceRefDType)) { - pinIrefp = VN_CAST(varp->subDTypep(), IfaceRefDType); - } else if (varp && varp->subDTypep() && arraySubDTypep(varp->subDTypep()) - && VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType)) { - pinIrefp = VN_CAST(arraySubDTypep(varp->subDTypep()), IfaceRefDType); - } else if (exprp && exprp->op1p() && VN_IS(exprp->op1p(), VarRef) - && VN_CAST(exprp->op1p(), VarRef)->varp() - && VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep() - && arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()) - && VN_CAST( - arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), - IfaceRefDType)) { - pinIrefp = VN_CAST( - arraySubDTypep(VN_CAST(exprp->op1p(), VarRef)->varp()->subDTypep()), - IfaceRefDType); - } - - UINFO(9, " portIfaceRef " << portIrefp << endl); - - if (!portIrefp) { - pinp->v3error("Interface port " << modvarp->prettyNameQ() - << " is not an interface " << modvarp); - } else if (!pinIrefp) { - pinp->v3error("Interface port " - << modvarp->prettyNameQ() - << " is not connected to interface/modport pin expression"); - } else { - UINFO(9, " pinIfaceRef " << pinIrefp << endl); - if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) { - UINFO(9, " IfaceRefDType needs reconnect " << pinIrefp << endl); - longname += ("_" + paramSmallName(srcModp, pinp->modVarp()) - + paramValueNumber(pinIrefp)); - any_overrides = true; - ifaceRefRefs.push_back(make_pair(portIrefp, pinIrefp)); - if (portIrefp->ifacep() != pinIrefp->ifacep() - // Might be different only due to param cloning, so check names too - && portIrefp->ifaceName() != pinIrefp->ifaceName()) { - pinp->v3error("Port " << pinp->prettyNameQ() << " expects " - << AstNode::prettyNameQ(portIrefp->ifaceName()) - << " interface but pin connects " - << AstNode::prettyNameQ(pinIrefp->ifaceName()) - << " interface"); - } - } - } - } - } - - if (!any_overrides) { - UINFO(8, "Cell parameters all match original values, skipping expansion.\n"); - } else if (AstNodeModule* modp - = m_hierBlocks.findByParams(srcModp->name(), nodep->paramsp(), m_modp)) { - nodep->modp(modp); - nodep->modName(modp->name()); - modp->dead(false); - // We need to relink the pins to the new module - relinkPinsByName(nodep->pinsp(), modp); - } else { - // If the name is very long, we don't want to overwhelm the filename limit - // We don't do this always, as it aids debugability to have intuitive naming. - // TODO can use new V3Name hash replacement instead of this - // Shorter name is convenient for hierarchical block - string newname = longname; - if (longname.length() > 30 || srcModp->hierBlock()) { - const auto iter = m_longMap.find(longname); - if (iter != m_longMap.end()) { - newname = iter->second; - } else { - if (srcModp->hierBlock()) { - newname = parametrizedHierBlockName(srcModp, nodep->paramsp()); - } else { - newname = srcModp->name(); - // We use all upper case above, so lower here can't conflict - newname += "__pi" + cvtToStr(++m_longId); - } - m_longMap.insert(make_pair(longname, newname)); - } - } - UINFO(4, "Name: " << srcModp->name() << "->" << longname << "->" << newname << endl); - - // - // Already made this flavor? - AstNodeModule* cellmodp = nullptr; - auto iter = m_modNameMap.find(newname); - if (iter != m_modNameMap.end()) cellmodp = iter->second.m_modp; - if (!cellmodp) { - // Deep clone of new module - // Note all module internal variables will be re-linked to the new modules by clone - // However links outside the module (like on the upper cells) will not. - cellmodp = srcModp->cloneTree(false); - cellmodp->name(newname); - cellmodp->user5(false); // We need to re-recurse this module once changed - cellmodp->recursive(false); - cellmodp->recursiveClone(false); - // Only the first generation of clone holds this property - cellmodp->hierBlock(srcModp->hierBlock() && !srcModp->recursiveClone()); - nodep->recursive(false); - // Recursion may need level cleanups - if (cellmodp->level() <= m_modp->level()) cellmodp->level(m_modp->level() + 1); - if ((cellmodp->level() - srcModp->level()) - >= (v3Global.opt.moduleRecursionDepth() - 2)) { - nodep->v3error("Exceeded maximum --module-recursion-depth of " - << v3Global.opt.moduleRecursionDepth()); - } - // Keep tree sorted by level - AstNodeModule* insertp = srcModp; - while (VN_IS(insertp->nextp(), NodeModule) - && VN_CAST(insertp->nextp(), NodeModule)->level() < cellmodp->level()) { - insertp = VN_CAST(insertp->nextp(), NodeModule); - } - insertp->addNextHere(cellmodp); - - m_modNameMap.insert(make_pair(cellmodp->name(), ModInfo(cellmodp))); - iter = m_modNameMap.find(newname); - CloneMap* clonemapp = &(iter->second.m_cloneMap); - UINFO(4, " De-parameterize to new: " << cellmodp << endl); - - // Grab all I/O so we can remap our pins later - // Note we allow multiple users of a parameterized model, - // thus we need to stash this info. - collectPins(clonemapp, cellmodp); - // Relink parameter vars to the new module - relinkPins(clonemapp, nodep->paramsp()); - - // Fix any interface references - for (IfaceRefRefs::iterator it = ifaceRefRefs.begin(); it != ifaceRefRefs.end(); - ++it) { - AstIfaceRefDType* portIrefp = it->first; - AstIfaceRefDType* pinIrefp = it->second; - AstIfaceRefDType* cloneIrefp = portIrefp->clonep(); - UINFO(8, " IfaceOld " << portIrefp << endl); - UINFO(8, " IfaceTo " << pinIrefp << endl); - UASSERT_OBJ(cloneIrefp, portIrefp, - "parameter clone didn't hit AstIfaceRefDType"); - UINFO(8, " IfaceClo " << cloneIrefp << endl); - cloneIrefp->ifacep(pinIrefp->ifaceViaCellp()); - UINFO(8, " IfaceNew " << cloneIrefp << endl); - } - // Assign parameters to the constants specified - // DOES clone() so must be finished with module clonep() before here - for (AstPin* pinp = nodep->paramsp(); pinp; pinp = VN_CAST(pinp->nextp(), Pin)) { - if (pinp->exprp()) { - if (cellmodp->hierBlock()) checkSupportedParam(cellmodp, pinp); - if (AstVar* modvarp = pinp->modVarp()) { - AstNode* newp = pinp->exprp(); // Const or InitArray - // Remove any existing parameter - if (modvarp->valuep()) modvarp->valuep()->unlinkFrBack()->deleteTree(); - // Set this parameter to value requested by cell - modvarp->valuep(newp->cloneTree(false)); - modvarp->overriddenParam(true); - } else if (AstParamTypeDType* modptp = pinp->modPTypep()) { - AstNodeDType* dtypep = VN_CAST(pinp->exprp(), NodeDType); - UASSERT_OBJ(dtypep, pinp, "unlinked param dtype"); - if (modptp->childDTypep()) { - pushDeletep(modptp->childDTypep()->unlinkFrBack()); - } - // Set this parameter to value requested by cell - modptp->childDTypep(dtypep->cloneTree(false)); - // Later V3LinkDot will convert the ParamDType to a Typedef - // Not done here as may be localparams, etc, that also need conversion - } - } - } - - } else { - UINFO(4, " De-parameterize to old: " << cellmodp << endl); - } - - // Have child use this module instead. - nodep->modp(cellmodp); - nodep->modName(newname); - - // We need to relink the pins to the new module - CloneMap* clonemapp = &(iter->second.m_cloneMap); - relinkPins(clonemapp, nodep->pinsp()); - UINFO(8, " Done with " << cellmodp << endl); - } // if any_overrides - - nodep->recursive(false); - - // Delete the parameters from the cell; they're not relevant any longer. - if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree(); - UINFO(8, " Done with " << nodep << endl); - // if (debug() >= 10) - // v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree")); - } - - // Now remember to process the child module at the end of the module - m_todoModps.insert(make_pair(nodep->modp()->level(), nodep->modp())); -} - //###################################################################### // Param class functions diff --git a/src/V3Param.h b/src/V3Param.h index a2354de03..750e4177c 100644 --- a/src/V3Param.h +++ b/src/V3Param.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Param { +class V3Param final { public: static void param(AstNetlist* rootp); }; diff --git a/src/V3Parse.h b/src/V3Parse.h index 47bb0206e..198af1757 100644 --- a/src/V3Parse.h +++ b/src/V3Parse.h @@ -30,7 +30,7 @@ class V3ParseSym; //============================================================================ -class V3Parse { +class V3Parse final { private: V3ParseImp* m_impp; diff --git a/src/V3ParseGrammar.cpp b/src/V3ParseGrammar.cpp index 329631792..e49b8f5d8 100644 --- a/src/V3ParseGrammar.cpp +++ b/src/V3ParseGrammar.cpp @@ -14,6 +14,8 @@ // //************************************************************************* +#define YYDEBUG 1 // Nicer errors + #include "V3Ast.h" // This must be before V3ParseBison.cpp, as we don't want #defines to conflict //====================================================================== diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h index c460ee22a..eb5dc8a6f 100644 --- a/src/V3ParseImp.h +++ b/src/V3ParseImp.h @@ -70,8 +70,8 @@ struct VMemberQualifiers { } void applyToNodes(AstNodeFTask* nodesp) const { for (AstNodeFTask* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), NodeFTask)) { - // Ignored for now: m_local - // Ignored for now: m_protected + if (m_local) nodep->isHideLocal(true); + if (m_protected) nodep->isHideProtected(true); if (m_virtual) nodep->isVirtual(true); if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); if (m_static) nodep->lifetime(VLifetime::STATIC); @@ -83,10 +83,10 @@ struct VMemberQualifiers { } void applyToNodes(AstVar* nodesp) const { for (AstVar* nodep = nodesp; nodep; nodep = VN_CAST(nodep->nextp(), Var)) { - // Ignored for now: m_local - // Ignored for now: m_protected // Ignored for now: m_rand // Ignored for now: m_randc + if (m_local) nodep->isHideLocal(true); + if (m_protected) nodep->isHideProtected(true); if (m_automatic) nodep->lifetime(VLifetime::AUTOMATIC); if (m_static) nodep->lifetime(VLifetime::STATIC); if (m_const) nodep->isConst(true); @@ -156,7 +156,7 @@ std::ostream& operator<<(std::ostream& os, const V3ParseBisonYYSType& rhs); //###################################################################### -class V3ParseImp { +class V3ParseImp final { // MEMBERS AstNetlist* m_rootp; // Root of the design VInFilter* m_filterp; // Reading filter diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp index 45f0cfb96..04bfa9b90 100644 --- a/src/V3ParseLex.cpp +++ b/src/V3ParseLex.cpp @@ -32,12 +32,12 @@ // Lex-derived class /// Override the base lexer class so we can add some access functions -class V3Lexer : public V3LexerBase { +class V3Lexer final : public V3LexerBase { public: // CONSTRUCTORS V3Lexer() : V3LexerBase{nullptr} {} - ~V3Lexer() override {} + ~V3Lexer() override = default; // METHODS void unputString(const char* textp, size_t length) { // Add characters to input stream in back-to-front order diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h index 3837aa096..42045f273 100644 --- a/src/V3ParseSym.h +++ b/src/V3ParseSym.h @@ -30,7 +30,7 @@ //###################################################################### // Symbol table for parsing -class V3ParseSym { +class V3ParseSym final { // TYPES typedef std::vector SymStack; @@ -50,7 +50,7 @@ public: pushScope(findNewTable(rootp)); m_symCurrentp = symCurrentp(); } - ~V3ParseSym() {} + ~V3ParseSym() = default; private: // METHODS diff --git a/src/V3Partition.cpp b/src/V3Partition.cpp index abfb6ce0d..c48f8737a 100644 --- a/src/V3Partition.cpp +++ b/src/V3Partition.cpp @@ -243,7 +243,7 @@ private: VL_UNCOPYABLE(PartPropagateCp); }; -class PartPropagateCpSelfTest { +class PartPropagateCpSelfTest final { private: // MEMBERS V3Graph m_graph; // A graph @@ -253,8 +253,8 @@ private: CpMap m_seen; // Set of vertices we've seen // CONSTRUCTORS - PartPropagateCpSelfTest() {} - ~PartPropagateCpSelfTest() {} + PartPropagateCpSelfTest() = default; + ~PartPropagateCpSelfTest() = default; // METHODS protected: @@ -306,7 +306,8 @@ private: } void go() { // Generate a pseudo-random graph - vluint64_t rngState[2] = {0x12345678ULL, 0x9abcdef0ULL}; + std::array rngState + = {{0x12345678ULL, 0x9abcdef0ULL}}; // GCC 3.8.0 wants {{}} // Create 50 vertices for (auto& i : m_vx) i = new V3GraphVertex(&m_graph); // Create 250 edges at random. Edges must go from @@ -350,7 +351,7 @@ public: //###################################################################### // LogicMTask -class LogicMTask : public AbstractLogicMTask { +class LogicMTask final : public AbstractLogicMTask { public: // TYPES typedef std::list VxList; @@ -366,10 +367,10 @@ public: // - PartPropagateCp can thus be declared before LogicMTask // - PartPropagateCp could be reused with graphs of other node types // in the future, using another Accessor adaptor. - class CpCostAccessor { + class CpCostAccessor final { public: - CpCostAccessor() {} - ~CpCostAccessor() {} + CpCostAccessor() = default; + ~CpCostAccessor() = default; // Return cost of this node uint32_t cost(const V3GraphVertex* vxp) const { const LogicMTask* mtaskp = dynamic_cast(vxp); @@ -425,7 +426,7 @@ private: // Cost of critical paths going FORWARD from graph-start to the start // of this vertex, and also going REVERSE from the end of the graph to // the end of the vertex. Same units as m_cost. - uint32_t m_critPathCost[GraphWay::NUM_WAYS]; + std::array m_critPathCost; uint32_t m_serialId; // Unique MTask ID number @@ -443,7 +444,7 @@ private: // relatives in longest-to-shortest CP order. We rely on this ordering // in more than one place. typedef SortByValueMap EdgeSet; - EdgeSet m_edges[GraphWay::NUM_WAYS]; + std::array m_edges; public: // CONSTRUCTORS @@ -663,7 +664,7 @@ public: // Dump for (const LogicMTask* mtaskp : path) { - *osp << "begin mtask with cost " << mtaskp->cost() << endl; + *osp << "begin mtask with cost " << mtaskp->cost() << '\n'; for (VxList::const_iterator lit = mtaskp->vertexListp()->begin(); lit != mtaskp->vertexListp()->end(); ++lit) { const OrderLogicVertex* logicp = (*lit)->logicp(); @@ -690,17 +691,17 @@ private: // Sort AbstractMTask objects into deterministic order by calling id() // which is a unique and stable serial number. -class MTaskIdLessThan { +class MTaskIdLessThan final { public: - MTaskIdLessThan() {} - virtual ~MTaskIdLessThan() {} + MTaskIdLessThan() = default; + virtual ~MTaskIdLessThan() = default; virtual bool operator()(const AbstractMTask* lhsp, const AbstractMTask* rhsp) const { return lhsp->id() < rhsp->id(); } }; // Information associated with scoreboarding an MTask -class MergeCandidate { +class MergeCandidate VL_NOT_FINAL { private: bool m_removedFromSb = false; // Not on scoreboard, generally ignore vluint64_t m_id; // Serial number for ordering @@ -720,7 +721,7 @@ public: // A pair of associated LogicMTask's that are merge candidates for sibling // contraction -class SiblingMC : public MergeCandidate { +class SiblingMC final : public MergeCandidate { private: LogicMTask* m_ap; LogicMTask* m_bp; @@ -739,7 +740,7 @@ public: m_bp = ap; } } - virtual ~SiblingMC() {} + virtual ~SiblingMC() = default; // METHODS LogicMTask* ap() const { return m_ap; } LogicMTask* bp() const { return m_bp; } @@ -755,7 +756,7 @@ public: }; // GraphEdge for the MTask graph -class MTaskEdge : public V3GraphEdge, public MergeCandidate { +class MTaskEdge final : public V3GraphEdge, public MergeCandidate { public: // CONSTRUCTORS MTaskEdge(V3Graph* graphp, LogicMTask* fromp, LogicMTask* top, int weight) @@ -801,7 +802,7 @@ private: //###################################################################### // Vertex utility classes -class OrderByPtrId { +class OrderByPtrId final { PartPtrIdMap m_ids; public: @@ -815,7 +816,7 @@ public: //###################################################################### // PartParallelismEst - Estimate parallelism of graph -class PartParallelismEst { +class PartParallelismEst final { // MEMBERS const V3Graph* m_graphp; // Mtask-containing graph @@ -1028,7 +1029,7 @@ static void partMergeEdgesFrom(V3Graph* mtasksp, LogicMTask* recipientp, LogicMT // PartContraction // Perform edge or sibling contraction on the partition graph -class PartContraction { +class PartContraction final { private: // TYPES @@ -1633,7 +1634,7 @@ const GraphWay* PartContraction::s_shortestWaywardCpInclusiveWay = nullptr; // Scan node, indicate whether it contains a call to a DPI imported // routine. -class DpiImportCallVisitor : public AstNVisitor { +class DpiImportCallVisitor final : public AstNVisitor { private: bool m_hasDpiHazard = false; // Found a DPI import call. bool m_tracingCall = false; // Iterating into a CCall to a CFunc @@ -1663,7 +1664,7 @@ public: // CONSTRUCTORS explicit DpiImportCallVisitor(AstNode* nodep) { iterate(nodep); } bool hasDpiHazard() const { return m_hasDpiHazard; } - virtual ~DpiImportCallVisitor() override {} + virtual ~DpiImportCallVisitor() override = default; private: VL_UNCOPYABLE(DpiImportCallVisitor); @@ -1753,7 +1754,7 @@ private: // clock signal. This leads to unordered reader/writer pairs in // parallel mode. // -class PartFixDataHazards { +class PartFixDataHazards final { private: // TYPES typedef std::set LogicMTaskSet; @@ -2015,7 +2016,7 @@ private: // depending on which thread is looking. Be a little bit pessimistic when // thread A checks the end time of an mtask running on thread B. This extra // "padding" avoids tight "layovers" at cross-thread dependencies. -class PartPackMTasks { +class PartPackMTasks final { private: // TYPES struct MTaskState { @@ -2052,7 +2053,7 @@ public: , m_sandbagNumerator{sandbagNumerator} , m_sandbagDenom{sandbagDenom} , m_ready{m_mtaskCmp} {} - ~PartPackMTasks() {} + ~PartPackMTasks() = default; // METHODS uint32_t completionTime(const ExecMTask* mtaskp, uint32_t thread) { @@ -2252,8 +2253,8 @@ void V3Partition::debugMTaskGraphStats(const V3Graph* graphp, const string& stag UINFO(4, " Stats for " << stage << endl); uint32_t mtaskCount = 0; uint32_t totalCost = 0; - uint32_t mtaskCostHist[32]; - memset(mtaskCostHist, 0, sizeof(mtaskCostHist)); + std::array mtaskCostHist; + mtaskCostHist.fill(0); for (const V3GraphVertex* mtaskp = graphp->verticesBeginp(); mtaskp; mtaskp = mtaskp->verticesNextp()) { diff --git a/src/V3Partition.h b/src/V3Partition.h index 231ebf8d2..0a91c6010 100644 --- a/src/V3Partition.h +++ b/src/V3Partition.h @@ -34,14 +34,14 @@ typedef std::unordered_map Vx2MTaskMap; /// of which contains of set of the logic nodes from the fine-grained /// graph. -class V3Partition { +class V3Partition final { // MEMBERS V3Graph* m_fineDepsGraphp; // Fine-grained dependency graph public: // CONSTRUCTORS explicit V3Partition(V3Graph* fineDepsGraphp) : m_fineDepsGraphp{fineDepsGraphp} {} - ~V3Partition() {} + ~V3Partition() = default; // METHODS @@ -73,7 +73,7 @@ private: //************************************************************************* // Map a pointer into a id, for e.g. nodep to mtask mappings -class PartPtrIdMap { +class PartPtrIdMap final { private: // TYPES typedef std::unordered_map PtrMap; @@ -83,7 +83,7 @@ private: public: // CONSTRUCTORS - PartPtrIdMap() {} + PartPtrIdMap() = default; // METHODS vluint64_t findId(const void* ptrp) const { const auto it = m_id.find(ptrp); diff --git a/src/V3PartitionGraph.h b/src/V3PartitionGraph.h index d79fa83e7..74276c92d 100644 --- a/src/V3PartitionGraph.h +++ b/src/V3PartitionGraph.h @@ -28,23 +28,23 @@ //************************************************************************* // MTasks and graph structures -class AbstractMTask : public V3GraphVertex { +class AbstractMTask VL_NOT_FINAL : public V3GraphVertex { public: AbstractMTask(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~AbstractMTask() override {} + virtual ~AbstractMTask() override = default; virtual uint32_t id() const = 0; virtual uint32_t cost() const = 0; }; -class AbstractLogicMTask : public AbstractMTask { +class AbstractLogicMTask VL_NOT_FINAL : public AbstractMTask { public: // TYPES typedef std::list VxList; // CONSTRUCTORS AbstractLogicMTask(V3Graph* graphp) : AbstractMTask{graphp} {} - virtual ~AbstractLogicMTask() override {} + virtual ~AbstractLogicMTask() override = default; // METHODS // Set of logic vertices in this mtask. Order is not significant. virtual const VxList* vertexListp() const = 0; @@ -52,7 +52,7 @@ public: virtual uint32_t cost() const override = 0; }; -class ExecMTask : public AbstractMTask { +class ExecMTask final : public AbstractMTask { private: AstMTaskBody* m_bodyp; // Task body uint32_t m_id; // Unique id of this mtask. diff --git a/src/V3PreLex.h b/src/V3PreLex.h index 34f978de0..ee801421f 100644 --- a/src/V3PreLex.h +++ b/src/V3PreLex.h @@ -126,7 +126,7 @@ void yy_delete_buffer(YY_BUFFER_STATE b); //====================================================================== // Entry for each file processed; a stack of entries included -class VPreStream { +class VPreStream final { public: FileLine* m_curFilelinep; // Current processing point (see also m_tokFilelinep) V3PreLex* m_lexp; // Lexer, for resource tracking @@ -149,7 +149,7 @@ private: //====================================================================== // Class entry for each per-lexer state -class V3PreLex { +class V3PreLex final { public: // Used only by V3PreLex.cpp and V3PreProc.cpp V3PreProcImp* m_preimpp; // Preprocessor lexor belongs to std::stack m_streampStack; // Stack of processing files diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp index 0b1b0d782..122385e8f 100644 --- a/src/V3PreProc.cpp +++ b/src/V3PreProc.cpp @@ -43,7 +43,7 @@ //************************************************************************* -class VDefine { +class VDefine final { // Define class. One for each define. // string m_name; // Name of the define (list is keyed by this) FileLine* m_fileline; // Where it was declared @@ -64,7 +64,7 @@ public: //************************************************************************* -class VDefineRef { +class VDefineRef final { // One for each pending define substitution string m_name; // Define last name being defined string m_params; // Define parameter list for next expansion @@ -83,13 +83,13 @@ public: VDefineRef(const string& name, const string& params) : m_name{name} , m_params{params} {} - ~VDefineRef() {} + ~VDefineRef() = default; }; //************************************************************************* /// Data for parsing on/off -class VPreIfEntry { +class VPreIfEntry final { // One for each pending ifdef/ifndef bool m_on; // Current parse for this ifdef level is "on" bool m_everOn; // Some if term in elsif tree has been on @@ -99,13 +99,13 @@ public: VPreIfEntry(bool on, bool everOn) : m_on{on} , m_everOn{everOn || on} {} // Note everOn includes new state - ~VPreIfEntry() {} + ~VPreIfEntry() = default; }; //************************************************************************* // Data for a preprocessor instantiation. -class V3PreProcImp : public V3PreProc { +class V3PreProcImp final : public V3PreProc { public: // TYPES typedef std::map DefinesMap; @@ -855,7 +855,7 @@ void V3PreProcImp::dumpDefines(std::ostream& os) { // No need to print "()" below as already part of params() if (!it->second.params().empty()) os << it->second.params(); if (!it->second.value().empty()) os << " " << it->second.value(); - os << endl; + os << '\n'; } } diff --git a/src/V3PreProc.h b/src/V3PreProc.h index de2d02215..39c7dbb48 100644 --- a/src/V3PreProc.h +++ b/src/V3PreProc.h @@ -33,7 +33,7 @@ class VInFilter; class VSpellCheck; -class V3PreProc { +class V3PreProc VL_NOT_FINAL { // This defines a preprocessor. Functions are virtual so implementation can be hidden. // After creating, call open(), then getline() in a loop. The class will to the rest... @@ -103,7 +103,7 @@ protected: public: static V3PreProc* createPreProc(FileLine* fl); - virtual ~V3PreProc() {} // LCOV_EXCL_LINE // Persistent + virtual ~V3PreProc() = default; // LCOV_EXCL_LINE // Persistent }; #endif // Guard diff --git a/src/V3PreShell.cpp b/src/V3PreShell.cpp index 54de5495d..e2f1042dd 100644 --- a/src/V3PreShell.cpp +++ b/src/V3PreShell.cpp @@ -29,7 +29,7 @@ //###################################################################### -class V3PreShellImp { +class V3PreShellImp final { protected: friend class V3PreShell; @@ -151,8 +151,8 @@ private: public: // CONSTRUCTORS - V3PreShellImp() {} - ~V3PreShellImp() {} + V3PreShellImp() = default; + ~V3PreShellImp() = default; }; V3PreShellImp V3PreShellImp::s_preImp; diff --git a/src/V3PreShell.h b/src/V3PreShell.h index ec8a7678a..3428a8a88 100644 --- a/src/V3PreShell.h +++ b/src/V3PreShell.h @@ -29,7 +29,7 @@ class VSpellCheck; //============================================================================ -class V3PreShell { +class V3PreShell final { // Static class for calling preprocessor public: static void boot(char** env); diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp index 7e432830a..ac5582b4c 100644 --- a/src/V3Premit.cpp +++ b/src/V3Premit.cpp @@ -36,7 +36,7 @@ //###################################################################### // Structure for global state -class PremitAssignVisitor : public AstNVisitor { +class PremitAssignVisitor final : public AstNVisitor { private: // NODE STATE // AstVar::user4() // bool; occurs on LHS of current assignment @@ -75,14 +75,14 @@ public: UINFO(4, " PremitAssignVisitor on " << nodep << endl); iterate(nodep); } - virtual ~PremitAssignVisitor() override {} + virtual ~PremitAssignVisitor() override = default; bool noOpt() const { return m_noopt; } }; //###################################################################### // Premit state, as a visitor of each AstNode -class PremitVisitor : public AstNVisitor { +class PremitVisitor final : public AstNVisitor { private: // NODE STATE // AstNodeMath::user() -> bool. True if iterated already @@ -127,7 +127,9 @@ private: } else if (VN_IS(nodep->backp(), Sel) && VN_CAST(nodep->backp(), Sel)->widthp() == nodep) { // AstSel::width must remain a constant - } else if (nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) { + } else if ((nodep->firstAbovep() && VN_IS(nodep->firstAbovep(), ArraySel)) + || ((VN_IS(m_stmtp, CCall) || VN_IS(m_stmtp, CStmt)) + && VN_IS(nodep, ArraySel))) { // ArraySel's are pointer refs, ignore } else { UINFO(4, "Cre Temp: " << nodep << endl); @@ -397,7 +399,7 @@ private: public: // CONSTRUCTORS explicit PremitVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~PremitVisitor() override {} + virtual ~PremitVisitor() override = default; }; //---------------------------------------------------------------------- diff --git a/src/V3Premit.h b/src/V3Premit.h index b7a5e302d..8d798665c 100644 --- a/src/V3Premit.h +++ b/src/V3Premit.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Premit { +class V3Premit final { public: static void premitAll(AstNetlist* nodep); }; diff --git a/src/V3ProtectLib.cpp b/src/V3ProtectLib.cpp index 88bf6ba8f..188a5e8f3 100644 --- a/src/V3ProtectLib.cpp +++ b/src/V3ProtectLib.cpp @@ -28,7 +28,7 @@ //###################################################################### // ProtectLib top-level visitor -class ProtectVisitor : public AstNVisitor { +class ProtectVisitor final : public AstNVisitor { private: AstVFile* m_vfilep = nullptr; // DPI-enabled Verilog wrapper AstCFile* m_cfilep = nullptr; // C implementation of DPI functions @@ -411,11 +411,12 @@ private: string cInputConnection(AstVar* varp) { string frstmt; - bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt); + string ket; + bool useSetWSvlv = V3Task::dpiToInternalFrStmt(varp, varp->name(), frstmt, ket); if (useSetWSvlv) { - return frstmt + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n"; + return frstmt + ket + " handlep__V->" + varp->name() + ", " + varp->name() + ");\n"; } - return "handlep__V->" + varp->name() + " = " + frstmt + ";\n"; + return "handlep__V->" + varp->name() + " = " + frstmt + ket + ";\n"; } void handleClock(AstVar* varp) { diff --git a/src/V3ProtectLib.h b/src/V3ProtectLib.h index 879305054..8bb167db3 100644 --- a/src/V3ProtectLib.h +++ b/src/V3ProtectLib.h @@ -25,7 +25,7 @@ //============================================================================ -class V3ProtectLib { +class V3ProtectLib final { public: static void protect(); }; diff --git a/src/V3Reloop.cpp b/src/V3Reloop.cpp index 50c3e9e30..71379aa05 100644 --- a/src/V3Reloop.cpp +++ b/src/V3Reloop.cpp @@ -43,7 +43,7 @@ constexpr unsigned RELOOP_MIN_ITERS = 40; // Need at least this many loops to d //###################################################################### -class ReloopVisitor : public AstNVisitor { +class ReloopVisitor final : public AstNVisitor { private: // TYPES typedef std::vector AssVec; diff --git a/src/V3Reloop.h b/src/V3Reloop.h index 674ef408f..fb0a748dc 100644 --- a/src/V3Reloop.h +++ b/src/V3Reloop.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Reloop { +class V3Reloop final { public: static void reloopAll(AstNetlist* nodep); }; diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp index 6195ffc98..cc11bdb40 100644 --- a/src/V3Scope.cpp +++ b/src/V3Scope.cpp @@ -36,7 +36,7 @@ //###################################################################### // Scope class functions -class ScopeVisitor : public AstNVisitor { +class ScopeVisitor final : public AstNVisitor { private: // NODE STATE // AstVar::user1p -> AstVarScope replacement for this variable @@ -68,8 +68,8 @@ private: for (const auto& itr : m_varRefScopes) { AstVarRef* nodep = itr.first; AstScope* scopep = itr.second; - if (nodep->packagep() && !nodep->varp()->isClassMember()) { - const auto it2 = m_packageScopes.find(nodep->packagep()); + if (nodep->classOrPackagep()) { + const auto it2 = m_packageScopes.find(nodep->classOrPackagep()); UASSERT_OBJ(it2 != m_packageScopes.end(), nodep, "Can't locate package scope"); scopep = it2->second; } @@ -109,9 +109,7 @@ private: (m_aboveCellp ? static_cast(m_aboveCellp) : static_cast(nodep)) ->fileline(), nodep, scopename, m_aboveScopep, m_aboveCellp); - if (VN_IS(nodep, Package)) { - m_packageScopes.insert(make_pair(VN_CAST(nodep, Package), m_scopep)); - } + if (VN_IS(nodep, Package)) m_packageScopes.insert(make_pair(nodep, m_scopep)); // Now for each child cell, iterate the module this cell points to for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp = cellnextp->nextp()) { @@ -152,8 +150,10 @@ private: VL_RESTORER(m_scopep); VL_RESTORER(m_aboveCellp); VL_RESTORER(m_aboveScopep); + VL_RESTORER(m_modp); { m_aboveScopep = m_scopep; + m_modp = nodep; string scopename; if (!m_aboveScopep) { @@ -169,6 +169,8 @@ private: : static_cast(nodep)); m_scopep = new AstScope(abovep->fileline(), m_modp, scopename, m_aboveScopep, m_aboveCellp); + m_packageScopes.insert(make_pair(nodep, m_scopep)); + // Create scope for the current usage of this cell AstNode::user1ClearTree(); nodep->addMembersp(m_scopep); @@ -283,7 +285,8 @@ private: } else { // We may have not made the variable yet, and we can't make it now as // the var's referenced package etc might not be created yet. - // So push to a list and post-correct + // So push to a list and post-correct. + // No check here for nodep->classOrPackagep(), will check when walk list. m_varRefScopes.insert(make_pair(nodep, m_scopep)); } } @@ -313,13 +316,13 @@ private: public: // CONSTRUCTORS explicit ScopeVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ScopeVisitor() override {} + virtual ~ScopeVisitor() override = default; }; //###################################################################### // Scope cleanup -- remove unused activates -class ScopeCleanupVisitor : public AstNVisitor { +class ScopeCleanupVisitor final : public AstNVisitor { private: // STATE AstScope* m_scopep = nullptr; // Current scope we are building @@ -365,7 +368,7 @@ private: virtual void visit(AstNodeFTaskRef* nodep) override { // The crossrefs are dealt with in V3LinkDot UINFO(9, " Old pkg-taskref " << nodep << endl); - if (nodep->packagep()) { + if (nodep->classOrPackagep()) { // Point to the clone UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked"); AstNodeFTask* newp = VN_CAST(nodep->taskp()->user2p(), NodeFTask); @@ -391,7 +394,7 @@ private: public: // CONSTRUCTORS explicit ScopeCleanupVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ScopeCleanupVisitor() override {} + virtual ~ScopeCleanupVisitor() override = default; }; //###################################################################### diff --git a/src/V3Scope.h b/src/V3Scope.h index 46a9691a4..ffce787f9 100644 --- a/src/V3Scope.h +++ b/src/V3Scope.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Scope { +class V3Scope final { public: static void scopeAll(AstNetlist* nodep); }; diff --git a/src/V3Scoreboard.cpp b/src/V3Scoreboard.cpp index a4ffda454..42df6dbd8 100644 --- a/src/V3Scoreboard.cpp +++ b/src/V3Scoreboard.cpp @@ -19,7 +19,7 @@ #include "V3Scoreboard.h" -class ScoreboardTestElem { +class ScoreboardTestElem final { public: // MEMBERS uint32_t m_score; @@ -30,7 +30,7 @@ public: static uint32_t s_serial = 0; m_id = ++s_serial; } - ScoreboardTestElem() {} + ScoreboardTestElem() = default; // METHODS static uint32_t scoreFn(const ScoreboardTestElem* elp) { return elp->m_score; } diff --git a/src/V3Scoreboard.h b/src/V3Scoreboard.h index beffd2ca7..d0a1ec3e7 100644 --- a/src/V3Scoreboard.h +++ b/src/V3Scoreboard.h @@ -41,7 +41,7 @@ /// break ties in the sort when values collide. template > -class SortByValueMap { +class SortByValueMap final { // TYPES private: typedef std::unordered_map Key2Val; @@ -54,9 +54,9 @@ private: public: // CONSTRUCTORS - SortByValueMap() {} + SortByValueMap() = default; - class const_iterator { + class const_iterator VL_NOT_FINAL { // TYPES public: typedef const_iterator value_type; @@ -193,7 +193,7 @@ public: } }; - class iterator : public const_iterator { + class iterator final : public const_iterator { public: // TYPES typedef iterator value_type; @@ -350,11 +350,11 @@ private: /// the full set size. template > -class V3Scoreboard { +class V3Scoreboard final { private: // TYPES typedef std::unordered_set NeedRescoreSet; - class CmpElems { + class CmpElems final { public: bool operator()(const T_Elem* const& ap, const T_Elem* const& bp) const { T_ElemCompare cmp; @@ -375,7 +375,7 @@ public: explicit V3Scoreboard(UserScoreFnp scoreFnp, bool slowAsserts) : m_scoreFnp{scoreFnp} , m_slowAsserts{slowAsserts} {} - ~V3Scoreboard() {} + ~V3Scoreboard() = default; // METHODS diff --git a/src/V3SenTree.h b/src/V3SenTree.h index 806b5919f..b64937081 100644 --- a/src/V3SenTree.h +++ b/src/V3SenTree.h @@ -31,7 +31,7 @@ // Collect SenTrees under the entire scope // And provide functions to find/add a new one -class SenTreeSet { +class SenTreeSet final { // Hash table of sensitive blocks. private: // TYPES @@ -53,7 +53,7 @@ private: public: // CONSTRUCTORS - SenTreeSet() {} + SenTreeSet() = default; // METHODS void add(AstSenTree* nodep) { m_trees.insert(nodep); } @@ -71,7 +71,7 @@ private: VL_UNCOPYABLE(SenTreeSet); }; -class SenTreeFinder { +class SenTreeFinder final { private: // STATE AstTopScope* m_topScopep = nullptr; // Top scope to add global SenTrees to @@ -81,7 +81,7 @@ private: public: // CONSTRUCTORS - SenTreeFinder() {} + SenTreeFinder() = default; // METHODS AstSenTree* getSenTree(AstSenTree* senTreep) { diff --git a/src/V3Simulate.h b/src/V3Simulate.h index 846d303f5..edec6cffe 100644 --- a/src/V3Simulate.h +++ b/src/V3Simulate.h @@ -48,7 +48,7 @@ //###################################################################### // Simulate class functions -class SimStackNode { +class SimStackNode final { public: // MEMBERS AstFuncRef* m_funcp; @@ -57,13 +57,13 @@ public: SimStackNode(AstFuncRef* funcp, V3TaskConnects* tconnects) : m_funcp{funcp} , m_tconnects{tconnects} {} - ~SimStackNode() {} + ~SimStackNode() = default; }; typedef std::deque ConstDeque; -typedef std::map ConstPile; +typedef std::unordered_map ConstPile; -class SimulateVisitor : public AstNVisitor { +class SimulateVisitor VL_NOT_FINAL : public AstNVisitor { // Simulate a node tree, returning value of variables // Two major operating modes: // Test the tree to see if it is conformant diff --git a/src/V3Slice.cpp b/src/V3Slice.cpp index ccf559bbc..3c66b1648 100644 --- a/src/V3Slice.cpp +++ b/src/V3Slice.cpp @@ -44,7 +44,7 @@ //************************************************************************* -class SliceVisitor : public AstNVisitor { +class SliceVisitor final : public AstNVisitor { // NODE STATE // Cleared on netlist // AstNodeAssign::user1() -> bool. True if find is complete @@ -225,7 +225,7 @@ class SliceVisitor : public AstNVisitor { public: // CONSTRUCTORS explicit SliceVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~SliceVisitor() override {} + virtual ~SliceVisitor() override = default; }; //###################################################################### diff --git a/src/V3Slice.h b/src/V3Slice.h index 1ac23ac24..ad711d0f2 100644 --- a/src/V3Slice.h +++ b/src/V3Slice.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Slice { +class V3Slice final { public: static void sliceAll(AstNetlist* nodep); }; diff --git a/src/V3Split.cpp b/src/V3Split.cpp index bb528c0ae..9b7e0cd85 100644 --- a/src/V3Split.cpp +++ b/src/V3Split.cpp @@ -95,14 +95,14 @@ //###################################################################### // Support classes -class SplitNodeVertex : public V3GraphVertex { +class SplitNodeVertex VL_NOT_FINAL : public V3GraphVertex { AstNode* m_nodep; protected: SplitNodeVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~SplitNodeVertex() override {} + virtual ~SplitNodeVertex() override = default; // ACCESSORS // Do not make accessor for nodep(), It may change due to // reordering a lower block, but we don't repair it @@ -115,36 +115,36 @@ public: virtual AstNode* nodep() const { return m_nodep; } }; -class SplitPliVertex : public SplitNodeVertex { +class SplitPliVertex final : public SplitNodeVertex { public: explicit SplitPliVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitPliVertex() override {} + virtual ~SplitPliVertex() override = default; virtual string name() const override { return "*PLI*"; } virtual string dotColor() const override { return "green"; } }; -class SplitLogicVertex : public SplitNodeVertex { +class SplitLogicVertex final : public SplitNodeVertex { public: SplitLogicVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitLogicVertex() override {} + virtual ~SplitLogicVertex() override = default; virtual string dotColor() const override { return "yellow"; } }; -class SplitVarStdVertex : public SplitNodeVertex { +class SplitVarStdVertex final : public SplitNodeVertex { public: SplitVarStdVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitVarStdVertex() override {} + virtual ~SplitVarStdVertex() override = default; virtual string dotColor() const override { return "skyblue"; } }; -class SplitVarPostVertex : public SplitNodeVertex { +class SplitVarPostVertex final : public SplitNodeVertex { public: SplitVarPostVertex(V3Graph* graphp, AstNode* nodep) : SplitNodeVertex{graphp, nodep} {} - virtual ~SplitVarPostVertex() override {} + virtual ~SplitVarPostVertex() override = default; virtual string name() const override { return string("POST ") + SplitNodeVertex::name(); } virtual string dotColor() const override { return "CadetBlue"; } }; @@ -152,7 +152,7 @@ public: //###################################################################### // Edge types -class SplitEdge : public V3GraphEdge { +class SplitEdge VL_NOT_FINAL : public V3GraphEdge { uint32_t m_ignoreInStep = 0; // Step number that if set to, causes this edge to be ignored static uint32_t s_stepNum; // Global step number protected: @@ -160,7 +160,7 @@ protected: SplitEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable = CUTABLE) : V3GraphEdge{graphp, fromp, top, weight, cutable} {} - virtual ~SplitEdge() override {} + virtual ~SplitEdge() override = default; public: // Iterator for graph functions @@ -185,29 +185,29 @@ public: }; uint32_t SplitEdge::s_stepNum = 0; -class SplitPostEdge : public SplitEdge { +class SplitPostEdge final : public SplitEdge { public: SplitPostEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitPostEdge() override {} + virtual ~SplitPostEdge() override = default; virtual bool followScoreboard() const override { return false; } virtual string dotColor() const override { return "khaki"; } }; -class SplitLVEdge : public SplitEdge { +class SplitLVEdge final : public SplitEdge { public: SplitLVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitLVEdge() override {} + virtual ~SplitLVEdge() override = default; virtual bool followScoreboard() const override { return true; } virtual string dotColor() const override { return "yellowGreen"; } }; -class SplitRVEdge : public SplitEdge { +class SplitRVEdge final : public SplitEdge { public: SplitRVEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitRVEdge() override {} + virtual ~SplitRVEdge() override = default; virtual bool followScoreboard() const override { return true; } virtual string dotColor() const override { return "green"; } }; @@ -216,7 +216,7 @@ struct SplitScorebdEdge : public SplitEdge { public: SplitScorebdEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL} {} - virtual ~SplitScorebdEdge() override {} + virtual ~SplitScorebdEdge() override = default; virtual bool followScoreboard() const override { return true; } virtual string dotColor() const override { return "blue"; } }; @@ -227,7 +227,7 @@ struct SplitStrictEdge : public SplitEdge { public: SplitStrictEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) : SplitEdge{graphp, fromp, top, WEIGHT_NORMAL, NOT_CUTABLE} {} - virtual ~SplitStrictEdge() override {} + virtual ~SplitStrictEdge() override = default; virtual bool followScoreboard() const override { return true; } virtual string dotColor() const override { return "blue"; } }; @@ -235,7 +235,7 @@ public: //###################################################################### // Split class functions -class SplitReorderBaseVisitor : public AstNVisitor { +class SplitReorderBaseVisitor VL_NOT_FINAL : public AstNVisitor { private: // NODE STATE // AstVarScope::user1p -> Var SplitNodeVertex* for usage var, 0=not set yet @@ -439,11 +439,11 @@ private: VL_UNCOPYABLE(SplitReorderBaseVisitor); }; -class ReorderVisitor : public SplitReorderBaseVisitor { +class ReorderVisitor final : public SplitReorderBaseVisitor { // CONSTRUCTORS public: explicit ReorderVisitor(AstNetlist* nodep) { iterate(nodep); } - virtual ~ReorderVisitor() override {} + virtual ~ReorderVisitor() override = default; // METHODS protected: @@ -622,7 +622,7 @@ private: typedef std::unordered_set ColorSet; typedef std::vector AlwaysVec; -class IfColorVisitor : public AstNVisitor { +class IfColorVisitor final : public AstNVisitor { // MEMBERS ColorSet m_colors; // All colors in the original always block @@ -638,7 +638,7 @@ public: // Visit through *nodep and map each AstNodeIf within to the set of // colors it will participate in. Also find the whole set of colors. explicit IfColorVisitor(AstAlways* nodep) { iterate(nodep); } - virtual ~IfColorVisitor() override {} + virtual ~IfColorVisitor() override = default; // METHODS const ColorSet& colors() const { return m_colors; } @@ -680,7 +680,7 @@ private: VL_UNCOPYABLE(IfColorVisitor); }; -class EmitSplitVisitor : public AstNVisitor { +class EmitSplitVisitor final : public AstNVisitor { // MEMBERS AstAlways* m_origAlwaysp; // Block that *this will split const IfColorVisitor* m_ifColorp; // Digest of results of prior coloring @@ -703,7 +703,7 @@ public: UINFO(6, " splitting always " << nodep << endl); } - virtual ~EmitSplitVisitor() override {} + virtual ~EmitSplitVisitor() override = default; // METHODS void go() { @@ -793,7 +793,7 @@ private: VL_UNCOPYABLE(EmitSplitVisitor); }; -class RemovePlaceholdersVisitor : public AstNVisitor { +class RemovePlaceholdersVisitor final : public AstNVisitor { typedef std::unordered_set NodeSet; NodeSet m_removeSet; // placeholders to be removed public: @@ -804,7 +804,7 @@ public: VL_DO_DANGLING(np->deleteTree(), np); } } - virtual ~RemovePlaceholdersVisitor() override {} + virtual ~RemovePlaceholdersVisitor() override = default; virtual void visit(AstSplitPlaceholder* nodep) override { m_removeSet.insert(nodep); } virtual void visit(AstNode* nodep) override { iterateChildren(nodep); } @@ -812,7 +812,7 @@ private: VL_UNCOPYABLE(RemovePlaceholdersVisitor); }; -class SplitVisitor : public SplitReorderBaseVisitor { +class SplitVisitor final : public SplitReorderBaseVisitor { private: // Keys are original always blocks pending delete, // values are newly split always blocks pending insertion @@ -844,7 +844,7 @@ public: } } - virtual ~SplitVisitor() override {} + virtual ~SplitVisitor() override = default; // METHODS protected: diff --git a/src/V3Split.h b/src/V3Split.h index a60268cee..bcabc01e3 100644 --- a/src/V3Split.h +++ b/src/V3Split.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Split { +class V3Split final { public: static void splitReorderAll(AstNetlist* nodep); static void splitAlwaysAll(AstNetlist* nodep); diff --git a/src/V3SplitAs.cpp b/src/V3SplitAs.cpp index 48a1c2960..e40a87f42 100644 --- a/src/V3SplitAs.cpp +++ b/src/V3SplitAs.cpp @@ -33,7 +33,7 @@ //###################################################################### -class SplitAsBaseVisitor : public AstNVisitor { +class SplitAsBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -42,7 +42,7 @@ public: //###################################################################### // Find all split variables in a block -class SplitAsFindVisitor : public SplitAsBaseVisitor { +class SplitAsFindVisitor final : public SplitAsBaseVisitor { private: // STATE AstVarScope* m_splitVscp = nullptr; // Variable we want to split @@ -58,7 +58,7 @@ private: public: // CONSTRUCTORS explicit SplitAsFindVisitor(AstAlways* nodep) { iterate(nodep); } - virtual ~SplitAsFindVisitor() override {} + virtual ~SplitAsFindVisitor() override = default; // METHODS AstVarScope* splitVscp() const { return m_splitVscp; } }; @@ -66,7 +66,7 @@ public: //###################################################################### // Remove nodes not containing proper references -class SplitAsCleanVisitor : public SplitAsBaseVisitor { +class SplitAsCleanVisitor final : public SplitAsBaseVisitor { private: // STATE AstVarScope* m_splitVscp; // Variable we want to split @@ -118,13 +118,13 @@ public: , m_modeMatch{modeMatch} { iterate(nodep); } - virtual ~SplitAsCleanVisitor() override {} + virtual ~SplitAsCleanVisitor() override = default; }; //###################################################################### // SplitAs class functions -class SplitAsVisitor : public SplitAsBaseVisitor { +class SplitAsVisitor final : public SplitAsBaseVisitor { private: // NODE STATE // AstAlways::user() -> bool. True if already processed diff --git a/src/V3SplitAs.h b/src/V3SplitAs.h index e42d03678..82f9d4915 100644 --- a/src/V3SplitAs.h +++ b/src/V3SplitAs.h @@ -25,7 +25,7 @@ //============================================================================ -class V3SplitAs { +class V3SplitAs final { public: static void splitAsAll(AstNetlist* nodep); }; diff --git a/src/V3SplitVar.cpp b/src/V3SplitVar.cpp index 38ea0da47..83ae80e89 100644 --- a/src/V3SplitVar.cpp +++ b/src/V3SplitVar.cpp @@ -232,7 +232,7 @@ struct AstNodeComparator { } }; -class UnpackRef { +class UnpackRef final { // m_nodep is called in this context (AstNodeStmt, AstCell, AstNodeFTask, or AstAlways) AstNode* m_contextp; AstNode* m_nodep; // ArraySel, SliceSel, ArrayVarRef (entire value) @@ -283,7 +283,7 @@ public: } }; -class UnpackRefMap { +class UnpackRefMap final { public: typedef std::map, AstNodeComparator> MapType; typedef MapType::iterator MapIt; @@ -384,7 +384,7 @@ public: typedef std::map SplitVarRefsMap; -class SplitUnpackedVarVisitor : public AstNVisitor, public SplitVarImpl { +class SplitUnpackedVarVisitor final : public AstNVisitor, public SplitVarImpl { typedef std::set VarSet; VarSet m_foundTargetVar; UnpackRefMap m_refs; @@ -802,7 +802,7 @@ public: // Split packed variables // Split variable -class SplitNewVar { +class SplitNewVar final { int m_lsb; // LSB in the original bitvector int m_bitwidth; AstVar* m_varp; // The LSB of this variable is always 0, not m_lsb @@ -828,7 +828,7 @@ public: }; // One Entry instance for an AstVarRef instance -class PackedVarRefEntry { +class PackedVarRefEntry final { AstNode* m_nodep; // Either AstSel or AstVarRef is expected. int m_lsb; int m_bitwidth; @@ -859,7 +859,7 @@ public: }; // How a variable is used -class PackedVarRef { +class PackedVarRef final { struct SortByFirst { bool operator()(const std::pair& a, const std::pair& b) const { if (a.first == b.first) return a.second < b.second; @@ -956,11 +956,11 @@ public: } }; -class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { +class SplitPackedVarVisitor final : public AstNVisitor, public SplitVarImpl { typedef std::map PackedVarRefMap; AstNetlist* m_netp; - AstNodeModule* m_modp; // Current module (just for log) - int m_numSplit; // Total number of split variables + AstNodeModule* m_modp = nullptr; // Current module (just for log) + int m_numSplit = 0; // Total number of split variables // key:variable to be split. value:location where the variable is referenced. PackedVarRefMap m_refs; virtual void visit(AstNodeFTask* nodep) override { @@ -982,7 +982,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { const auto refit = m_refs.find(varp); if (refit == m_refs.end()) return; // variable without split_var metacomment UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached"); - UASSERT_OBJ(!nodep->packagep(), nodep, + UASSERT_OBJ(!nodep->classOrPackagep(), nodep, "variable in package must have been dropped beforehand."); const AstBasicDType* basicp = refit->second.basicp(); refit->second.append(PackedVarRefEntry(nodep, basicp->lsb(), varp->width()), @@ -1005,7 +1005,9 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { } UASSERT_OBJ(varp->attrSplitVar(), varp, "split_var attribute must be attached"); - AstConst* consts[2] = {VN_CAST(nodep->lsbp(), Const), VN_CAST(nodep->widthp(), Const)}; + std::array consts + = {{VN_CAST(nodep->lsbp(), Const), + VN_CAST(nodep->widthp(), Const)}}; // GCC 3.8.0 wants {{}} if (consts[0] && consts[1]) { // OK refit->second.append( PackedVarRefEntry(nodep, consts[0]->toSInt() + refit->second.basicp()->lsb(), @@ -1206,9 +1208,7 @@ class SplitPackedVarVisitor : public AstNVisitor, public SplitVarImpl { public: // When reusing the information from SplitUnpackedVarVisitor SplitPackedVarVisitor(AstNetlist* nodep, SplitVarRefsMap& refs) - : m_netp{nodep} - , m_modp{nullptr} - , m_numSplit{0} { + : m_netp{nodep} { // If you want ignore refs and walk the tne entire AST, // just call iterateChildren(m_modp) and split() for each module for (auto& i : refs) { diff --git a/src/V3SplitVar.h b/src/V3SplitVar.h index f9c1c64ab..41195bc57 100644 --- a/src/V3SplitVar.h +++ b/src/V3SplitVar.h @@ -22,7 +22,7 @@ class AstNetlist; class AstVar; -class V3SplitVar { +class V3SplitVar final { public: // Split variables marked with split_var metacomment. static void splitVariable(AstNetlist* nodep); diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp index 9562aa8a0..612ea0244 100644 --- a/src/V3Stats.cpp +++ b/src/V3Stats.cpp @@ -30,7 +30,7 @@ //###################################################################### // Stats class functions -class StatsVisitor : public AstNVisitor { +class StatsVisitor final : public AstNVisitor { private: // NODE STATE/TYPES @@ -49,7 +49,7 @@ private: std::vector m_statTypeCount; // Nodes of given type VDouble0 m_statAbove[AstType::_ENUM_END][AstType::_ENUM_END]; // Nodes of given type - VDouble0 m_statPred[VBranchPred::_ENUM_END]; // Nodes of given type + std::array m_statPred; // Nodes of given type VDouble0 m_statInstr; // Instruction count VDouble0 m_statInstrFast; // Instruction count, non-slow() eval functions only std::vector m_statVarWidths; // Variables of given width diff --git a/src/V3Stats.h b/src/V3Stats.h index ad5985110..7f9012238 100644 --- a/src/V3Stats.h +++ b/src/V3Stats.h @@ -26,14 +26,13 @@ class AstNetlist; //============================================================================ -class VDouble0 { +class VDouble0 final { // Double counter, initializes to zero for easy use - double m_d; ///< Count of occurrences/ value + double m_d = 0.0; ///< Count of occurrences/ value public: // METHODS - VDouble0() - : m_d{0.0} {} - ~VDouble0() {} + VDouble0() = default; + ~VDouble0() = default; // Implicit conversion operators: explicit VDouble0(const vluint64_t v) @@ -66,14 +65,14 @@ public: //============================================================================ -class V3Statistic { +class V3Statistic final { // A statistical entry we want published into the database string m_name; ///< Nameiption of this statistic double m_count; ///< Count of occurrences/ value string m_stage; ///< Runtime stage bool m_sumit; ///< Do summation of similar stats bool m_perf; ///< Performance section - bool m_printit; ///< Print the results + bool m_printit = true; ///< Print the results public: // METHODS string stage() const { return m_stage; } @@ -94,14 +93,13 @@ public: , m_count{count} , m_stage{stage} , m_sumit{sumit} - , m_perf{perf} - , m_printit{true} {} - virtual ~V3Statistic() {} + , m_perf{perf} {} + virtual ~V3Statistic() = default; }; //============================================================================ -class V3Stats { +class V3Stats final { public: static void addStat(const V3Statistic&); static void addStat(const string& stage, const string& name, double count) { diff --git a/src/V3StatsReport.cpp b/src/V3StatsReport.cpp index 71db187a3..24c84932e 100644 --- a/src/V3StatsReport.cpp +++ b/src/V3StatsReport.cpp @@ -30,7 +30,7 @@ //###################################################################### // Stats dumping -class StatsReport { +class StatsReport final { // TYPES typedef std::vector StatColl; @@ -39,13 +39,12 @@ class StatsReport { static StatColl s_allStats; ///< All statistics void header() { - os << "Verilator Statistics Report\n"; - os << endl; + os << "Verilator Statistics Report\n\n"; - os << "Information:" << endl; - os << " " << V3Options::version() << endl; - os << " Arguments: " << v3Global.opt.allArgsString() << endl; - os << endl; + os << "Information:\n"; + os << " " << V3Options::version() << '\n'; + os << " Arguments: " << v3Global.opt.allArgsString() << '\n'; + os << '\n'; } void sumit() { @@ -85,28 +84,26 @@ class StatsReport { } // Print organized by stage - os << "Global Statistics:\n"; - os << endl; + os << "Global Statistics:\n\n"; for (const auto& itr : byName) { const V3Statistic* repp = itr.second; if (repp->perf()) continue; os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); - os << endl; + os << '\n'; } - os << endl; + os << '\n'; // Print organized by stage - os << "Performance Statistics:\n"; - os << endl; + os << "Performance Statistics:\n\n"; for (const auto& itr : byName) { const V3Statistic* repp = itr.second; if (!repp->perf()) continue; os << " " << std::left << std::setw(maxWidth) << repp->name(); repp->dump(os); - os << endl; + os << '\n'; } - os << endl; + os << '\n'; } void stages() { @@ -136,7 +133,7 @@ class StatsReport { // Header os << " Stat " << std::left << std::setw(maxWidth - 5 - 2) << ""; for (const string& i : stages) os << " " << std::left << std::setw(9) << i; - os << endl; + os << '\n'; os << " -------- " << std::left << std::setw(maxWidth - 5 - 2) << ""; for (auto it = stages.begin(); it != stages.end(); ++it) { os << " " << std::left << std::setw(9) << "-------"; @@ -157,10 +154,10 @@ class StatsReport { if ((pos = commaName.find(',')) != string::npos) commaName.erase(pos); if (lastCommaName != commaName) { lastCommaName = commaName; - os << endl; + os << '\n'; } } - os << endl; + os << '\n'; col = 0; os << " " << std::left << std::setw(maxWidth) << repp->name(); } @@ -171,7 +168,7 @@ class StatsReport { repp->dump(os); col++; } - os << endl; + os << '\n'; } public: @@ -186,7 +183,7 @@ public: stars(); stages(); } - ~StatsReport() {} + ~StatsReport() = default; }; StatsReport::StatColl StatsReport::s_allStats; diff --git a/src/V3String.cpp b/src/V3String.cpp index 12db74f7c..edf02a01d 100644 --- a/src/V3String.cpp +++ b/src/V3String.cpp @@ -25,6 +25,7 @@ size_t VName::s_minLength = 32; size_t VName::s_maxLength = 0; // Disabled +std::map VName::s_dehashMap; //###################################################################### // Wildcard @@ -306,7 +307,7 @@ uint64_t VHashSha256::digestUInt64() { } string VHashSha256::digestHex() { - static const char digits[16 + 1] = "0123456789abcdef"; + static const char* const digits = "0123456789abcdef"; const string& binhash = digestBinary(); string out; out.reserve(70); @@ -322,7 +323,7 @@ string VHashSha256::digestSymbol() { // has + and / for last two digits, but need C symbol, and we also // avoid conflicts with use of _, so use "AB" at the end. // Thus this function is non-reversible. - static const char digits[64 + 1] + static const char* const digits = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789AB"; const string& binhash = digestBinary(); string out; @@ -345,13 +346,13 @@ void VHashSha256::selfTestOne(const string& data, const string& data2, const str VHashSha256 digest(data); if (data2 != "") digest.insert(data2); if (VL_UNCOVERABLE(digest.digestHex() != exp)) { - std::cerr << "%Error: When hashing '" << data + data2 << "'" << endl // LCOV_EXCL_LINE - << " ... got=" << digest.digestHex() << endl // LCOV_EXCL_LINE + std::cerr << "%Error: When hashing '" << data + data2 << "'\n" // LCOV_EXCL_LINE + << " ... got=" << digest.digestHex() << '\n' // LCOV_EXCL_LINE << " ... exp=" << exp << endl; // LCOV_EXCL_LINE } if (VL_UNCOVERABLE(digest.digestSymbol() != exp64)) { - std::cerr << "%Error: When hashing '" << data + data2 << "'" << endl // LCOV_EXCL_LINE - << " ... got=" << digest.digestSymbol() << endl // LCOV_EXCL_LINE + std::cerr << "%Error: When hashing '" << data + data2 << "'\n" // LCOV_EXCL_LINE + << " ... got=" << digest.digestSymbol() << '\n' // LCOV_EXCL_LINE << " ... exp=" << exp64 << endl; // LCOV_EXCL_LINE } } @@ -378,6 +379,15 @@ void VHashSha256::selfTest() { //###################################################################### // VName +string VName::dehash(const string& in) { + const string::size_type pos = in.find("__Vhsh"); + if (VL_LIKELY(pos == string::npos)) return in; + const string vhsh = in.substr(pos); + const auto& it = s_dehashMap.find(vhsh); + UASSERT(it != s_dehashMap.end(), "String not in reverse hash map '" << vhsh << "'"); + return in.substr(0, pos) + it->second; +} + string VName::hashedName() { if (m_name == "") return ""; if (m_hashed != "") return m_hashed; // Memoized @@ -388,8 +398,10 @@ string VName::hashedName() { VHashSha256 hash(m_name); string suffix = "__Vhsh" + hash.digestSymbol(); if (s_minLength < s_maxLength) { + s_dehashMap[suffix] = m_name.substr(s_minLength); m_hashed = m_name.substr(0, s_minLength) + suffix; } else { + s_dehashMap[suffix] = m_name; m_hashed = suffix; } return m_hashed; @@ -408,9 +420,9 @@ VSpellCheck::EditDistance VSpellCheck::editDistance(const string& s, const strin if (sLen >= LENGTH_LIMIT) return sLen; if (tLen >= LENGTH_LIMIT) return tLen; - static EditDistance s_v_two_ago[LENGTH_LIMIT + 1]; - static EditDistance s_v_one_ago[LENGTH_LIMIT + 1]; - static EditDistance s_v_next[LENGTH_LIMIT + 1]; + static std::array s_v_two_ago; + static std::array s_v_one_ago; + static std::array s_v_next; for (size_t i = 0; i < sLen + 1; i++) s_v_one_ago[i] = i; @@ -488,10 +500,10 @@ void VSpellCheck::selfTestSuggestOne(bool matches, const string& c, const string speller.pushCandidate(c); string got = speller.bestCandidateInfo(goal, gdist /*ref*/); if (matches) { - UASSERT_SELFTEST(string, got, c); + UASSERT_SELFTEST(const string&, got, c); UASSERT_SELFTEST(EditDistance, gdist, dist); } else { - UASSERT_SELFTEST(string, got, ""); + UASSERT_SELFTEST(const string&, got, ""); } } diff --git a/src/V3String.h b/src/V3String.h index b02ee587f..6bc0bd61f 100644 --- a/src/V3String.h +++ b/src/V3String.h @@ -22,8 +22,10 @@ // No V3 headers here - this is a base class for Vlc etc -#include +#include #include +#include +#include #include //###################################################################### @@ -65,7 +67,7 @@ inline string ucfirst(const string& text) { //###################################################################### // VString - String manipulation -class VString { +class VString final { static bool wildmatchi(const char* s, const char* p); public: @@ -103,7 +105,7 @@ public: //###################################################################### // VHashSha256 - Compute Sha256 hashes -class VHashSha256 { +class VHashSha256 final { // As blocks must be processed in 64 byte chunks, this does not at present // support calling input() on multiple non-64B chunks and getting the correct // hash. To do that first combine the string before calling here. @@ -130,7 +132,7 @@ public: : VHashSha256{} { insert(data); } - ~VHashSha256() {} + ~VHashSha256() = default; // METHODS string digestBinary(); // Return digest as 32 character binary @@ -156,17 +158,19 @@ private: // VName - string which contains a possibly hashed string // TODO use this wherever there is currently a "string m_name" -class VName { +class VName final { string m_name; string m_hashed; + static std::map s_dehashMap; // hashed -> original decoder static size_t s_maxLength; // Length at which to start hashing static size_t s_minLength; // Length to preserve if over maxLength + public: // CONSTRUCTORS explicit VName(const string& name) : m_name{name} {} - ~VName() {} + ~VName() = default; // METHODS void name(const string& name) { m_name = name; @@ -178,12 +182,13 @@ public: // Length at which to start hashing, 0=disable static void maxLength(size_t flag) { s_maxLength = flag; } static size_t maxLength() { return s_maxLength; } + static string dehash(const string& in); }; //###################################################################### // VSpellCheck - Find near-match spelling suggestions given list of possibilities -class VSpellCheck { +class VSpellCheck final { // CONSTANTS static constexpr unsigned NUM_CANDIDATE_LIMIT = 10000; // Avoid searching huge netlists static constexpr unsigned LENGTH_LIMIT = 100; // Maximum string length to search @@ -194,8 +199,8 @@ class VSpellCheck { Candidates m_candidates; // Strings we try to match public: // CONSTRUCTORS - explicit VSpellCheck() {} - ~VSpellCheck() {} + VSpellCheck() = default; + ~VSpellCheck() = default; // METHODS // Push a symbol table value to be considered as a candidate // The first item pushed has highest priority, all else being equal diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp index d8a01fbb3..8a0bb483c 100644 --- a/src/V3Subst.cpp +++ b/src/V3Subst.cpp @@ -36,7 +36,7 @@ //###################################################################### // Common debugging baseclass -class SubstBaseVisitor : public AstNVisitor { +class SubstBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: VL_DEBUG_FUNC; // Declare debug() }; @@ -44,7 +44,7 @@ public: //###################################################################### // Class for each word of a multi-word variable -class SubstVarWord { +class SubstVarWord final { protected: // MEMBERS AstNodeAssign* m_assignp; // Last assignment to each word of this var @@ -64,7 +64,7 @@ protected: //###################################################################### // Class for every variable we may process -class SubstVarEntry { +class SubstVarEntry final { // MEMBERS AstVar* m_varp; // Variable this tracks bool m_wordAssign = false; // True if any word assignments @@ -81,7 +81,7 @@ public: m_whole.clear(); for (int i = 0; i < varp->widthWords(); i++) m_words[i].clear(); } - ~SubstVarEntry() {} + ~SubstVarEntry() = default; private: // METHODS @@ -174,7 +174,7 @@ public: // See if any variables have changed value since we determined subst value, // as a visitor of each AstNode -class SubstUseVisitor : public SubstBaseVisitor { +class SubstUseVisitor final : public SubstBaseVisitor { private: // NODE STATE // See SubstVisitor @@ -213,7 +213,7 @@ public: UINFO(9, " SubstUseVisitor " << origStep << " " << nodep << endl); iterate(nodep); } - virtual ~SubstUseVisitor() override {} + virtual ~SubstUseVisitor() override = default; // METHODS bool ok() const { return m_ok; } }; @@ -221,7 +221,7 @@ public: //###################################################################### // Subst state, as a visitor of each AstNode -class SubstVisitor : public SubstBaseVisitor { +class SubstVisitor final : public SubstBaseVisitor { private: // NODE STATE // Passed to SubstUseVisitor diff --git a/src/V3Subst.h b/src/V3Subst.h index fbc3e5708..9906f3487 100644 --- a/src/V3Subst.h +++ b/src/V3Subst.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Subst { +class V3Subst final { public: static void substituteAll(AstNetlist* nodep); }; diff --git a/src/V3SymTable.h b/src/V3SymTable.h index 6fbdca71f..de63b816a 100644 --- a/src/V3SymTable.h +++ b/src/V3SymTable.h @@ -36,9 +36,9 @@ class VSymEnt; //###################################################################### // Symbol table -typedef std::set VSymConstMap; +typedef std::unordered_set VSymConstMap; -class VSymEnt { +class VSymEnt final { // Symbol table that can have a "superior" table for resolving upper references // MEMBERS typedef std::multimap IdNameMap; @@ -46,7 +46,7 @@ class VSymEnt { AstNode* m_nodep; // Node that entry belongs to VSymEnt* m_fallbackp; // Table "above" this one in name scope, for fallback resolution VSymEnt* m_parentp; // Table that created this table, dot notation needed to resolve into it - AstNodeModule* m_packagep; // Package node is in (for V3LinkDot, unused here) + AstNodeModule* m_classOrPackagep; // Package node is in (for V3LinkDot, unused here) string m_symPrefix; // String to prefix symbols with (for V3LinkDot, unused here) bool m_exported; // Allow importing bool m_imported; // Was imported @@ -57,7 +57,7 @@ class VSymEnt { return level; } #else - static inline int debug() { return 0; } // NOT runtime, too hot of a function + static constexpr int debug() { return 0; } // NOT runtime, too hot of a function #endif public: typedef IdNameMap::const_iterator const_iterator; @@ -72,7 +72,7 @@ public: os << " fallb=se" << cvtToHex(m_fallbackp); if (m_symPrefix != "") os << " symPrefix=" << m_symPrefix; os << " n=" << nodep(); - os << endl; + os << '\n'; if (VL_UNCOVERABLE(doneSymsr.find(this) != doneSymsr.end())) { os << indent << "| ^ duplicate, so no children printed\n"; // LCOV_EXCL_LINE } else { @@ -100,7 +100,7 @@ public: m_nodep = reinterpret_cast(1); m_fallbackp = reinterpret_cast(1); m_parentp = reinterpret_cast(1); - m_packagep = reinterpret_cast(1); + m_classOrPackagep = reinterpret_cast(1); #endif } #if defined(VL_DEBUG) && !defined(VL_LEAK_CHECKS) @@ -111,8 +111,8 @@ public: VSymEnt* fallbackp() const { return m_fallbackp; } void parentp(VSymEnt* entp) { m_parentp = entp; } VSymEnt* parentp() const { return m_parentp; } - void packagep(AstNodeModule* entp) { m_packagep = entp; } - AstNodeModule* packagep() const { return m_packagep; } + void classOrPackagep(AstNodeModule* entp) { m_classOrPackagep = entp; } + AstNodeModule* classOrPackagep() const { return m_classOrPackagep; } AstNode* nodep() const { return m_nodep; } string symPrefix() const { return m_symPrefix; } void symPrefix(const string& name) { m_symPrefix = name; } @@ -126,8 +126,7 @@ public: if (name != "" && m_idNameMap.find(name) != m_idNameMap.end()) { if (!V3Error::errorCount()) { // Else may have just reported warning if (debug() >= 9 || V3Error::debugDefault()) dump(cout, "- err-dump: ", 1); - entp->nodep()->v3fatalSrc("Inserting two symbols with same name: " << name - << endl); + entp->nodep()->v3fatalSrc("Inserting two symbols with same name: " << name); } } else { m_idNameMap.insert(make_pair(name, entp)); @@ -278,7 +277,7 @@ public: //###################################################################### // Symbol tables -class VSymGraph { +class VSymGraph final { // Collection of symbol tables // TYPES typedef std::vector SymStack; @@ -338,7 +337,7 @@ inline VSymEnt::VSymEnt(VSymGraph* graphp, AstNode* nodep) // by an earlier search insertion. m_fallbackp = nullptr; m_parentp = nullptr; - m_packagep = nullptr; + m_classOrPackagep = nullptr; m_exported = true; m_imported = false; graphp->pushNewEnt(this); @@ -348,7 +347,7 @@ inline VSymEnt::VSymEnt(VSymGraph* graphp, const VSymEnt* symp) : m_nodep(symp->m_nodep) { m_fallbackp = symp->m_fallbackp; m_parentp = symp->m_parentp; - m_packagep = symp->m_packagep; + m_classOrPackagep = symp->m_classOrPackagep; m_exported = symp->m_exported; m_imported = symp->m_imported; graphp->pushNewEnt(this); diff --git a/src/V3TSP.cpp b/src/V3TSP.cpp index 3cd98df8d..95348cbbb 100644 --- a/src/V3TSP.cpp +++ b/src/V3TSP.cpp @@ -59,7 +59,7 @@ public: TspVertexTmpl(V3Graph* graphp, const T_Key& k) : V3GraphVertex{graphp} , m_key{k} {} - virtual ~TspVertexTmpl() override {} + virtual ~TspVertexTmpl() override = default; const T_Key& key() const { return m_key; } private: @@ -80,7 +80,7 @@ public: // CONSTRUCTORS TspGraphTmpl() : V3Graph{} {} - virtual ~TspGraphTmpl() override {} + virtual ~TspGraphTmpl() override = default; // METHODS void addVertex(const T_Key& key) { @@ -119,13 +119,13 @@ public: return vertices; } - class EdgeCmp { + class EdgeCmp final { // Provides a deterministic compare for outgoing V3GraphEdge's // to be used in Prim's algorithm below. Also used in the // perfectMatching() routine. public: // CONSTRUCTORS - EdgeCmp() {} + EdgeCmp() = default; // METHODS bool operator()(const V3GraphEdge* ap, const V3GraphEdge* bp) { int aCost = ap->weight(); @@ -346,10 +346,10 @@ public: os << "At " << nameComment << ", dumping graph. Keys:\n"; for (V3GraphVertex* vxp = verticesBeginp(); vxp; vxp = vxp->verticesNextp()) { Vertex* tspvp = castVertexp(vxp); - os << " " << tspvp->key() << endl; + os << " " << tspvp->key() << '\n'; for (V3GraphEdge* edgep = tspvp->outBeginp(); edgep; edgep = edgep->outNextp()) { Vertex* neighborp = castVertexp(edgep->top()); - os << " has edge " << edgep->user() << " to " << neighborp->key() << endl; + os << " has edge " << edgep->user() << " to " << neighborp->key() << '\n'; } } } @@ -494,13 +494,13 @@ void V3TSP::tspSort(const V3TSP::StateVec& states, V3TSP::StateVec* resultp) { //###################################################################### // Self Tests -class TspTestState : public V3TSP::TspStateBase { +class TspTestState final : public V3TSP::TspStateBase { public: TspTestState(unsigned xpos, unsigned ypos) : m_xpos{xpos} , m_ypos{ypos} - , m_serial{++m_serialNext} {} - ~TspTestState() {} + , m_serial{++s_serialNext} {} + ~TspTestState() = default; virtual int cost(const TspStateBase* otherp) const override { return cost(dynamic_cast(otherp)); } @@ -530,10 +530,10 @@ private: unsigned m_xpos; unsigned m_ypos; unsigned m_serial; - static unsigned m_serialNext; + static unsigned s_serialNext; }; -unsigned TspTestState::m_serialNext = 0; +unsigned TspTestState::s_serialNext = 0; void V3TSP::selfTestStates() { // Linear test -- coords all along the x-axis diff --git a/src/V3TSP.h b/src/V3TSP.h index cc9e79fed..e44295150 100644 --- a/src/V3TSP.h +++ b/src/V3TSP.h @@ -27,7 +27,7 @@ namespace V3TSP { // Perform a "Traveling Salesman Problem" optimizing sort // on any type you like -- so long as inherits from TspStateBase. -class TspStateBase { +class TspStateBase VL_NOT_FINAL { public: // This is the cost function that the TSP sort will minimize. // All costs in V3TSP are int, chosen to match the type of @@ -39,6 +39,8 @@ public: // key maps so that iteration is stable, without relying // on pointer values that could lead to nondeterminism. virtual bool operator<(const TspStateBase& otherp) const = 0; + + virtual ~TspStateBase() = default; }; typedef std::vector StateVec; diff --git a/src/V3Table.cpp b/src/V3Table.cpp index dcec7c663..271c8c649 100644 --- a/src/V3Table.cpp +++ b/src/V3Table.cpp @@ -48,7 +48,7 @@ static const int TABLE_MIN_NODE_COUNT = 32; // If < 32 instructions, not worth class TableVisitor; -class TableSimulateVisitor : public SimulateVisitor { +class TableSimulateVisitor final : public SimulateVisitor { // MEMBERS TableVisitor* m_cbthis; ///< Class for callback @@ -59,13 +59,13 @@ public: // CONSTRUCTORS explicit TableSimulateVisitor(TableVisitor* cbthis) : m_cbthis{cbthis} {} - virtual ~TableSimulateVisitor() override {} + virtual ~TableSimulateVisitor() override = default; }; //###################################################################### // Table class functions -class TableVisitor : public AstNVisitor { +class TableVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on each always/assignw diff --git a/src/V3Table.h b/src/V3Table.h index c54220b8d..3ad3de773 100644 --- a/src/V3Table.h +++ b/src/V3Table.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Table { +class V3Table final { public: static void tableAll(AstNetlist* nodep); }; diff --git a/src/V3Task.cpp b/src/V3Task.cpp index f6a0c4a3c..131129160 100644 --- a/src/V3Task.cpp +++ b/src/V3Task.cpp @@ -39,13 +39,13 @@ //###################################################################### // Graph subclasses -class TaskBaseVertex : public V3GraphVertex { +class TaskBaseVertex VL_NOT_FINAL : public V3GraphVertex { AstNode* m_impurep = nullptr; // Node causing impure function w/ outside references bool m_noInline = false; // Marked with pragma public: explicit TaskBaseVertex(V3Graph* graphp) : V3GraphVertex{graphp} {} - virtual ~TaskBaseVertex() override {} + virtual ~TaskBaseVertex() override = default; bool pure() const { return m_impurep == nullptr; } AstNode* impureNode() const { return m_impurep; } void impure(AstNode* nodep) { m_impurep = nodep; } @@ -53,7 +53,7 @@ public: void noInline(bool flag) { m_noInline = flag; } }; -class TaskFTaskVertex : public TaskBaseVertex { +class TaskFTaskVertex final : public TaskBaseVertex { // Every task gets a vertex, and we link tasks together based on funcrefs. AstNodeFTask* m_nodep; AstCFunc* m_cFuncp = nullptr; @@ -62,7 +62,7 @@ public: TaskFTaskVertex(V3Graph* graphp, AstNodeFTask* nodep) : TaskBaseVertex{graphp} , m_nodep{nodep} {} - virtual ~TaskFTaskVertex() override {} + virtual ~TaskFTaskVertex() override = default; AstNodeFTask* nodep() const { return m_nodep; } virtual string name() const override { return nodep()->name(); } virtual string dotColor() const override { return pure() ? "black" : "red"; } @@ -71,27 +71,27 @@ public: void cFuncp(AstCFunc* nodep) { m_cFuncp = nodep; } }; -class TaskCodeVertex : public TaskBaseVertex { +class TaskCodeVertex final : public TaskBaseVertex { // Top vertex for all calls not under another task public: explicit TaskCodeVertex(V3Graph* graphp) : TaskBaseVertex{graphp} {} - virtual ~TaskCodeVertex() override {} + virtual ~TaskCodeVertex() override = default; virtual string name() const override { return "*CODE*"; } virtual string dotColor() const override { return "green"; } }; -class TaskEdge : public V3GraphEdge { +class TaskEdge final : public V3GraphEdge { public: TaskEdge(V3Graph* graphp, TaskBaseVertex* fromp, TaskBaseVertex* top) : V3GraphEdge{graphp, fromp, top, 1, false} {} - virtual ~TaskEdge() override {} + virtual ~TaskEdge() override = default; virtual string dotLabel() const override { return "w" + cvtToStr(weight()); } }; //###################################################################### -class TaskStateVisitor : public AstNVisitor { +class TaskStateVisitor final : public AstNVisitor { private: // NODE STATE // Output: @@ -104,7 +104,7 @@ private: // TYPES typedef std::map, AstVarScope*> VarToScopeMap; - typedef std::map FuncToClassMap; + typedef std::unordered_map FuncToClassMap; typedef std::vector Initials; // MEMBERS VarToScopeMap m_varToScopeMap; // Map for Var -> VarScope mappings @@ -146,11 +146,11 @@ public: if (!vxp->pure()) { nodep->v3warn( IMPURE, "Unsupported: External variable referenced by non-inlined function/task: " - << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << vxp->impureNode()->warnOther() << "... Location of the external reference: " - << vxp->impureNode()->prettyNameQ() << endl + << vxp->impureNode()->prettyNameQ() << '\n' << vxp->impureNode()->warnContextSecondary()); } // And, we need to check all tasks this task calls @@ -281,13 +281,13 @@ public: m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue); m_callGraph.dumpDotFilePrefixed("task_call"); } - virtual ~TaskStateVisitor() override {} + virtual ~TaskStateVisitor() override = default; VL_UNCOPYABLE(TaskStateVisitor); }; //###################################################################### -class TaskRelinkVisitor : public AstNVisitor { +class TaskRelinkVisitor final : public AstNVisitor { // Replace varrefs with new var pointer private: // NODE STATE @@ -317,13 +317,13 @@ public: explicit TaskRelinkVisitor(AstBegin* nodep) { // Passed temporary tree iterate(nodep); } - virtual ~TaskRelinkVisitor() override {} + virtual ~TaskRelinkVisitor() override = default; }; //###################################################################### // Task state, as a visitor of each AstNode -class TaskVisitor : public AstNVisitor { +class TaskVisitor final : public AstNVisitor { private: // NODE STATE // Each module: @@ -641,11 +641,7 @@ private: } AstNode* createDpiTemp(AstVar* portp, const string& suffix) { - string stmt = portp->dpiArgType(false, true) + " " + portp->name() + suffix; - if (!portp->basicp()->isDpiPrimitive()) { - stmt += "[" + cvtToStr(portp->widthWords()) + "]"; - } - stmt += ";\n"; + const string stmt = portp->dpiTmpVarType(portp->name() + suffix) + ";\n"; return new AstCStmt(portp->fileline(), stmt); } @@ -655,30 +651,80 @@ private: return new AstCStmt(portp->fileline(), stmt); } + static std::vector> unpackDimsAndStrides(AstVar* varp) { + std::vector> dimStrides; + if (AstUnpackArrayDType* dtypep = VN_CAST(varp->dtypep()->skipRefp(), UnpackArrayDType)) { + const std::vector dims = dtypep->unpackDimensions(); + dimStrides.resize(dims.size(), {nullptr, 0}); + dimStrides.back() = {dims.back(), 1}; + for (ssize_t i = dims.size() - 2; i >= 0; --i) { + dimStrides[i].first = dims[i]; + dimStrides[i].second = dimStrides[i + 1].second * dims[i + 1]->elementsConst(); + } + } + return dimStrides; + } + AstNode* createAssignDpiToInternal(AstVarScope* portvscp, const string& frName) { // Create assignment from DPI temporary into internal format + // DPI temporary is scalar or 1D array (if unpacked array) + // Internal representation is scalar, 1D, or multi-dimensional array (similar to SV) AstVar* portp = portvscp->varp(); string frstmt; - bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt); - if (useSetWSvlv) { - AstNode* linesp = new AstText(portp->fileline(), frstmt); - linesp->addNext(new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE)); - linesp->addNext(new AstText(portp->fileline(), "," + frName + ");")); - return new AstCStmt(portp->fileline(), linesp); - } + string ket; + const bool useSetWSvlv = V3Task::dpiToInternalFrStmt(portp, frName, frstmt, ket); // Use a AstCMath, as we want V3Clean to mask off bits that don't make sense. int cwidth = VL_IDATASIZE; - if (portp->basicp()) { + if (!useSetWSvlv && portp->basicp()) { if (portp->basicp()->keyword().isBitLogic()) { cwidth = VL_EDATASIZE * portp->widthWords(); } else { cwidth = portp->basicp()->keyword().width(); } } - AstNode* newp = new AstAssign( - portp->fileline(), new AstVarRef(portp->fileline(), portvscp, VAccess::WRITE), - new AstSel(portp->fileline(), new AstCMath(portp->fileline(), frstmt, cwidth, false), - 0, portp->width())); + + const std::vector> dimStrides + = unpackDimsAndStrides(portvscp->varp()); + const int total = dimStrides.empty() ? 1 + : dimStrides.front().first->elementsConst() + * dimStrides.front().second; + AstNode* newp = nullptr; + const int widthWords = portvscp->varp()->basicp()->widthWords(); + for (int i = 0; i < total; ++i) { + AstNode* srcp = new AstVarRef(portvscp->fileline(), portvscp, VAccess::WRITE); + // extract a scalar from multi-dimensional array (internal format) + for (auto&& dimStride : dimStrides) { + const size_t dimIdx = (i / dimStride.second) % dimStride.first->elementsConst(); + srcp = new AstArraySel(portvscp->fileline(), srcp, dimIdx); + } + AstNode* stmtp = nullptr; + // extract a scalar from DPI temporary var that is scalar or 1D array + if (useSetWSvlv) { + AstNode* linesp = new AstText(portvscp->fileline(), frstmt + ket); + linesp->addNext(srcp); + linesp->addNext( + new AstText(portvscp->fileline(), + "," + frName + " + " + cvtToStr(i * widthWords) + ");\n")); + stmtp = new AstCStmt(portvscp->fileline(), linesp); + } else { + string from = frstmt; + if (!dimStrides.empty()) { + // e.g. time is 64bit svLogicVector + const int coef = portvscp->varp()->basicp()->isDpiLogicVec() ? widthWords : 1; + from += "[" + cvtToStr(i * coef) + "]"; + } + from += ket; + AstNode* rhsp = new AstSel(portp->fileline(), + new AstCMath(portp->fileline(), from, cwidth, false), 0, + portp->width()); + stmtp = new AstAssign(portp->fileline(), srcp, rhsp); + } + if (i > 0) { + newp->addNext(stmtp); + } else { + newp = stmtp; + } + } return newp; } @@ -749,7 +795,10 @@ private: if (portp->isNonOutput()) { std::string frName - = portp->isInoutish() && portp->basicp()->isDpiPrimitive() ? "*" : ""; + = portp->isInoutish() && portp->basicp()->isDpiPrimitive() + && portp->dtypep()->skipRefp()->arrayUnpackedElements() == 1 + ? "*" + : ""; frName += portp->name(); dpip->addStmtsp(createAssignDpiToInternal(outvscp, frName)); } @@ -837,11 +886,11 @@ private: } else if (iter->second.second != dpiproto) { nodep->v3error( "Duplicate declaration of DPI function with different formal arguments: " - << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl - << nodep->warnMore() << "... New prototype: " << dpiproto << endl + << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' + << nodep->warnMore() << "... New prototype: " << dpiproto << '\n' << iter->second.first->warnOther() - << "... Original prototype: " << iter->second.second << endl + << "... Original prototype: " << iter->second.second << '\n' << iter->second.first->warnContextSecondary()); return true; } else { @@ -862,7 +911,7 @@ private: portp->v3warn( E_UNSUPPORTED, "Unsupported: DPI argument of type " - << portp->basicp()->prettyTypeName() << endl + << portp->basicp()->prettyTypeName() << '\n' << portp->warnMore() << "... For best portability, use bit, byte, int, or longint"); // We don't warn on logic either, although the 4-stateness is lost. @@ -913,7 +962,7 @@ private: args += "&" + name; } else { if (portp->isWritable() && portp->basicp()->isDpiPrimitive()) { - args += "&"; + if (!VN_IS(portp->dtypep()->skipRefp(), UnpackArrayDType)) args += "&"; } args += portp->name() + tmpSuffixp; @@ -1378,7 +1427,7 @@ public: : m_statep{statep} { iterate(nodep); } - virtual ~TaskVisitor() override {} + virtual ~TaskVisitor() override = default; }; //###################################################################### @@ -1532,37 +1581,76 @@ V3TaskConnects V3Task::taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp) string V3Task::assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix) { // Create assignment from internal format into DPI temporary + // Internal representation is scalar, 1D, or multi-dimensional array (similar to SV) + // DPI temporary is scalar or 1D array (if unpacked array) string stmt; string ket; // Someday we'll have better type support, and this can make variables and casts. // But for now, we'll just text-bash it. string frName = frPrefix + portp->name() + frSuffix; string toName = portp->name() + toSuffix; - if (portp->basicp()->isDpiBitVec()) { - stmt += ("VL_SET_SVBV_" + string(portp->dtypep()->charIQWN()) + "(" - + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); - } else if (portp->basicp()->isDpiLogicVec()) { - stmt += ("VL_SET_SVLV_" + string(portp->dtypep()->charIQWN()) + "(" - + cvtToStr(portp->width()) + ", " + toName + ", " + frName + ")"); + size_t unpackSize = 1; // non-unpacked array is treated as size 1 + int unpackDim = 0; + if (AstUnpackArrayDType* unpackp = VN_CAST(portp->dtypep()->skipRefp(), UnpackArrayDType)) { + unpackSize = unpackp->arrayUnpackedElements(); + unpackDim = unpackp->dimensions(false).second; + if (unpackDim > 0) UASSERT_OBJ(unpackSize > 0, portp, "size must be greater than 0"); + } + if (portp->basicp()->isDpiBitVec() || portp->basicp()->isDpiLogicVec()) { + const bool isBit = portp->basicp()->isDpiBitVec(); + const string idx = portp->name() + "__Vidx"; + stmt = "for (size_t " + idx + " = 0; " + idx + " < " + cvtToStr(unpackSize) + "; ++" + idx + + ") "; + stmt += (isBit ? "VL_SET_SVBV_" : "VL_SET_SVLV_") + + string(portp->dtypep()->skipRefp()->charIQWN()) + "(" + cvtToStr(portp->width()) + + ", "; + stmt += toName + " + " + cvtToStr(portp->dtypep()->skipRefp()->widthWords()) + " * " + idx + + ", "; + if (unpackDim > 0) { // Access multi-dimensional array as a 1D array + stmt += "(&" + frName; + for (int i = 0; i < unpackDim; ++i) stmt += "[0]"; + stmt += ")[" + idx + "])"; + } else { + stmt += frName + ")"; + } } else { - if (isPtr) stmt += "*"; // DPI outputs are pointers - stmt += toName + " = "; - if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) { + const bool isChandle + = portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE; + const bool isString + = portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING; + const string idx = portp->name() + "__Vidx"; + stmt = "for (size_t " + idx + " = 0; " + idx + " < " + cvtToStr(unpackSize) + "; ++" + idx + + ") "; + if (unpackDim > 0) { + stmt += toName + "[" + idx + "]"; + } else { + if (isPtr) stmt += "*"; // DPI outputs are pointers + stmt += toName; + } + stmt += " = "; + if (isChandle) { stmt += "VL_CVT_Q_VP("; ket += ")"; } - stmt += frName; - if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING) { - stmt += ".c_str()"; + if (unpackDim > 0) { + stmt += "(&" + frName; + for (int i = 0; i < unpackDim; ++i) stmt += "[0]"; + stmt += ")[" + idx + "]"; + } else { + stmt += frName; } + if (isString) stmt += ".c_str()"; } stmt += ket + ";\n"; return stmt; } -bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt) { +bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt, + string& ket) { + ket.clear(); if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::CHANDLE) { - frstmt = "VL_CVT_VP_Q(" + frName + ")"; + frstmt = "VL_CVT_VP_Q(" + frName; + ket = ")"; } else if ((portp->basicp() && portp->basicp()->isDpiPrimitive())) { frstmt = frName; } else { @@ -1572,15 +1660,18 @@ bool V3Task::dpiToInternalFrStmt(AstVar* portp, const string& frName, string& fr frstmt = "VL_SET_W_" + frSvType + "(" + cvtToStr(portp->width()) + ","; return true; } else { - frstmt = "VL_SET_" + string(portp->dtypep()->charIQWN()) + "_" + frSvType + "(" - + frName + ")"; + const AstNodeDType* dtypep = portp->dtypep()->skipRefp(); + frstmt = "VL_SET_" + string(dtypep->charIQWN()) + "_" + frSvType + "("; + if (VN_IS(dtypep, UnpackArrayDType)) frstmt += "&"; + frstmt += frName; + ket = ")"; } } return false; } const char* V3Task::dpiTemporaryVarSuffix() { - static const char suffix[] = "__Vcvt"; + static const char* const suffix = "__Vcvt"; return suffix; } diff --git a/src/V3Task.h b/src/V3Task.h index a1722a16c..78d7b0dde 100644 --- a/src/V3Task.h +++ b/src/V3Task.h @@ -32,14 +32,15 @@ typedef std::vector V3TaskConnects; // [ [port, pin-connects-to] //============================================================================ -class V3Task { +class V3Task final { public: static void taskAll(AstNetlist* nodep); /// Return vector of [port, pin-connects-to] (SLOW) static V3TaskConnects taskConnects(AstNodeFTaskRef* nodep, AstNode* taskStmtsp); static string assignInternalToDpi(AstVar* portp, bool isPtr, const string& frSuffix, const string& toSuffix, const string& frPrefix = ""); - static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt); + static bool dpiToInternalFrStmt(AstVar* portp, const string& frName, string& frstmt, + string& ket); static const char* dpiTemporaryVarSuffix(); }; diff --git a/src/V3Trace.cpp b/src/V3Trace.cpp index 28712534e..fcd5e7e03 100644 --- a/src/V3Trace.cpp +++ b/src/V3Trace.cpp @@ -51,7 +51,7 @@ //###################################################################### // Graph vertexes -class TraceActivityVertex : public V3GraphVertex { +class TraceActivityVertex final : public V3GraphVertex { AstNode* const m_insertp; vlsint32_t m_activityCode; bool m_slow; // If always slow, we can use the same code @@ -71,7 +71,7 @@ public: m_activityCode = code; m_slow = false; } - virtual ~TraceActivityVertex() override {} + virtual ~TraceActivityVertex() override = default; // ACCESSORS AstNode* insertp() const { if (!m_insertp) v3fatalSrc("Null insertp; probably called on a special always/slow."); @@ -95,14 +95,14 @@ public: } }; -class TraceCFuncVertex : public V3GraphVertex { +class TraceCFuncVertex final : public V3GraphVertex { AstCFunc* m_nodep; public: TraceCFuncVertex(V3Graph* graphp, AstCFunc* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceCFuncVertex() override {} + virtual ~TraceCFuncVertex() override = default; // ACCESSORS AstCFunc* nodep() const { return m_nodep; } virtual string name() const override { return nodep()->name(); } @@ -110,7 +110,7 @@ public: virtual FileLine* fileline() const override { return nodep()->fileline(); } }; -class TraceTraceVertex : public V3GraphVertex { +class TraceTraceVertex final : public V3GraphVertex { AstTraceDecl* const m_nodep; // TRACEINC this represents // nullptr, or other vertex with the real code() that duplicates this one TraceTraceVertex* m_duplicatep = nullptr; @@ -119,7 +119,7 @@ public: TraceTraceVertex(V3Graph* graphp, AstTraceDecl* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceTraceVertex() override {} + virtual ~TraceTraceVertex() override = default; // ACCESSORS AstTraceDecl* nodep() const { return m_nodep; } virtual string name() const override { return nodep()->name(); } @@ -132,14 +132,14 @@ public: } }; -class TraceVarVertex : public V3GraphVertex { +class TraceVarVertex final : public V3GraphVertex { AstVarScope* m_nodep; public: TraceVarVertex(V3Graph* graphp, AstVarScope* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TraceVarVertex() override {} + virtual ~TraceVarVertex() override = default; // ACCESSORS AstVarScope* nodep() const { return m_nodep; } virtual string name() const override { return nodep()->name(); } @@ -150,7 +150,7 @@ public: //###################################################################### // Trace state, as a visitor of each AstNode -class TraceVisitor : public EmitCBaseVisitor { +class TraceVisitor final : public EmitCBaseVisitor { private: // NODE STATE // V3Hashed @@ -426,7 +426,7 @@ private: void addActivitySetter(AstNode* insertp, uint32_t code) { FileLine* const fl = insertp->fileline(); AstAssign* const setterp = new AstAssign(fl, selectActivity(fl, code, VAccess::WRITE), - new AstConst(fl, AstConst::LogicTrue())); + new AstConst(fl, AstConst::BitTrue())); if (AstCCall* const callp = VN_CAST(insertp, CCall)) { callp->addNextHere(setterp); } else if (AstCFunc* const funcp = VN_CAST(insertp, CFunc)) { @@ -687,7 +687,7 @@ private: // Clear fine grained activity flags for (uint32_t i = 0; i < m_activityNumber; ++i) { AstNode* const clrp = new AstAssign(fl, selectActivity(fl, i, VAccess::WRITE), - new AstConst(fl, AstConst::LogicFalse())); + new AstConst(fl, AstConst::BitFalse())); cleanupFuncp->addStmtsp(clrp); } } diff --git a/src/V3Trace.h b/src/V3Trace.h index 07d7fd679..c45922fe6 100644 --- a/src/V3Trace.h +++ b/src/V3Trace.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Trace { +class V3Trace final { public: static void traceAll(AstNetlist* nodep); }; diff --git a/src/V3TraceDecl.cpp b/src/V3TraceDecl.cpp index f8669c6bd..ba248b720 100644 --- a/src/V3TraceDecl.cpp +++ b/src/V3TraceDecl.cpp @@ -31,7 +31,7 @@ //###################################################################### // TraceDecl state, as a visitor of each AstNode -class TraceDeclVisitor : public EmitCBaseVisitor { +class TraceDeclVisitor final : public EmitCBaseVisitor { private: // NODE STATE diff --git a/src/V3TraceDecl.h b/src/V3TraceDecl.h index 1327b45df..024d284a7 100644 --- a/src/V3TraceDecl.h +++ b/src/V3TraceDecl.h @@ -25,7 +25,7 @@ //============================================================================ -class V3TraceDecl { +class V3TraceDecl final { public: static void traceDeclAll(AstNetlist* nodep); }; diff --git a/src/V3Tristate.cpp b/src/V3Tristate.cpp index 922fac45b..cc192edd4 100644 --- a/src/V3Tristate.cpp +++ b/src/V3Tristate.cpp @@ -69,7 +69,7 @@ //###################################################################### -class TristateBaseVisitor : public AstNVisitor { +class TristateBaseVisitor VL_NOT_FINAL : public AstNVisitor { public: // METHODS VL_DEBUG_FUNC; // Declare debug() @@ -78,7 +78,7 @@ public: //###################################################################### // Graph support classes -class TristateVertex : public V3GraphVertex { +class TristateVertex final : public V3GraphVertex { AstNode* m_nodep; bool m_isTristate = false; // Logic indicates a tristate bool m_feedsTri = false; // Propagates to a tristate node (on RHS) @@ -87,7 +87,7 @@ public: TristateVertex(V3Graph* graphp, AstNode* nodep) : V3GraphVertex{graphp} , m_nodep{nodep} {} - virtual ~TristateVertex() override {} + virtual ~TristateVertex() override = default; // ACCESSORS AstNode* nodep() const { return m_nodep; } AstVar* varp() const { return VN_CAST(nodep(), Var); } @@ -110,7 +110,7 @@ public: //###################################################################### -class TristateGraph { +class TristateGraph final { // NODE STATE // AstVar::user5p -> TristateVertex* for variable being built // AstUser5InUse m_inuser5; // In visitor below @@ -271,7 +271,7 @@ public: // Given a node, flip any VarRef from LValue to RValue (i.e. make it an input) // See also V3LinkLValue::linkLValueSet -class TristatePinVisitor : public TristateBaseVisitor { +class TristatePinVisitor final : public TristateBaseVisitor { TristateGraph& m_tgraph; bool m_lvalue; // Flip to be an LVALUE // VISITORS @@ -307,12 +307,12 @@ public: , m_lvalue{lvalue} { iterate(nodep); } - virtual ~TristatePinVisitor() override {} + virtual ~TristatePinVisitor() override = default; }; //###################################################################### -class TristateVisitor : public TristateBaseVisitor { +class TristateVisitor final : public TristateBaseVisitor { // NODE STATE // *::user1p -> pointer to output enable __en expressions // *::user2 -> int - already visited, see U2_ enum @@ -329,7 +329,7 @@ class TristateVisitor : public TristateBaseVisitor { // TYPES typedef std::vector RefVec; - typedef std::map VarMap; + typedef std::unordered_map VarMap; enum : uint8_t { U2_GRAPHING = 1, // bit[0] if did m_graphing visit U2_NONGRAPH = 2, // bit[1] if did !m_graphing visit @@ -449,7 +449,7 @@ class TristateVisitor : public TristateBaseVisitor { } else { if (oldpullp->direction() != pullp->direction()) { pullp->v3warn(E_UNSUPPORTED, "Unsupported: Conflicting pull directions.\n" - << pullp->warnContextPrimary() << endl + << pullp->warnContextPrimary() << '\n' << oldpullp->warnOther() << "... Location of conflicting pull.\n" << oldpullp->warnContextSecondary()); @@ -981,6 +981,65 @@ class TristateVisitor : public TristateBaseVisitor { virtual void visit(AstEqWild* nodep) override { visitEqNeqWild(nodep); } virtual void visit(AstNeqWild* nodep) override { visitEqNeqWild(nodep); } + virtual void visit(AstCountBits* nodep) override { + std::array dropop; + dropop[0] = VN_IS(nodep->rhsp(), Const) && VN_CAST(nodep->rhsp(), Const)->num().isAnyZ(); + dropop[1] = VN_IS(nodep->thsp(), Const) && VN_CAST(nodep->thsp(), Const)->num().isAnyZ(); + dropop[2] = VN_IS(nodep->fhsp(), Const) && VN_CAST(nodep->fhsp(), Const)->num().isAnyZ(); + UINFO(4, " COUNTBITS(" << dropop[0] << dropop[1] << dropop[2] << " " << nodep << endl); + AstVarRef* varrefp = VN_CAST(nodep->lhsp(), VarRef); // Input variable + if (m_graphing) { + iterateAndNextNull(nodep->lhsp()); + if (!dropop[0]) iterateAndNextNull(nodep->rhsp()); + if (!dropop[1]) iterateAndNextNull(nodep->thsp()); + if (!dropop[2]) iterateAndNextNull(nodep->fhsp()); + } else { + AstNode* nonXp = nullptr; + if (!dropop[0]) + nonXp = nodep->rhsp(); + else if (!dropop[1]) + nonXp = nodep->thsp(); + else if (!dropop[2]) + nonXp = nodep->fhsp(); + // Replace 'z with non-Z + if (dropop[0] || dropop[1] || dropop[2]) { + // Unsupported: A $countones('0) should compare with the enables, but we don't + // do so at present, we only compare if there is a z in the equation. Otherwise + // we'd need to attach an enable to every signal, then optimize them away later + // when we determine the signal has no tristate + if (!VN_IS(nodep->lhsp(), VarRef)) { + nodep->v3warn(E_UNSUPPORTED, "Unsupported LHS tristate construct: " + << nodep->prettyTypeName()); + return; + } + AstVar* envarp = getCreateEnVarp(varrefp->varp()); + // If any drops, we need to add in the count of Zs (from __en) + UINFO(4, " COUNTBITS('z)-> " << nodep << endl); + AstNRelinker relinkHandle; + nodep->unlinkFrBack(&relinkHandle); + AstNode* newp = new AstCountOnes( + nodep->fileline(), new AstVarRef(nodep->fileline(), envarp, VAccess::READ)); + if (nonXp) { // Need to still count '0 or '1 or 'x's + if (dropop[0]) { + nodep->rhsp()->unlinkFrBack()->deleteTree(); + nodep->rhsp(nonXp->cloneTree(true)); + } + if (dropop[1]) { + nodep->thsp()->unlinkFrBack()->deleteTree(); + nodep->thsp(nonXp->cloneTree(true)); + } + if (dropop[2]) { + nodep->fhsp()->unlinkFrBack()->deleteTree(); + nodep->fhsp(nonXp->cloneTree(true)); + } + newp = new AstAdd(nodep->fileline(), nodep, newp); + } + if (debug() >= 9) newp->dumpTree(cout, "-countout: "); + relinkHandle.relink(newp); + } + iterateChildren(nodep); + } + } virtual void visit(AstPull* nodep) override { UINFO(9, dbgState() << nodep << endl); AstVarRef* varrefp = nullptr; @@ -1107,6 +1166,7 @@ class TristateVisitor : public TristateBaseVisitor { AstVar* enVarp = new AstVar(nodep->fileline(), AstVarType::MODULETEMP, nodep->name() + "__en" + cvtToStr(m_unique++), VFlagBitPacked(), enModVarp->width()); + enModVarp->direction(VDirection::INPUT); UINFO(9, " newenv " << enVarp << endl); AstPin* enpinp = new AstPin(nodep->fileline(), nodep->pinNum(), diff --git a/src/V3Tristate.h b/src/V3Tristate.h index 509a6bd94..5ea6c7d17 100644 --- a/src/V3Tristate.h +++ b/src/V3Tristate.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Tristate { +class V3Tristate final { public: static void tristateAll(AstNetlist* nodep); }; diff --git a/src/V3Undriven.cpp b/src/V3Undriven.cpp index 2e5dc239d..36077d610 100644 --- a/src/V3Undriven.cpp +++ b/src/V3Undriven.cpp @@ -37,7 +37,7 @@ //###################################################################### // Class for every variable we may process -class UndrivenVarEntry { +class UndrivenVarEntry final { // MEMBERS AstVar* m_varp; // Variable this tracks std::vector m_wholeFlags; // Used/Driven on whole vector @@ -57,7 +57,7 @@ public: m_bitFlags.resize(varp->width() * FLAGS_PER_BIT); for (int i = 0; i < varp->width() * FLAGS_PER_BIT; i++) m_bitFlags[i] = false; } - ~UndrivenVarEntry() {} + ~UndrivenVarEntry() = default; private: // METHODS @@ -226,7 +226,7 @@ public: //###################################################################### // Undriven state, as a visitor of each AstNode -class UndrivenVisitor : public AstNVisitor { +class UndrivenVisitor final : public AstNVisitor { private: // NODE STATE // Netlist: @@ -237,7 +237,7 @@ private: AstUser2InUse m_inuser2; // STATE - std::vector m_entryps[3]; // Nodes to delete when we are finished + std::array, 3> m_entryps; // Nodes to delete when finished bool m_inBBox = false; // In black box; mark as driven+used bool m_inContAssign = false; // In continuous assignment bool m_inProcAssign = false; // In procedural assignment diff --git a/src/V3Undriven.h b/src/V3Undriven.h index 4475ab053..2a4e5d18c 100644 --- a/src/V3Undriven.h +++ b/src/V3Undriven.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Undriven { +class V3Undriven final { public: static void undrivenAll(AstNetlist* nodep); }; diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp index 21e61b019..0c2dcc553 100644 --- a/src/V3Unknown.cpp +++ b/src/V3Unknown.cpp @@ -41,7 +41,7 @@ //###################################################################### -class UnknownVisitor : public AstNVisitor { +class UnknownVisitor final : public AstNVisitor { private: // NODE STATE // Cleared on Netlist @@ -137,6 +137,7 @@ private: virtual void visit(AstNodeModule* nodep) override { UINFO(4, " MOD " << nodep << endl); VL_RESTORER(m_modp); + VL_RESTORER(m_constXCvt); { m_modp = nodep; m_constXCvt = true; @@ -144,25 +145,34 @@ private: } } virtual void visit(AstAssignDly* nodep) override { - m_assigndlyp = nodep; - VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. - m_assigndlyp = nullptr; + VL_RESTORER(m_assigndlyp); + { + m_assigndlyp = nodep; + VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. + } } virtual void visit(AstAssignW* nodep) override { - m_assignwp = nodep; - VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. - m_assignwp = nullptr; + VL_RESTORER(m_assignwp); + { + m_assignwp = nodep; + VL_DO_DANGLING(iterateChildren(nodep), nodep); // May delete nodep. + } } virtual void visit(AstCaseItem* nodep) override { - m_constXCvt = false; // Avoid losing the X's in casex - iterateAndNextNull(nodep->condsp()); - m_constXCvt = true; - iterateAndNextNull(nodep->bodysp()); + VL_RESTORER(m_constXCvt); + { + m_constXCvt = false; // Avoid losing the X's in casex + iterateAndNextNull(nodep->condsp()); + m_constXCvt = true; + iterateAndNextNull(nodep->bodysp()); + } } virtual void visit(AstNodeDType* nodep) override { - m_constXCvt = false; // Avoid losing the X's in casex - iterateChildren(nodep); - m_constXCvt = true; + VL_RESTORER(m_constXCvt); + { + m_constXCvt = false; // Avoid losing the X's in casex + iterateChildren(nodep); + } } void visitEqNeqCase(AstNodeBiop* nodep) { UINFO(4, " N/EQCASE->EQ " << nodep << endl); @@ -244,10 +254,46 @@ private: iterateChildren(nodep); // Ahh, we're two state, so this is easy UINFO(4, " ISUNKNOWN->0 " << nodep << endl); - AstConst* newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + AstConst* newp = new AstConst(nodep->fileline(), AstConst::BitFalse()); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } + virtual void visit(AstCountBits* nodep) override { + // Ahh, we're two state, so this is easy + std::array dropop; + dropop[0] = VN_IS(nodep->rhsp(), Const) && VN_CAST(nodep->rhsp(), Const)->num().isAnyX(); + dropop[1] = VN_IS(nodep->thsp(), Const) && VN_CAST(nodep->thsp(), Const)->num().isAnyX(); + dropop[2] = VN_IS(nodep->fhsp(), Const) && VN_CAST(nodep->fhsp(), Const)->num().isAnyX(); + UINFO(4, " COUNTBITS(" << dropop[0] << dropop[1] << dropop[2] << " " << nodep << endl); + + AstNode* nonXp = nullptr; + if (!dropop[0]) + nonXp = nodep->rhsp(); + else if (!dropop[1]) + nonXp = nodep->thsp(); + else if (!dropop[2]) + nonXp = nodep->fhsp(); + else { // Was all X-s + UINFO(4, " COUNTBITS('x)->0 " << nodep << endl); + AstConst* newp = new AstConst(nodep->fileline(), AstConst::BitFalse()); + nodep->replaceWith(newp); + VL_DO_DANGLING(nodep->deleteTree(), nodep); + return; + } + if (dropop[0]) { + nodep->rhsp()->unlinkFrBack()->deleteTree(); + nodep->rhsp(nonXp->cloneTree(true)); + } + if (dropop[1]) { + nodep->thsp()->unlinkFrBack()->deleteTree(); + nodep->thsp(nonXp->cloneTree(true)); + } + if (dropop[2]) { + nodep->fhsp()->unlinkFrBack()->deleteTree(); + nodep->fhsp(nonXp->cloneTree(true)); + } + iterateChildren(nodep); + } virtual void visit(AstConst* nodep) override { if (m_constXCvt && nodep->num().isFourState()) { UINFO(4, " CONST4 " << nodep << endl); @@ -288,10 +334,11 @@ private: new AstAssign( nodep->fileline(), new AstVarRef(nodep->fileline(), newvarp, VAccess::WRITE), - new AstOr( - nodep->fileline(), new AstConst(nodep->fileline(), numb1), - new AstAnd(nodep->fileline(), new AstConst(nodep->fileline(), numbx), - new AstRand(nodep->fileline(), nodep->dtypep(), true))))); + new AstOr(nodep->fileline(), new AstConst(nodep->fileline(), numb1), + new AstAnd(nodep->fileline(), + new AstConst(nodep->fileline(), numbx), + new AstRand(nodep->fileline(), AstRand::Reset{}, + nodep->dtypep(), true))))); // Add inits in front of other statement. // In the future, we should stuff the initp into the module's constructor. AstNode* afterp = m_modp->stmtsp()->unlinkFrBackWithNext(); diff --git a/src/V3Unknown.h b/src/V3Unknown.h index db784a95a..2139cf771 100644 --- a/src/V3Unknown.h +++ b/src/V3Unknown.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Unknown { +class V3Unknown final { public: static void unknownAll(AstNetlist* nodep); }; diff --git a/src/V3Unroll.cpp b/src/V3Unroll.cpp index 7a9c15e04..85b7d4484 100644 --- a/src/V3Unroll.cpp +++ b/src/V3Unroll.cpp @@ -39,7 +39,7 @@ //###################################################################### // Unroll state, as a visitor of each AstNode -class UnrollVisitor : public AstNVisitor { +class UnrollVisitor final : public AstNVisitor { private: // STATE AstVar* m_forVarp; // Iterator variable @@ -118,11 +118,10 @@ private: m_forVarp = VN_CAST(initAssp->lhsp(), VarRef)->varp(); m_forVscp = VN_CAST(initAssp->lhsp(), VarRef)->varScopep(); if (VN_IS(nodep, GenFor) && !m_forVarp->isGenVar()) { - nodep->v3error("Non-genvar used in generate for: " // - << m_forVarp->prettyNameQ() << endl); + nodep->v3error("Non-genvar used in generate for: " << m_forVarp->prettyNameQ()); } else if (!VN_IS(nodep, GenFor) && m_forVarp->isGenVar()) { nodep->v3error("Genvar not legal in non-generate for (IEEE 1800-2017 27.4): " - << m_forVarp->prettyNameQ() << endl + << m_forVarp->prettyNameQ() << '\n' << nodep->warnMore() << "... Suggest move for loop upwards to generate-level scope."); } diff --git a/src/V3Unroll.h b/src/V3Unroll.h index 39e588c41..61b662f1b 100644 --- a/src/V3Unroll.h +++ b/src/V3Unroll.h @@ -28,7 +28,7 @@ class UnrollVisitor; -class UnrollStateful { +class UnrollStateful final { // MEMBERS UnrollVisitor* m_unrollerp; VL_UNCOPYABLE(UnrollStateful); @@ -44,7 +44,7 @@ public: //============================================================================ -class V3Unroll { +class V3Unroll final { public: static void unrollAll(AstNetlist* nodep); }; diff --git a/src/V3Waiver.cpp b/src/V3Waiver.cpp index 6cfa87687..31b6b9c86 100644 --- a/src/V3Waiver.cpp +++ b/src/V3Waiver.cpp @@ -34,20 +34,18 @@ void V3Waiver::write(const std::string& filename) { if (ofp->fail()) v3fatal("Can't write " << filename); *ofp << "// DESCR" - "IPTION: Verilator output: Waivers generated with --waiver-output" - << std::endl - << endl; + "IPTION: Verilator output: Waivers generated with --waiver-output\n\n"; - *ofp << "`verilator_config" << endl << endl; + *ofp << "`verilator_config\n\n"; - *ofp << "// Below you find suggested waivers. You have three options:" << endl; - *ofp << "// 1. Fix the reason for the linter warning" << endl; - *ofp << "// 2. Keep the waiver permanently if you are sure this is okay" << endl; - *ofp << "// 3. Keep the waiver temporarily to suppress the output" << endl << endl; + *ofp << "// Below you find suggested waivers. You have three options:\n"; + *ofp << "// 1. Fix the reason for the linter warning\n"; + *ofp << "// 2. Keep the waiver permanently if you are sure this is okay\n"; + *ofp << "// 3. Keep the waiver temporarily to suppress the output\n\n"; - if (s_waiverList.size() == 0) { *ofp << "// No waivers needed - great!" << endl; } + if (s_waiverList.empty()) *ofp << "// No waivers needed - great!\n"; - for (const auto& i : s_waiverList) *ofp << "// " << i << std::endl << endl; + for (const auto& i : s_waiverList) *ofp << "// " << i << "\n\n"; } V3Waiver::WaiverList V3Waiver::s_waiverList; diff --git a/src/V3Waiver.h b/src/V3Waiver.h index 67d4d65a0..7c93aa52c 100644 --- a/src/V3Waiver.h +++ b/src/V3Waiver.h @@ -22,7 +22,7 @@ #include #include -class V3Waiver { +class V3Waiver final { // TYPES typedef std::vector WaiverList; static WaiverList s_waiverList; diff --git a/src/V3Width.cpp b/src/V3Width.cpp index 7afd7a905..5fcac846d 100644 --- a/src/V3Width.cpp +++ b/src/V3Width.cpp @@ -103,7 +103,7 @@ std::ostream& operator<<(std::ostream& str, const Determ& rhs) { //###################################################################### // Width state, as a visitor of each AstNode -class WidthVP { +class WidthVP final { // Parameters to pass down hierarchy with visit functions. AstNodeDType* m_dtypep; // Parent's data type to resolve to Stage m_stage; // If true, report errors @@ -164,7 +164,7 @@ std::ostream& operator<<(std::ostream& str, const WidthVP* vup) { //###################################################################### -class WidthClearVisitor { +class WidthClearVisitor final { // Rather than a AstNVisitor, can just quickly touch every node void clearWidthRecurse(AstNode* nodep) { for (; nodep; nodep = nodep->nextp()) { @@ -179,7 +179,7 @@ class WidthClearVisitor { public: // CONSTRUCTORS explicit WidthClearVisitor(AstNetlist* nodep) { clearWidthRecurse(nodep); } - virtual ~WidthClearVisitor() {} + virtual ~WidthClearVisitor() = default; }; //###################################################################### @@ -188,7 +188,7 @@ public: //###################################################################### -class WidthVisitor : public AstNVisitor { +class WidthVisitor final : public AstNVisitor { private: // TYPES typedef std::map, AstVar*> TableMap; @@ -198,11 +198,10 @@ private: // STATE WidthVP* m_vup = nullptr; // Current node state bool m_paramsOnly; // Computing parameter value; limit operation - AstRange* m_cellRangep - = nullptr; // Range for arrayed instantiations, nullptr for normal instantiations + AstCell* m_cellp = nullptr; // Current cell for arrayed instantiations AstNodeFTask* m_ftaskp = nullptr; // Current function/task AstNodeProcedure* m_procedurep = nullptr; // Current final/always - AstLambdaArgRef* m_lambdaArgRefp = nullptr; // Argument to above lambda + AstWith* m_withp = nullptr; // Current 'with' statement AstFunc* m_funcp = nullptr; // Current function AstAttrOf* m_attrp = nullptr; // Current attribute bool m_doGenerate; // Do errors later inside generate statement @@ -795,7 +794,7 @@ private: AstConst* widthConstp = VN_CAST(nodep->widthp(), Const); if (!widthConstp) { nodep->v3error("Width of bit extract isn't a constant"); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); return; } int width = nodep->widthConst(); @@ -1086,7 +1085,7 @@ private: virtual void visit(AstFell* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } virtual void visit(AstPast* nodep) override { @@ -1116,7 +1115,7 @@ private: virtual void visit(AstRose* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } @@ -1130,7 +1129,7 @@ private: virtual void visit(AstStable* nodep) override { if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->exprp(), SELF, BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } @@ -1138,18 +1137,18 @@ private: if (m_vup->prelim()) { iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } virtual void visit(AstRand* nodep) override { if (m_vup->prelim()) { - nodep->dtypeSetSigned32(); // Says the spec - } - } - virtual void visit(AstURandom* nodep) override { - if (m_vup->prelim()) { - nodep->dtypeSetUInt32(); // Says the spec + if (nodep->urandom()) { + nodep->dtypeSetUInt32(); // Says the spec + } else { + nodep->dtypeSetSigned32(); // Says the spec + } + if (nodep->seedp()) iterateCheckSigned32(nodep, "seed", nodep->seedp(), BOTH); } } virtual void visit(AstURandomRange* nodep) override { @@ -1183,7 +1182,7 @@ private: virtual void visit(AstIsUnbounded* nodep) override { if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } virtual void visit(AstUCFunc* nodep) override { @@ -1416,7 +1415,7 @@ private: = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim); AstNode* dimp = nodep->dimp()->unlinkFrBack(); AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); - varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -1568,7 +1567,7 @@ private: virtual void visit(AstRefDType* nodep) override { if (nodep->doingWidth()) { // Early exit if have circular parameter definition nodep->v3error("Typedef's type is circular: " << nodep->prettyName()); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); nodep->doingWidth(false); return; } @@ -1606,10 +1605,10 @@ private: virtual void visit(AstTypedef* nodep) override { if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed if (auto* refp = checkRefToTypedefRecurse(nodep, nodep)) { - nodep->v3error("Typedef has self-reference: " << nodep->prettyNameQ() << endl - << nodep->warnContextPrimary() << endl + nodep->v3error("Typedef has self-reference: " << nodep->prettyNameQ() << '\n' + << nodep->warnContextPrimary() << '\n' << refp->warnOther() - << "... Location of reference" << endl + << "... Location of reference\n" << refp->warnContextSecondary()); // May cause internel error but avoids infinite loop on dump refp->typedefp(nullptr); @@ -1730,7 +1729,7 @@ private: if (!underDtp) underDtp = underp->dtypep()->basicp(); if (!underDtp) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Size-changing cast on non-basic data type"); - underDtp = VN_CAST(nodep->findLogicBoolDType(), BasicDType); + underDtp = VN_CAST(nodep->findBitDType(), BasicDType); } UASSERT_OBJ(underp == nodep->op1p(), nodep, "Assuming op1 is cast value"); // A cast propagates its size to the lower expression and is included in the maximum @@ -1771,7 +1770,7 @@ private: UASSERT_OBJ(nodep->valuep(), nodep, "circular, but without value"); nodep->v3error("Variable's initial value is circular: " << nodep->prettyNameQ()); pushDeletep(nodep->valuep()->unlinkFrBack()); - nodep->valuep(new AstConst(nodep->fileline(), AstConst::LogicTrue())); + nodep->valuep(new AstConst(nodep->fileline(), AstConst::BitTrue())); nodep->dtypeFrom(nodep->valuep()); nodep->didWidth(true); return; @@ -1788,12 +1787,6 @@ private: nodep->dtypep(newp); v3Global.rootp()->typeTablep()->addTypesp(newp); } - } else if (nodep->isIO() - && !(VN_IS(nodep->dtypeSkipRefp(), BasicDType) - || VN_IS(nodep->dtypeSkipRefp(), NodeArrayDType) - || VN_IS(nodep->dtypeSkipRefp(), NodeUOrStructDType))) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: Inputs and outputs must be simple data types"); } if (VN_IS(nodep->dtypep()->skipRefToConstp(), ConstDType)) nodep->isConst(true); // Parameters if implicit untyped inherit from what they are assigned to @@ -1960,8 +1953,8 @@ private: if (inits.find(num) != inits.end()) { // IEEE says illegal AstNode* otherp = inits.find(num)->second; itemp->v3error("Overlapping enumeration value: " - << itemp->prettyNameQ() << endl - << itemp->warnContextPrimary() << endl + << itemp->prettyNameQ() << '\n' + << itemp->warnContextPrimary() << '\n' << otherp->warnOther() << "... Location of original declaration\n" << otherp->warnContextSecondary()); } else { @@ -1999,7 +1992,7 @@ private: } virtual void visit(AstConsAssoc* nodep) override { // Type computed when constructed here - auto* vdtypep = VN_CAST(m_vup->dtypep(), AssocArrayDType); + auto* vdtypep = VN_CAST(m_vup->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(vdtypep, nodep, "ConsAssoc requires assoc upper parent data type"); if (m_vup->prelim()) { nodep->dtypeFrom(vdtypep); @@ -2011,7 +2004,7 @@ private: } virtual void visit(AstSetAssoc* nodep) override { // Type computed when constructed here - auto* vdtypep = VN_CAST(m_vup->dtypep(), AssocArrayDType); + auto* vdtypep = VN_CAST(m_vup->dtypep()->skipRefp(), AssocArrayDType); UASSERT_OBJ(vdtypep, nodep, "SetsAssoc requires assoc upper parent data type"); if (m_vup->prelim()) { nodep->dtypeFrom(vdtypep); @@ -2024,7 +2017,7 @@ private: } virtual void visit(AstConsDynArray* nodep) override { // Type computed when constructed here - AstDynArrayDType* vdtypep = VN_CAST(m_vup->dtypep(), DynArrayDType); + AstDynArrayDType* vdtypep = VN_CAST(m_vup->dtypep()->skipRefp(), DynArrayDType); UASSERT_OBJ(vdtypep, nodep, "ConsDynArray requires queue upper parent data type"); if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p()); @@ -2056,7 +2049,7 @@ private: } virtual void visit(AstConsQueue* nodep) override { // Type computed when constructed here - AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep(), QueueDType); + AstQueueDType* vdtypep = VN_CAST(m_vup->dtypep()->skipRefp(), QueueDType); UASSERT_OBJ(vdtypep, nodep, "ConsQueue requires queue upper parent data type"); if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(vdtypep, PRELIM).p()); @@ -2123,7 +2116,7 @@ private: for (AstNode* itemp = nodep->itemsp(); itemp; itemp = itemp->nextp()) { iterateCheck(nodep, "Inside Item", itemp, CONTEXT, FINAL, subDTypep, EXTEND_EXP); } - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); if (debug() >= 9) nodep->dumpTree(cout, "-inside-in: "); // Now rip out the inside and replace with simple math AstNode* newp = nullptr; @@ -2147,7 +2140,7 @@ private: newp = inewp; } } - if (!newp) newp = new AstConst(nodep->fileline(), AstConst::LogicFalse()); + if (!newp) newp = new AstConst(nodep->fileline(), AstConst::BitFalse()); if (debug() >= 9) newp->dumpTree(cout, "-inside-out: "); nodep->replaceWith(newp); VL_DO_DANGLING(pushDeletep(nodep), nodep); @@ -2204,6 +2197,9 @@ private: } virtual void visit(AstClass* nodep) override { if (nodep->didWidthAndSet()) return; + // Must do extends first, as we may in functions under this class + // start following a tree of extends that takes us to other classes + userIterateAndNext(nodep->extendsp(), nullptr); userIterateChildren(nodep, nullptr); // First size all members nodep->repairCache(); } @@ -2250,7 +2246,7 @@ private: } UINFO(1, "found object " << foundp << endl); nodep->v3fatalSrc("MemberSel of non-variable\n" - << nodep->warnContextPrimary() << endl + << nodep->warnContextPrimary() << '\n' << foundp->warnOther() << "... Location of found object\n" << foundp->warnContextSecondary()); } @@ -2274,7 +2270,7 @@ private: << nodep->fromp()->dtypep()->prettyTypeName() << "'"); } // Error handling - nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse())); + nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::BitFalse())); VL_DO_DANGLING(pushDeletep(nodep), nodep); } AstNode* memberSelClass(AstMemberSel* nodep, AstClassRefDType* adtypep) { @@ -2374,10 +2370,12 @@ private: } } AstWith* methodWithArgument(AstMethodCall* nodep, bool required, bool arbReturn, - AstNodeDType* returnDtp, AstNodeDType* argDtp) { + AstNodeDType* returnDtp, AstNodeDType* indexDtp, + AstNodeDType* valueDtp) { UASSERT_OBJ(arbReturn || returnDtp, nodep, "Null return type"); if (AstWith* withp = VN_CAST(nodep->pinsp(), With)) { - withp->argrefp()->dtypep(argDtp); + withp->indexArgRefp()->dtypep(indexDtp); + withp->valueArgRefp()->dtypep(valueDtp); userIterate(withp, WidthVP(returnDtp, BOTH).p()); withp->unlinkFrBack(); return withp; @@ -2490,33 +2488,16 @@ private: return; } // Need a runtime lookup table. Yuk. - // Most enums unless overridden are 32 bits, so we size array - // based on max enum value used. - // Ideally we would have a fast algorithm when a number is - // of small width and complete and so can use an array, and - // a map for when the value is many bits and sparse. - uint64_t msbdim = 0; - { - for (AstEnumItem* itemp = adtypep->itemsp(); itemp; - itemp = VN_CAST(itemp->nextp(), EnumItem)) { - const AstConst* vconstp = VN_CAST(itemp->valuep(), Const); - UASSERT_OBJ(vconstp, nodep, "Enum item without constified value"); - if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad(); - } - if (adtypep->itemsp()->width() > 64 || msbdim >= (1 << 16)) { - nodep->v3warn(E_UNSUPPORTED, - "Unsupported: enum next/prev method on enum with > 10 bits"); - return; - } - } + uint64_t msbdim = enumMaxValue(nodep, adtypep); int selwidth = V3Number::log2b(msbdim) + 1; // Width to address a bit AstVar* varp = enumVarp(adtypep, attrType, (1ULL << selwidth) - 1); AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, VAccess::READ); - varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp()); + varrefp->classOrPackagep(v3Global.rootp()->dollarUnitPkgAddp()); AstNode* newp = new AstArraySel( nodep->fileline(), varrefp, - // Select in case widths are - // off due to msblen!=width + // Select in case widths are off due to msblen!=width + // We return "random" values if outside the range, which is fine + // as next/previous on illegal values just need something good out new AstSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), 0, selwidth)); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); @@ -2571,7 +2552,7 @@ private: || nodep->name() == "sum" || nodep->name() == "product") { // All value return AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2592,8 +2573,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2602,8 +2583,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + adtypep->keyDTypep(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2664,7 +2645,7 @@ private: || nodep->name() == "sum" || nodep->name() == "product") { // All value return AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2675,7 +2656,8 @@ private: || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { - withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), + adtypep->subDTypep()); } methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -2696,8 +2678,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last" || nodep->name() == "find_index") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2706,8 +2688,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2795,7 +2777,7 @@ private: } else if (nodep->name() == "and" || nodep->name() == "or" || nodep->name() == "xor" || nodep->name() == "sum" || nodep->name() == "product") { AstWith* withp = methodWithArgument(nodep, false, false, adtypep->subDTypep(), - adtypep->subDTypep()); + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2806,7 +2788,8 @@ private: || nodep->name() == "sort" || nodep->name() == "rsort") { AstWith* withp = nullptr; if (nodep->name() == "sort" || nodep->name() == "rsort") { - withp = methodWithArgument(nodep, false, true, nullptr, adtypep->subDTypep()); + withp = methodWithArgument(nodep, false, true, nullptr, nodep->findUInt32DType(), + adtypep->subDTypep()); } methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::WRITE); @@ -2827,8 +2810,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find" || nodep->name() == "find_first" || nodep->name() == "find_last") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2837,8 +2820,8 @@ private: if (!nodep->firstAbovep()) newp->makeStatement(); } else if (nodep->name() == "find_index" || nodep->name() == "find_first_index" || nodep->name() == "find_last_index") { - AstWith* withp = methodWithArgument(nodep, true, false, nodep->findLogicBoolDType(), - adtypep->subDTypep()); + AstWith* withp = methodWithArgument(nodep, true, false, nodep->findBitDType(), + nodep->findUInt32DType(), adtypep->subDTypep()); methodOkArguments(nodep, 0, 0); methodCallLValueRecurse(nodep, nodep->fromp(), VAccess::READ); newp = new AstCMethodHard(nodep->fileline(), nodep->fromp()->unlinkFrBack(), @@ -2880,12 +2863,13 @@ private: newp = new AstFuncRef(nodep->fileline(), ftaskp->name(), argsp); } newp->taskp(ftaskp); - newp->packagep(classp); + newp->classOrPackagep(classp); nodep->replaceWith(newp); VL_DO_DANGLING(nodep->deleteTree(), nodep); } else { nodep->taskp(ftaskp); nodep->dtypeFrom(ftaskp); + nodep->classOrPackagep(classp); if (VN_IS(ftaskp, Task)) nodep->makeStatement(); } return; @@ -3084,7 +3068,8 @@ private: virtual void visit(AstNew* nodep) override { if (nodep->didWidthAndSet()) return; - AstClassRefDType* refp = VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType); + AstClassRefDType* refp + = m_vup ? VN_CAST(m_vup->dtypeNullSkipRefp(), ClassRefDType) : nullptr; if (!refp) { // e.g. int a = new; nodep->v3error("new() not expected in this context"); return; @@ -3095,7 +3080,7 @@ private: UASSERT_OBJ(classp, nodep, "Unlinked"); if (AstNodeFTask* ftaskp = VN_CAST(classp->findMember("new"), Func)) { nodep->taskp(ftaskp); - nodep->packagep(classp); + nodep->classOrPackagep(classp); } else { // Either made explicitly or V3LinkDot made implicitly classp->v3fatalSrc("Can't find class's new"); @@ -3105,7 +3090,6 @@ private: "Illegal to call 'new' using an abstract virtual class (IEEE 1800-2017 8.21)"); } userIterate(nodep->taskp(), nullptr); - userIterateChildren(nodep, nullptr); processFTaskRefArgs(nodep); } virtual void visit(AstNewCopy* nodep) override { @@ -3452,7 +3436,7 @@ private: } if (patp) { // Determine initial values - vdtypep = nodep->findLogicBoolDType(); + vdtypep = nodep->findBitDType(); patp->dtypep(vdtypep); AstNode* valuep = patternMemberValueIterate(patp); { // Packed. Convert to concat for now. @@ -3536,7 +3520,7 @@ private: iterateCheckBool(nodep, "Disable", nodep->disablep(), BOTH); // it's like an if() condition. } - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } @@ -4052,8 +4036,8 @@ private: if (conDTypep == pinDTypep // If match, we're golden || similarDTypeRecurse(conDTypep, pinDTypep)) { userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p()); - } else if (m_cellRangep) { - int numInsts = m_cellRangep->elementsConst(); + } else if (m_cellp->rangep()) { + int numInsts = m_cellp->rangep()->elementsConst(); if (conwidth == pinwidth) { // Arrayed instants: widths match so connect to each instance subDTypep = conDTypep; // = same expr dtype @@ -4069,7 +4053,7 @@ private: << " requires " << pinwidth << " or " << pinwidth * numInsts << " bits, but connection's " << nodep->exprp()->prettyTypeName() << " generates " << conwidth - << " bits."); + << " bits. (IEEE 1800-2017 23.3.3)"); subDTypep = conDTypep; // = same expr dtype } userIterateAndNext(nodep->exprp(), WidthVP(subDTypep, FINAL).p()); @@ -4080,7 +4064,7 @@ private: << " requires matching types;" << " ref requires " << pinDTypep->prettyDTypeNameQ() << " data type but connection is " - << conDTypep->prettyDTypeNameQ() << " data type." << endl); + << conDTypep->prettyDTypeNameQ() << " data type."); } else if (nodep->modVarp()->isTristate()) { if (pinwidth != conwidth) { nodep->v3warn(E_UNSUPPORTED, @@ -4138,6 +4122,8 @@ private: // if (debug()) nodep->dumpTree(cout, "- PinOut: "); } virtual void visit(AstCell* nodep) override { + VL_RESTORER(m_cellp); + m_cellp = nodep; if (!m_paramsOnly) { if (VN_IS(nodep->modp(), NotFoundModule)) { // We've resolved parameters and hit a module that we couldn't resolve. It's @@ -4147,14 +4133,10 @@ private: << nodep->modName() << "'"); v3Global.opt.filePathLookedMsg(nodep->modNameFileline(), nodep->modName()); } - if (nodep->rangep()) { - m_cellRangep = nodep->rangep(); - userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p()); - } + if (nodep->rangep()) userIterateAndNext(nodep->rangep(), WidthVP(SELF, BOTH).p()); userIterateAndNext(nodep->pinsp(), nullptr); } userIterateAndNext(nodep->paramsp(), nullptr); - m_cellRangep = nullptr; } virtual void visit(AstGatePin* nodep) override { if (m_vup->prelim()) { @@ -4185,10 +4167,17 @@ private: if (nodep->didWidth()) return; if (nodep->doingWidth()) { nodep->v3warn(E_UNSUPPORTED, "Unsupported: Recursive function or task call"); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); nodep->didWidth(true); return; } + if (nodep->classMethod() && nodep->name() == "rand_mode") { + nodep->v3error("The 'rand_mode' method is built-in and cannot be overridden" + " (IEEE 1800-2017 18.8)"); + } else if (nodep->classMethod() && nodep->name() == "constraint_mode") { + nodep->v3error("The 'constraint_mode' method is built-in and cannot be overridden" + " (IEEE 1800-2017 18.9)"); + } // Function hasn't been widthed, so make it so. // Would use user1 etc, but V3Width called from too many places to spend a user nodep->doingWidth(true); @@ -4234,6 +4223,46 @@ private: nodep->dtypeFrom(nodep->taskp()); // if (debug()) nodep->dumpTree(cout, " FuncOut: "); } + // Returns true if dtypep0 and dtypep1 have same dimensions + static bool areSameSize(AstUnpackArrayDType* dtypep0, AstUnpackArrayDType* dtypep1) { + const std::vector dims0 = dtypep0->unpackDimensions(); + const std::vector dims1 = dtypep1->unpackDimensions(); + if (dims0.size() != dims1.size()) return false; + for (size_t i = 0; i < dims0.size(); ++i) { + if (dims0[i]->elementsConst() != dims1[i]->elementsConst()) return false; + } + return true; + } + // Makes sure that port and pin have same size and same datatype + void checkUnpackedArrayArgs(AstVar* portp, AstNode* pinp) { + if (AstUnpackArrayDType* portDtypep + = VN_CAST(portp->dtypep()->skipRefp(), UnpackArrayDType)) { + if (AstUnpackArrayDType* pinDtypep + = VN_CAST(pinp->dtypep()->skipRefp(), UnpackArrayDType)) { + if (!areSameSize(portDtypep, pinDtypep)) { + pinp->v3warn(E_UNSUPPORTED, + "Shape of the argument does not match the shape of the parameter " + << "(" << pinDtypep->prettyDTypeNameQ() << " v.s. " + << portDtypep->prettyDTypeNameQ() << ")"); + } + if (portDtypep->basicp()->width() != pinDtypep->basicp()->width() + || (portDtypep->basicp()->keyword() != pinDtypep->basicp()->keyword() + && !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT + && pinDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC) + && !(portDtypep->basicp()->keyword() == AstBasicDTypeKwd::LOGIC + && pinDtypep->basicp()->keyword() + == AstBasicDTypeKwd::LOGIC_IMPLICIT))) { + pinp->v3warn(E_UNSUPPORTED, + "Shape of the argument does not match the shape of the parameter " + << "(" << pinDtypep->basicp()->prettyDTypeNameQ() << " v.s. " + << portDtypep->basicp()->prettyDTypeNameQ() << ")"); + } + } else { + pinp->v3warn(E_UNSUPPORTED, "Argument is not an unpacked array while parameter " + << portp->prettyNameQ() << " is"); + } + } + } void processFTaskRefArgs(AstNodeFTaskRef* nodep) { // For arguments, is assignment-like context; see IEEE rules in AstNodeAssign // Function hasn't been widthed, so make it so. @@ -4284,6 +4313,7 @@ private: else if (portp->basicp() && portp->basicp()->keyword() == AstBasicDTypeKwd::STRING && !VN_IS(pinp, CvtPackString) && !VN_IS(pinp, SFormatF) // Already generates a string + && !VN_IS(portp->dtypep(), UnpackArrayDType) // Unpacked array must match && !(VN_IS(pinp, VarRef) && VN_CAST(pinp, VarRef)->varp()->basicp()->keyword() == AstBasicDTypeKwd::STRING)) { @@ -4307,6 +4337,7 @@ private: AstNode* pinp = argp->exprp(); if (!pinp) continue; // Argument error we'll find later // Change data types based on above accept completion + if (nodep->taskp()->dpiImport()) checkUnpackedArrayArgs(portp, pinp); if (portp->isDouble()) VL_DO_DANGLING(spliceCvtD(pinp), pinp); } } @@ -4376,10 +4407,11 @@ private: virtual void visit(AstWith* nodep) override { // Should otherwise be underneath a method call AstNodeDType* vdtypep = m_vup->dtypeNullSkipRefp(); - VL_RESTORER(m_lambdaArgRefp); + VL_RESTORER(m_withp); { - m_lambdaArgRefp = nodep->argrefp(); - userIterateChildren(nodep->argrefp(), nullptr); + m_withp = nodep; + userIterateChildren(nodep->indexArgRefp(), nullptr); + userIterateChildren(nodep->valueArgRefp(), nullptr); if (vdtypep) { userIterateAndNext(nodep->exprp(), WidthVP(nodep->dtypep(), PRELIM).p()); } else { // 'sort with' allows arbitrary type @@ -4391,8 +4423,12 @@ private: } } virtual void visit(AstLambdaArgRef* nodep) override { - UASSERT_OBJ(m_lambdaArgRefp, nodep, "LambdaArgRef not underneath with lambda"); - nodep->dtypeFrom(m_lambdaArgRefp); + UASSERT_OBJ(m_withp, nodep, "LambdaArgRef not underneath 'with' lambda"); + if (nodep->index()) { + nodep->dtypeFrom(m_withp->indexArgRefp()); + } else { + nodep->dtypeFrom(m_withp->valueArgRefp()); + } } virtual void visit(AstNetlist* nodep) override { // Iterate modules backwards, in bottom-up order. That's faster @@ -4486,7 +4522,7 @@ private: UASSERT_OBJ(!nodep->op2p(), nodep, "For unary ops only!"); if (m_vup->prelim()) { iterateCheckBool(nodep, "LHS", nodep->op1p(), BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } void visit_log_and_or(AstNodeBiop* nodep) { @@ -4498,7 +4534,7 @@ private: if (m_vup->prelim()) { iterateCheckBool(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckBool(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } void visit_red_and_or(AstNodeUniop* nodep) { @@ -4510,7 +4546,7 @@ private: // Sign: unsigned out (11.8.1) if (m_vup->prelim()) { iterateCheckSizedSelf(nodep, "LHS", nodep->lhsp(), SELF, BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } void visit_red_unknown(AstNodeUniop* nodep) { @@ -4522,7 +4558,7 @@ private: // Sign: unsigned out (11.8.1) if (m_vup->prelim()) { userIterateAndNext(nodep->lhsp(), WidthVP(SELF, BOTH).p()); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } @@ -4585,7 +4621,7 @@ private: iterateCheck(nodep, "RHS", nodep->rhsp(), CONTEXT, FINAL, subDTypep, (signedFl ? EXTEND_LHS : EXTEND_ZERO), warnOn); } - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } void visit_cmp_real(AstNodeBiop* nodep) { @@ -4600,7 +4636,7 @@ private: // See similar handling in visit_cmp_eq_gt where created iterateCheckReal(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckReal(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } void visit_cmp_string(AstNodeBiop* nodep) { @@ -4613,7 +4649,7 @@ private: // See similar handling in visit_cmp_eq_gt where created iterateCheckString(nodep, "LHS", nodep->lhsp(), BOTH); iterateCheckString(nodep, "RHS", nodep->rhsp(), BOTH); - nodep->dtypeSetLogicBool(); + nodep->dtypeSetBit(); } } @@ -5128,10 +5164,10 @@ private: nodep->v3error("Logical operator " << nodep->prettyTypeName() << " expects a non-complex data type on the " << side << "."); - underp->replaceWith(new AstConst(nodep->fileline(), AstConst::LogicFalse())); + underp->replaceWith(new AstConst(nodep->fileline(), AstConst::BitFalse())); VL_DO_DANGLING(pushDeletep(underp), underp); } else { - bool bad = widthBad(underp, nodep->findLogicBoolDType()); + bool bad = widthBad(underp, nodep->findBitDType()); if (bad) { { // if (warnOn), but not needed here if (debug() > 4) nodep->backp()->dumpTree(cout, " back: "); @@ -5214,7 +5250,8 @@ private: << " expected non-interface on " << side << " but '" << underp->name() << "' is an interface."); } else { - // Hope it just works out + // Hope it just works out (perhaps a cast will deal with it) + underp = userIterateSubtreeReturnEdits(underp, WidthVP(expDTypep, FINAL).p()); } } return underp; @@ -5407,9 +5444,7 @@ private: case AstType::atMulS: newp = new AstMul(fl, lhsp, rhsp); break; case AstType::atShiftR: newp = new AstShiftRS(fl, lhsp, rhsp); break; case AstType::atShiftRS: newp = new AstShiftR(fl, lhsp, rhsp); break; - default: - nodep->v3fatalSrc("Node needs sign change, but bad case: " << nodep << endl); - break; + default: nodep->v3fatalSrc("Node needs sign change, but bad case: " << nodep); break; } UINFO(6, " ReplaceWithUOrSVersion: " << nodep << " w/ " << newp << endl); nodep->replaceWith(newp); @@ -5447,7 +5482,7 @@ private: case AstType::atMul: case AstType::atMulS: newp = new AstMulD(fl, lhsp, rhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep << endl); + nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep); break; } UINFO(6, " ReplaceWithDVersion: " << nodep << " w/ " << newp << endl); @@ -5479,7 +5514,7 @@ private: case AstType::atLte: case AstType::atLteS: newp = new AstLteN(fl, lhsp, rhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to string, but bad case: " << nodep << endl); + nodep->v3fatalSrc("Node needs conversion to string, but bad case: " << nodep); break; } UINFO(6, " ReplaceWithNVersion: " << nodep << " w/ " << newp << endl); @@ -5498,7 +5533,7 @@ private: switch (nodep->type()) { case AstType::atNegate: newp = new AstNegateD(fl, lhsp); break; default: - nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep << endl); + nodep->v3fatalSrc("Node needs conversion to double, but bad case: " << nodep); break; } UINFO(6, " ReplaceWithDVersion: " << nodep << " w/ " << newp << endl); @@ -5666,6 +5701,26 @@ private: m_tableMap.insert(make_pair(make_pair(nodep, attrType), varp)); return varp; } + uint64_t enumMaxValue(const AstNode* errNodep, const AstEnumDType* adtypep) { + // Most enums unless overridden are 32 bits, so we size array + // based on max enum value used. + // Ideally we would have a fast algorithm when a number is + // of small width and complete and so can use an array, and + // a map for when the value is many bits and sparse. + uint64_t maxval = 0; + for (const AstEnumItem* itemp = adtypep->itemsp(); itemp; + itemp = VN_CAST(itemp->nextp(), EnumItem)) { + const AstConst* vconstp = VN_CAST(itemp->valuep(), Const); + UASSERT_OBJ(vconstp, errNodep, "Enum item without constified value"); + if (vconstp->toUQuad() >= maxval) maxval = vconstp->toUQuad(); + } + if (adtypep->itemsp()->width() > 64 || maxval >= (1 << 16)) { + errNodep->v3warn(E_UNSUPPORTED, + "Unsupported: enum next/prev method on enum with > 10 bits"); + return 0; + } + return maxval; + } AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) { // Return a variable table which has specified dimension properties for this variable const auto pos = m_tableMap.find(make_pair(nodep, attrType)); @@ -5909,7 +5964,7 @@ public: AstNode* mainAcceptEdit(AstNode* nodep) { return userIterateSubtreeReturnEdits(nodep, WidthVP(SELF, BOTH).p()); } - virtual ~WidthVisitor() override {} + virtual ~WidthVisitor() override = default; }; //###################################################################### diff --git a/src/V3Width.h b/src/V3Width.h index 5ba10dc80..03e1fb037 100644 --- a/src/V3Width.h +++ b/src/V3Width.h @@ -25,7 +25,7 @@ //============================================================================ -class V3Width { +class V3Width final { public: static int debug(); static void width(AstNetlist* nodep); diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h index ff6e3c03a..b84b5a110 100644 --- a/src/V3WidthCommit.h +++ b/src/V3WidthCommit.h @@ -34,7 +34,7 @@ /// Remove all $signed, $unsigned, we're done with them. /// This step is only called on real V3Width, not intermediate e.g. widthParams -class WidthRemoveVisitor : public AstNVisitor { +class WidthRemoveVisitor final : public AstNVisitor { private: // METHODS void replaceWithSignedVersion(AstNode* nodep, AstNode* newp) { @@ -55,8 +55,8 @@ private: public: // CONSTRUCTORS - WidthRemoveVisitor() {} - virtual ~WidthRemoveVisitor() override {} + WidthRemoveVisitor() = default; + virtual ~WidthRemoveVisitor() override = default; AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } }; @@ -64,11 +64,14 @@ public: // Now that all widthing is complete, // Copy all width() to widthMin(). V3Const expects this -class WidthCommitVisitor : public AstNVisitor { +class WidthCommitVisitor final : public AstNVisitor { // NODE STATE // AstVar::user1p -> bool, processed AstUser1InUse m_inuser1; + // STATE + AstNodeModule* m_modp = nullptr; + public: // METHODS static AstConst* newIfConstCommitSize(AstConst* nodep) { @@ -112,7 +115,50 @@ private: } return nodep; } + void classEncapCheck(AstNode* nodep, AstNode* defp, AstClass* defClassp) { + // Call on non-local class to check local/protected status and complain + bool local = false; + bool prot = false; + if (const auto varp = VN_CAST(defp, Var)) { + local = varp->isHideLocal(); + prot = varp->isHideProtected(); + } else if (const auto ftaskp = VN_CAST(defp, NodeFTask)) { + local = ftaskp->isHideLocal(); + prot = ftaskp->isHideProtected(); + } else { + nodep->v3fatalSrc("ref to unhandled definition type " << defp->prettyTypeName()); + } + if (local || prot) { + auto refClassp = VN_CAST(m_modp, Class); + const char* how = nullptr; + if (local && defClassp && refClassp != defClassp) { + how = "'local'"; + } else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)) { + how = "'protected'"; + } + if (how) { + UINFO(9, "refclass " << refClassp << endl); + UINFO(9, "defclass " << defClassp << endl); + nodep->v3warn(E_ENCAPSULATED, nodep->prettyNameQ() + << " is hidden as " << how + << " within this context (IEEE 1800-2017 8.18)\n" + << nodep->warnContextPrimary() << endl + << nodep->warnOther() + << "... Location of definition" << endl + << defp->warnContextSecondary()); + } + } + } + // VISITORS + virtual void visit(AstNodeModule* nodep) override { + VL_RESTORER(m_modp); + { + m_modp = nodep; + iterateChildren(nodep); + editDType(nodep); + } + } virtual void visit(AstConst* nodep) override { UASSERT_OBJ(nodep->dtypep(), nodep, "No dtype"); iterate(nodep->dtypep()); // Do datatype first @@ -153,6 +199,32 @@ private: nodep->virtRefDTypep(editOneDType(nodep->virtRefDTypep())); nodep->virtRefDType2p(editOneDType(nodep->virtRefDType2p())); } + virtual void visit(AstNodeFTask* nodep) override { + iterateChildren(nodep); + editDType(nodep); + if (nodep->classMethod() && nodep->pureVirtual() && VN_IS(m_modp, Class) + && !VN_CAST(m_modp, Class)->isVirtual()) { + nodep->v3error( + "Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21)"); + } + } + virtual void visit(AstNodeVarRef* nodep) override { + iterateChildren(nodep); + editDType(nodep); + classEncapCheck(nodep, nodep->varp(), VN_CAST(nodep->classOrPackagep(), Class)); + } + virtual void visit(AstNodeFTaskRef* nodep) override { + iterateChildren(nodep); + editDType(nodep); + classEncapCheck(nodep, nodep->taskp(), VN_CAST(nodep->classOrPackagep(), Class)); + } + virtual void visit(AstMemberSel* nodep) override { + iterateChildren(nodep); + editDType(nodep); + if (auto* classrefp = VN_CAST(nodep->fromp()->dtypep(), ClassRefDType)) { + classEncapCheck(nodep, nodep->varp(), classrefp->classp()); + } // else might be struct, etc + } virtual void visit(AstNodePreSel* nodep) override { // LCOV_EXCL_LINE // This check could go anywhere after V3Param nodep->v3fatalSrc("Presels should have been removed before this point"); @@ -171,7 +243,7 @@ public: // Don't want to repairCache, as all needed nodes have been added back in // a repair would prevent dead nodes from being detected } - virtual ~WidthCommitVisitor() override {} + virtual ~WidthCommitVisitor() override = default; }; //###################################################################### diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp index c3232066d..37f5959ff 100644 --- a/src/V3WidthSel.cpp +++ b/src/V3WidthSel.cpp @@ -36,7 +36,7 @@ //###################################################################### // Width state, as a visitor of each AstNode -class WidthSelVisitor : public AstNVisitor { +class WidthSelVisitor final : public AstNVisitor { private: // IMPORTANT //**** This is not a normal visitor, in that all iteration is instead @@ -67,7 +67,7 @@ private: : m_errp{errp} , m_dtypep{dtypep} , m_fromRange{fromRange} {} - ~FromData() {} + ~FromData() = default; }; FromData fromDataForArray(AstNode* nodep, AstNode* basefromp) { // What is the data type and information for this SEL-ish's from()? @@ -579,9 +579,9 @@ private: public: // CONSTRUCTORS - WidthSelVisitor() {} + WidthSelVisitor() = default; + virtual ~WidthSelVisitor() override = default; AstNode* mainAcceptEdit(AstNode* nodep) { return iterateSubtreeReturnEdits(nodep); } - virtual ~WidthSelVisitor() override {} }; //###################################################################### diff --git a/src/VlcBucket.h b/src/VlcBucket.h index 97df0c4b1..4a2c30afc 100644 --- a/src/VlcBucket.h +++ b/src/VlcBucket.h @@ -25,15 +25,15 @@ // This is a bitmap array - we store a single bit to indicate a test // has hit that point with sufficient coverage. -class VlcBuckets { +class VlcBuckets final { private: // MEMBERS vluint64_t* m_datap = nullptr; ///< Pointer to first bucket (dynamically allocated) vluint64_t m_dataSize = 0; ///< Current entries in m_datap vluint64_t m_bucketsCovered = 0; ///< Num buckets with sufficient coverage - static inline vluint64_t covBit(vluint64_t point) { return 1ULL << (point & 63); } - inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; } + static vluint64_t covBit(vluint64_t point) { return 1ULL << (point & 63); } + vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; } void allocate(vluint64_t point) { vluint64_t oldsize = m_dataSize; if (m_dataSize < point) m_dataSize = (point + 64) & ~63ULL; // Keep power of two diff --git a/src/VlcOptions.h b/src/VlcOptions.h index 423bfd1eb..53940bbb9 100644 --- a/src/VlcOptions.h +++ b/src/VlcOptions.h @@ -31,7 +31,7 @@ typedef std::set VlStringSet; -class VlcOptions { +class VlcOptions final { // MEMBERS (general options) // clang-format off string m_annotateOut; // main switch: --annotate I @@ -51,8 +51,8 @@ private: public: // CONSTRUCTORS - VlcOptions() {} - ~VlcOptions() {} + VlcOptions() = default; + ~VlcOptions() = default; // METHODS void parseOptsList(int argc, char** argv); diff --git a/src/VlcPoint.h b/src/VlcPoint.h index 208dc5c56..36eea2feb 100644 --- a/src/VlcPoint.h +++ b/src/VlcPoint.h @@ -29,7 +29,7 @@ //******************************************************************** // VlcPoint - A coverage point (across all tests) -class VlcPoint { +class VlcPoint final { private: // MEMBERS string m_name; //< Name of the point @@ -42,7 +42,7 @@ public: VlcPoint(const string& name, vluint64_t pointNum) : m_name{name} , m_pointNum{pointNum} {} - ~VlcPoint() {} + ~VlcPoint() = default; // ACCESSORS const string& name() const { return m_name; } vluint64_t pointNum() const { return m_pointNum; } @@ -77,20 +77,20 @@ public: } static void dumpHeader() { cout << "Points:\n"; - cout << " Num, TestsCover, Count, Name" << endl; + cout << " Num, TestsCover, Count, Name\n"; } void dump() const { cout << " " << std::setw(8) << std::setfill('0') << pointNum(); cout << ", " << std::setw(7) << std::setfill(' ') << testsCovering(); cout << ", " << std::setw(7) << std::setfill(' ') << count(); - cout << ", \"" << name() << "\"" << endl; + cout << ", \"" << name() << "\"\n"; } }; //******************************************************************** // VlcPoints - Container of all points -class VlcPoints { +class VlcPoints final { private: // MEMBERS typedef std::map NameMap; // Sorted by name (ordered) @@ -106,8 +106,8 @@ public: ByName::iterator end() { return m_nameMap.end(); } // CONSTRUCTORS - VlcPoints() {} - ~VlcPoints() {} + VlcPoints() = default; + ~VlcPoints() = default; // METHODS void dump() { diff --git a/src/VlcSource.h b/src/VlcSource.h index 06d1cd847..7874b9de0 100644 --- a/src/VlcSource.h +++ b/src/VlcSource.h @@ -26,7 +26,7 @@ //******************************************************************** // VlcColumnCount - count at specific source file, line and column -class VlcSourceCount { +class VlcSourceCount final { private: // MEMBERS int m_lineno; ///< Line number @@ -39,7 +39,7 @@ public: VlcSourceCount(int lineno, int column) : m_lineno{lineno} , m_column{column} {} - ~VlcSourceCount() {} + ~VlcSourceCount() = default; // ACCESSORS int lineno() const { return m_lineno; } @@ -57,7 +57,7 @@ public: //******************************************************************** // VlcSource - source file to annotate -class VlcSource { +class VlcSource final { public: // TYPES typedef std::map ColumnMap; // Map of {column} @@ -73,7 +73,7 @@ public: // CONSTRUCTORS explicit VlcSource(const string& name) : m_name{name} {} - ~VlcSource() {} + ~VlcSource() = default; // ACCESSORS const string& name() const { return m_name; } @@ -98,7 +98,7 @@ public: //******************************************************************** // VlcSources - Container of all source files -class VlcSources { +class VlcSources final { public: // TYPES typedef std::map NameMap; @@ -114,8 +114,8 @@ public: NameMap::iterator end() { return m_sources.end(); } // CONSTRUCTORS - VlcSources() {} - ~VlcSources() {} + VlcSources() = default; + ~VlcSources() = default; // METHODS VlcSource& findNewSource(const string& name) { diff --git a/src/VlcTest.h b/src/VlcTest.h index d1489e661..5cc1c3ae2 100644 --- a/src/VlcTest.h +++ b/src/VlcTest.h @@ -29,7 +29,7 @@ //******************************************************************** // VlcTest - a single testrun i.e. a file containing coverage data -class VlcTest { +class VlcTest final { private: // MEMBERS string m_name; //< Name of the test @@ -46,7 +46,7 @@ public: : m_name{name} , m_computrons{comp} , m_testrun{testrun} {} - ~VlcTest() {} + ~VlcTest() = default; // ACCESSORS const string& name() const { return m_name; } @@ -65,7 +65,7 @@ public: static void dumpHeader() { cout << "Tests:\n"; // cout<<" Testrun, Computrons,"; // Currently not loaded - cout << " Covered, Rank, RankPts, Filename" << endl; + cout << " Covered, Rank, RankPts, Filename\n"; } void dump(bool bucketsToo) { if (testrun() || computrons() != 0.0) { // currently unused // LCOV_EXCL_LINE @@ -76,7 +76,7 @@ public: cout << " " << std::setw(7) << std::setfill(' ') << bucketsCovered(); cout << ", " << std::setw(7) << std::setfill(' ') << rank(); cout << ", " << std::setw(7) << std::setfill(' ') << rankPoints(); - cout << ", \"" << name() << "\"" << endl; + cout << ", \"" << name() << "\"\n"; if (bucketsToo) m_buckets.dump(); } }; @@ -84,7 +84,7 @@ public: //******************************************************************** // VlcTests - Container of all tests -class VlcTests { +class VlcTests final { public: // TYPES typedef std::vector ByName; @@ -100,7 +100,7 @@ public: ByName::iterator end() { return m_tests.end(); } // CONSTRUCTORS - VlcTests() {} + VlcTests() = default; ~VlcTests() { for (auto it = begin(); it != end(); ++it) { VL_DO_CLEAR(delete *it, *it = nullptr); } } diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp index 4ff050d5f..cd87e5879 100644 --- a/src/VlcTop.cpp +++ b/src/VlcTop.cpp @@ -69,10 +69,10 @@ void VlcTop::writeCoverage(const string& filename) { return; } - os << "# SystemC::Coverage-3" << endl; + os << "# SystemC::Coverage-3\n"; for (const auto& i : m_points) { const VlcPoint& point = m_points.pointNumber(i.second); - os << "C '" << point.name() << "' " << point.count() << endl; + os << "C '" << point.name() << "' " << point.count() << '\n'; } } @@ -109,7 +109,7 @@ void VlcTop::writeInfo(const string& filename) { os << "TN:verilator_coverage\n"; for (auto& si : m_sources) { VlcSource& source = si.second; - os << "SF:" << source.name() << endl; + os << "SF:" << source.name() << '\n'; VlcSource::LinenoMap& lines = source.lines(); for (auto& li : lines) { int lineno = li.first; @@ -134,7 +134,7 @@ void VlcTop::writeInfo(const string& filename) { //******************************************************************** struct CmpComputrons { - inline bool operator()(const VlcTest* lhsp, const VlcTest* rhsp) const { + bool operator()(const VlcTest* lhsp, const VlcTest* rhsp) const { if (lhsp->computrons() != rhsp->computrons()) { return lhsp->computrons() < rhsp->computrons(); } @@ -206,7 +206,7 @@ void VlcTop::annotateCalc() { unsigned thresh = (!threshStr.empty()) ? atoi(threshStr.c_str()) : opt.annotateMin(); bool ok = (point.count() >= thresh); UINFO(9, "AnnoCalc count " << filename << ":" << lineno << ":" << point.column() << " " - << point.count() << " " << point.linescov() << endl); + << point.count() << " " << point.linescov() << '\n'); // Base coverage source.incCount(lineno, point.column(), point.count(), ok); // Additional lines covered by this statement @@ -263,8 +263,8 @@ void VlcTop::annotateCalcNeeded() { } float pct = totCases ? (100 * totOk / totCases) : 0; cout << "Total coverage (" << totOk << "/" << totCases << ") "; - cout << std::fixed << std::setw(3) << std::setprecision(2) << pct << "%" << endl; - if (totOk != totCases) cout << "See lines with '%00' in " << opt.annotateOut() << endl; + cout << std::fixed << std::setw(3) << std::setprecision(2) << pct << "%\n"; + if (totOk != totCases) cout << "See lines with '%00' in " << opt.annotateOut() << '\n'; } void VlcTop::annotateOutputFiles(const string& dirname) { @@ -290,7 +290,7 @@ void VlcTop::annotateOutputFiles(const string& dirname) { return; } - os << "\t// verilator_coverage annotation" << endl; + os << "\t// verilator_coverage annotation\n"; int lineno = 0; while (!is.eof()) { @@ -308,7 +308,7 @@ void VlcTop::annotateOutputFiles(const string& dirname) { // UINFO(0,"Source // "< yD_FGETS "$fgets" %token yD_FINISH "$finish" %token yD_FLOOR "$floor" +%token yD_FMONITOR "$fmonitor" +%token yD_FMONITORB "$fmonitorb" +%token yD_FMONITORH "$fmonitorh" +%token yD_FMONITORO "$fmonitoro" %token yD_FOPEN "$fopen" %token yD_FREAD "$fread" %token yD_FREWIND "$frewind" %token yD_FSCANF "$fscanf" %token yD_FSEEK "$fseek" +%token yD_FSTROBE "$fstrobe" +%token yD_FSTROBEB "$fstrobeb" +%token yD_FSTROBEH "$fstrobeh" +%token yD_FSTROBEO "$fstrobeo" %token yD_FTELL "$ftell" %token yD_FWRITE "$fwrite" %token yD_FWRITEB "$fwriteb" @@ -761,6 +769,12 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_LN "$ln" %token yD_LOG10 "$log10" %token yD_LOW "$low" +%token yD_MONITOR "$monitor" +%token yD_MONITORB "$monitorb" +%token yD_MONITORH "$monitorh" +%token yD_MONITORO "$monitoro" +%token yD_MONITOROFF "$monitoroff" +%token yD_MONITORON "$monitoron" %token yD_ONEHOT "$onehot" %token yD_ONEHOT0 "$onehot0" %token yD_PAST "$past" @@ -789,6 +803,10 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"}) %token yD_STABLE "$stable" %token yD_STIME "$stime" %token yD_STOP "$stop" +%token yD_STROBE "$strobe" +%token yD_STROBEB "$strobeb" +%token yD_STROBEH "$strobeh" +%token yD_STROBEO "$strobeo" %token yD_SWRITE "$swrite" %token yD_SWRITEB "$swriteb" %token yD_SWRITEH "$swriteh" @@ -1837,8 +1855,10 @@ data_typeNoRef: // ==IEEE: data_type, excluding class_type etc referenc // // IEEE has ['.' modport] but that will conflict with port // // declarations which decode '.' modport themselves, so // // instead see data_typeVar - | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ { $$ = nullptr; BBUNSUP($1, "Unsupported: virtual interface"); } - | yVIRTUAL__anyID id/*interface*/ { $$ = nullptr; BBUNSUP($1, "Unsupported: virtual data type"); } + | yVIRTUAL__INTERFACE yINTERFACE id/*interface*/ + { $$ = new AstBasicDType($1, AstBasicDTypeKwd::CHANDLE); BBUNSUP($1, "Unsupported: virtual interface"); } + | yVIRTUAL__anyID id/*interface*/ + { $$ = new AstBasicDType($1, AstBasicDTypeKwd::CHANDLE); BBUNSUP($1, "Unsupported: virtual data type"); } | type_reference { $$ = $1; } // // IEEE: class_scope: see data_type above // // IEEE: class_type: see data_type above @@ -3112,14 +3132,14 @@ statement_item: // IEEE: statement_item | yP_MINUSGT idDotted/*hierarchical_identifier-event*/ ';' { // AssignDly because we don't have stratified queue, and need to // read events, clear next event, THEN apply this set - $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::LogicTrue())); } + $$ = new AstAssignDly($1, $2, new AstConst($1, AstConst::BitTrue())); } //UNSUP yP_MINUSGTGT delay_or_event_controlE hierarchical_identifier/*event*/ ';' { UNSUP } // // IEEE remove below | yP_MINUSGTGT delayE idDotted/*hierarchical_identifier-event*/ ';' - { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::LogicTrue())); } + { $$ = new AstAssignDly($1, $3, new AstConst($1, AstConst::BitTrue())); } // // // IEEE: loop_statement - | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1,AstConst::LogicTrue()),$2); } + | yFOREVER stmtBlock { $$ = new AstWhile($1,new AstConst($1, AstConst::BitTrue()), $2); } | yREPEAT '(' expr ')' stmtBlock { $$ = new AstRepeat($1,$3,$5);} | yWHILE '(' expr ')' stmtBlock { $$ = new AstWhile($1,$3,$5);} // // for's first ';' is in for_initialization @@ -3177,7 +3197,7 @@ statementFor: // IEEE: part of statement $$->addStmtsp(new AstWhile($1, $4,$8,$6)); } | yFOR '(' for_initialization ';' for_stepE ')' stmtBlock { $$ = new AstBegin($1, "", $3, false, true); - $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::LogicTrue()),$7,$5)); } + $$->addStmtsp(new AstWhile($1, new AstConst($1,AstConst::BitTrue()), $7, $5)); } ; statementVerilatorPragmas: @@ -3578,6 +3598,14 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_DISPLAYH '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, $3, 'h'); } | yD_DISPLAYO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, nullptr, 'o'); } | yD_DISPLAYO '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, nullptr, $3, 'o'); } + | yD_MONITOR '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3); } + | yD_MONITORB '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'b'); } + | yD_MONITORH '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'h'); } + | yD_MONITORO '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, nullptr, $3, 'o'); } + | yD_STROBE '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3); } + | yD_STROBEB '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'b'); } + | yD_STROBEH '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'h'); } + | yD_STROBEO '(' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, nullptr, $3, 'o'); } | yD_WRITE parenE { $$ = nullptr; } // NOP | yD_WRITE '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, nullptr, $3); } | yD_WRITEB parenE { $$ = nullptr; } // NOP @@ -3594,10 +3622,18 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FDISPLAYH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'h'); } | yD_FDISPLAYO '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, nullptr, 'o'); } | yD_FDISPLAYO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_DISPLAY, $3, $5, 'o'); } - | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5); } - | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'b'); } - | yD_FWRITEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'h'); } - | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_WRITE, $3, $5, 'o'); } + | yD_FMONITOR '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5); } + | yD_FMONITORB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'b'); } + | yD_FMONITORH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'h'); } + | yD_FMONITORO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_MONITOR, $3, $5, 'o'); } + | yD_FSTROBE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5); } + | yD_FSTROBEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'b'); } + | yD_FSTROBEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'h'); } + | yD_FSTROBEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_STROBE, $3, $5, 'o'); } + | yD_FWRITE '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5); } + | yD_FWRITEB '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5, 'b'); } + | yD_FWRITEH '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5, 'h'); } + | yD_FWRITEO '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1, AstDisplayType::DT_WRITE, $3, $5, 'o'); } | yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, nullptr, nullptr); } | yD_INFO '(' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_INFO, nullptr, $3); } | yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::DT_WARNING, nullptr, nullptr); } @@ -3608,6 +3644,9 @@ system_t_call: // IEEE: system_tf_call (as task) | yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, nullptr, nullptr); $$->addNext(new AstStop($1, false)); DEL($3); } | yD_FATAL '(' expr ',' exprDispList ')' { $$ = new AstDisplay($1,AstDisplayType::DT_FATAL, nullptr, $5); $$->addNext(new AstStop($1, false)); DEL($3); } // + | yD_MONITOROFF parenE { $$ = new AstMonitorOff($1, true); } + | yD_MONITORON parenE { $$ = new AstMonitorOff($1, false); } + // | yD_PRINTTIMESCALE { $$ = new AstPrintTimeScale($1); } | yD_PRINTTIMESCALE '(' ')' { $$ = new AstPrintTimeScale($1); } | yD_PRINTTIMESCALE '(' idClassSel ')' { $$ = new AstPrintTimeScale($1); DEL($3); } @@ -3711,9 +3750,8 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_PAST '(' expr ',' expr ',' expr ')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } | yD_PAST '(' expr ',' expr ',' expr ',' expr')' { $$ = $3; BBUNSUP($1, "Unsupported: $past expr2 and clock arguments"); } | yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); } - // // Seeding is unsupported as would be slow to invalidate all per-thread RNGs - | yD_RANDOM '(' expr ')' { $$ = new AstRand($1); BBUNSUP($1, "Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag"); } - | yD_RANDOM parenE { $$ = new AstRand($1); } + | yD_RANDOM '(' expr ')' { $$ = new AstRand($1, $3, false); } + | yD_RANDOM parenE { $$ = new AstRand($1, nullptr, false); } | yD_REALTIME parenE { $$ = new AstTimeD($1, VTimescale(VTimescale::NONE)); } | yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); } | yD_REWIND '(' idClassSel ')' { $$ = new AstFSeek($1, $3, new AstConst($1, 0), new AstConst($1, 0)); } @@ -3742,9 +3780,9 @@ system_f_call_or_t: // IEEE: part of system_tf_call (can be task or func) | yD_TYPENAME '(' exprOrDataType ')' { $$ = new AstAttrOf($1, AstAttrType::TYPENAME, $3); } | yD_UNGETC '(' expr ',' expr ')' { $$ = new AstFUngetC($1, $5, $3); } // Arg swap to file first | yD_UNPACKED_DIMENSIONS '(' exprOrDataType ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); } - | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); } - | yD_URANDOM '(' expr ')' { $$ = new AstURandom($1); BBUNSUP($1, "Unsupported: Seed on $urandom. Suggest use +verilator+seed+ runtime flag"); } - | yD_URANDOM parenE { $$ = new AstURandom($1); } + | yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1, $3); } + | yD_URANDOM '(' expr ')' { $$ = new AstRand($1, $3, true); } + | yD_URANDOM parenE { $$ = new AstRand($1, nullptr, true); } | yD_URANDOM_RANGE '(' expr ',' expr ')' { $$ = new AstURandomRange($1, $3, $5); } | yD_VALUEPLUSARGS '(' expr ',' expr ')' { $$ = new AstValuePlusArgs($1, $3, $5); } ; @@ -3874,7 +3912,7 @@ taskId: // | packageClassScope id { $$ = new AstTask($$, *$2, nullptr); - $$->packagep($1); + $$->classOrPackagep($1); SYMP->pushNewUnderNodeOrCurrent($$, $1); } ; @@ -3913,7 +3951,7 @@ funcIdNew: // IEEE: from class_constructor_declaration SYMP->pushNewUnder($$, nullptr); } | packageClassScopeNoId yNEW__PAREN { $$ = new AstFunc($2, "new", nullptr, nullptr); - $$->packagep($1); + $$->classOrPackagep($1); $$->isConstructor(true); SYMP->pushNewUnderNodeOrCurrent($$, $1); } ; @@ -3935,7 +3973,7 @@ fIdScoped: // IEEE: part of function_body_declaration/task_body_declarat { $$ = $1; $$ = $1; $$ = new AstFunc($$, *$2, nullptr, nullptr); - $$->packagep($1); } + $$->classOrPackagep($1); } ; tfGuts: @@ -4190,7 +4228,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // IEEE: "... hierarchical_identifier select" see below // // // IEEE: empty_queue (IEEE 1800-2017 empty_unpacked_array_concatenation) - | '{' '}' { $$ = new AstConst($1, AstConst::LogicFalse()); + | '{' '}' { $$ = new AstConst($1, AstConst::BitFalse()); BBUNSUP($1, "Unsupported: empty queues (\"{ }\")"); } // // // IEEE: concatenation/constant_concatenation @@ -4217,7 +4255,9 @@ expr: // IEEE: part of expression/constant_expression/primary // // // IEEE: cast/constant_cast // // expanded from casting_type - | simple_type yP_TICK '(' expr ')' { $$ = new AstCast($1->fileline(), $4, $1); } + | simple_type yP_TICK '(' expr ')' { $$ = new AstCast($1->fileline(), $4, VFlagChildDType{}, $1); } + | yTYPE '(' exprOrDataType ')' yP_TICK '(' expr ')' + { $$ = new AstCast($1, $7, VFlagChildDType(), new AstRefDType($1, AstRefDType::FlagTypeOfExpr(), $3)); } | ySIGNED yP_TICK '(' expr ')' { $$ = new AstSigned($1, $4); } | yUNSIGNED yP_TICK '(' expr ')' { $$ = new AstUnsigned($1, $4); } | ySTRING yP_TICK '(' expr ')' { $$ = new AstCvtPackString($1, $4); } @@ -4247,7 +4287,7 @@ expr: // IEEE: part of expression/constant_expression/primary // // // IEEE: cond_predicate - here to avoid reduce problems // // Note expr includes cond_pattern - | ~l~expr yP_ANDANDAND ~r~expr { $$ = new AstConst($2, AstConst::LogicFalse()); + | ~l~expr yP_ANDANDAND ~r~expr { $$ = new AstConst($2, AstConst::BitFalse()); BBUNSUP($2, "Unsupported: &&& expression"); } // // // IEEE: cond_pattern - here to avoid reduce problems @@ -6266,7 +6306,7 @@ vltItem: { V3Config::addIgnore($1, false, *$3, $5->toUInt(), $7->toUInt()+1); } | vltOffFront yVLT_D_FILE yaSTRING yVLT_D_MATCH yaSTRING { if (($1==V3ErrorCode::I_COVERAGE) || ($1==V3ErrorCode::I_TRACING)) { - $1->v3error("Argument -match only supported for lint_off"<1->v3error("Argument -match only supported for lint_off"); } else { V3Config::addWaiver($1,*$3,*$5); }} @@ -6305,11 +6345,11 @@ vltOffFront: | yVLT_LINT_OFF { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_OFF yVLT_D_MSG idAny { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."<v3error("Unknown Error Code: " << *$3); } + $2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."); } | yVLT_LINT_OFF yVLT_D_RULE idAny { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<v3error("Unknown Error Code: " << *$3); } } ; vltOnFront: @@ -6318,11 +6358,11 @@ vltOnFront: | yVLT_LINT_ON { $$ = V3ErrorCode::I_LINT; } | yVLT_LINT_ON yVLT_D_MSG idAny { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."<v3error("Unknown Error Code: " << *$3); } + $2->v3warn(DEPRECATED, "Deprecated -msg in configuration files, use -rule instead."); } | yVLT_LINT_ON yVLT_D_RULE idAny { $$ = V3ErrorCode((*$3).c_str()); - if ($$ == V3ErrorCode::EC_ERROR) { $1->v3error("Unknown Error Code: "<<*$3<v3error("Unknown Error Code: " << *$3); } } ; vltDModuleE: diff --git a/test_regress/t/t_altera_lpm_mult_noinl.pl b/test_regress/t/t_altera_lpm_mult_noinl.pl new file mode 100755 index 000000000..2eac39a3a --- /dev/null +++ b/test_regress/t/t_altera_lpm_mult_noinl.pl @@ -0,0 +1,22 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt_all => 1); + +top_filename("t/t_altera_lpm.v"); +(my $module = $Self->{name}) =~ s/.*t_altera_//; +$module =~ s/_noinl//; + +compile( + verilator_flags2 => ["--top-module ${module}", "-Oi"] + ); + +ok(1); +1; diff --git a/test_regress/t/t_assoc_method.v b/test_regress/t/t_assoc_method.v index 29c8372e1..684e90c68 100644 --- a/test_regress/t/t_assoc_method.v +++ b/test_regress/t/t_assoc_method.v @@ -67,6 +67,11 @@ module t (/*AUTOARG*/); qi = q.find_last_index with (item == 20); v = $sformatf("%p", qi); `checks(v, "'{}"); + qi = q.find_index with (item.index == 12); + v = $sformatf("%p", qi); `checks(v, "'{'hc} "); + qi = q.find with (item.index == 12); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; diff --git a/test_regress/t/t_castdyn.out b/test_regress/t/t_castdyn.out index 2b0ae4bce..2e5c96249 100644 --- a/test_regress/t/t_castdyn.out +++ b/test_regress/t/t_castdyn.out @@ -2,28 +2,28 @@ : ... In instance t 28 | i = $cast(ao, a); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:32:7: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:33:7: Unsupported: $cast. Suggest try static cast. : ... In instance t - 32 | $cast(ao, a); + 33 | $cast(ao, a); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:35:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:36:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 35 | i = $cast(ao, 2.1 * 3.7); + 36 | i = $cast(ao, 2.1 * 3.7); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:39:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:40:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 39 | i = $cast(bo, null); + 40 | i = $cast(bo, null); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:45:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:46:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 45 | i = $cast(bao, b); + 46 | i = $cast(bao, b); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:51:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:52:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 51 | i = $cast(bbo, b); + 52 | i = $cast(bbo, b); | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn.v:58:11: Unsupported: $cast. Suggest try static cast. +%Error-UNSUPPORTED: t/t_castdyn.v:59:11: Unsupported: $cast. Suggest try static cast. : ... In instance t - 58 | i = $cast(bao, b); + 59 | i = $cast(bao, b); | ^~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_castdyn.v b/test_regress/t/t_castdyn.v index 123268419..4c8761f96 100644 --- a/test_regress/t/t_castdyn.v +++ b/test_regress/t/t_castdyn.v @@ -28,6 +28,7 @@ module t (/*AUTOARG*/); i = $cast(ao, a); if (i != 1) $stop; if (ao != 1234) $stop; + a = 12345; $cast(ao, a); if (ao != 12345) $stop; diff --git a/test_regress/t/t_castdyn_bad.out b/test_regress/t/t_castdyn_bad.out deleted file mode 100644 index 030a8b1ac..000000000 --- a/test_regress/t/t_castdyn_bad.out +++ /dev/null @@ -1,9 +0,0 @@ -%Error-UNSUPPORTED: t/t_castdyn_bad.v:20:11: Unsupported: $cast. Suggest try static cast. - : ... In instance t - 20 | i = $cast(c, b); - | ^~~~~ -%Error-UNSUPPORTED: t/t_castdyn_bad.v:23:7: Unsupported: $cast. Suggest try static cast. - : ... In instance t - 23 | $cast(c, b); - | ^~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_castdyn_enum.out b/test_regress/t/t_castdyn_enum.out new file mode 100644 index 000000000..893b3046b --- /dev/null +++ b/test_regress/t/t_castdyn_enum.out @@ -0,0 +1,5 @@ +%Error-UNSUPPORTED: t/t_castdyn_enum.v:23:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 23 | i = $cast(en, cyc); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_castdyn_bad.pl b/test_regress/t/t_castdyn_enum.pl similarity index 100% rename from test_regress/t/t_castdyn_bad.pl rename to test_regress/t/t_castdyn_enum.pl diff --git a/test_regress/t/t_castdyn_enum.v b/test_regress/t/t_castdyn_enum.v new file mode 100644 index 000000000..44cf50098 --- /dev/null +++ b/test_regress/t/t_castdyn_enum.v @@ -0,0 +1,54 @@ +// 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 + +typedef enum {TEN=10, + ELEVEN=11, + SIXTEEN=16} enum_t; + +module t (/*AUTOARG*/ + // Inputs + clk + ); + input clk; + + int i; + int cyc; + enum_t en; + + // Test loop + always @ (posedge clk) begin + i = $cast(en, cyc); +`ifdef TEST_VERBOSE + $write("[%0t] cyc==%0d i=%0d en=%0d\n",$time, cyc, i, en); +`endif + cyc <= cyc + 1; + if (cyc == 10) begin + if (i != 1) $stop; + if (en != TEN) $stop; + end + else if (cyc == 11) begin + if (i != 1) $stop; + if (en != ELEVEN) $stop; + end + else if (cyc == 12) begin + if (i != 0) $stop; + if (en != ELEVEN) $stop; + end + else if (cyc == 16) begin + if (i != 1) $stop; + if (en != SIXTEEN) $stop; + end + else if (cyc == 17) begin + if (i != 0) $stop; + if (en != SIXTEEN) $stop; + end + else if (cyc == 99) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule diff --git a/test_regress/t/t_castdyn_run_bad.out b/test_regress/t/t_castdyn_run_bad.out new file mode 100644 index 000000000..bba531f0e --- /dev/null +++ b/test_regress/t/t_castdyn_run_bad.out @@ -0,0 +1,9 @@ +%Error-UNSUPPORTED: t/t_castdyn_run_bad.v:20:11: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 20 | i = $cast(c, b); + | ^~~~~ +%Error-UNSUPPORTED: t/t_castdyn_run_bad.v:23:7: Unsupported: $cast. Suggest try static cast. + : ... In instance t + 23 | $cast(c, b); + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_castdyn_run_bad.pl b/test_regress/t/t_castdyn_run_bad.pl new file mode 100755 index 000000000..2ad4a887d --- /dev/null +++ b/test_regress/t/t_castdyn_run_bad.pl @@ -0,0 +1,23 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +execute( + check_finished => 1, + ) if !$Self->{vlt_all}; + +ok(1); +1; diff --git a/test_regress/t/t_castdyn_bad.v b/test_regress/t/t_castdyn_run_bad.v similarity index 100% rename from test_regress/t/t_castdyn_bad.v rename to test_regress/t/t_castdyn_run_bad.v diff --git a/test_regress/t/t_class_builtin_bad.out b/test_regress/t/t_class_builtin_bad.out new file mode 100644 index 000000000..525420077 --- /dev/null +++ b/test_regress/t/t_class_builtin_bad.out @@ -0,0 +1,9 @@ +%Error: t/t_class_builtin_bad.v:8:17: The 'rand_mode' method is built-in and cannot be overridden (IEEE 1800-2017 18.8) + : ... In instance t + 8 | function int rand_mode(bit onoff); + | ^~~~~~~~~ +%Error: t/t_class_builtin_bad.v:11:17: The 'constraint_mode' method is built-in and cannot be overridden (IEEE 1800-2017 18.9) + : ... In instance t + 11 | function int constraint_mode(bit onoff); + | ^~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_builtin_bad.pl b/test_regress/t/t_class_builtin_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_builtin_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_builtin_bad.v b/test_regress/t/t_class_builtin_bad.v new file mode 100644 index 000000000..54f29e150 --- /dev/null +++ b/test_regress/t/t_class_builtin_bad.v @@ -0,0 +1,20 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls; + function int rand_mode(bit onoff); + return 1; + endfunction + function int constraint_mode(bit onoff); + return 1; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c; + end +endmodule diff --git a/test_regress/t/t_class_extends_rec_bad.out b/test_regress/t/t_class_extends_rec_bad.out new file mode 100644 index 000000000..c5ffe68ce --- /dev/null +++ b/test_regress/t/t_class_extends_rec_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_extends_rec_bad.v:7:31: Attempting to extend class 'RecursiveExtCls' from itself + 7 | class RecursiveExtCls extends RecursiveExtCls; + | ^~~~~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_rec_bad.pl b/test_regress/t/t_class_extends_rec_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_extends_rec_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_rec_bad.v b/test_regress/t/t_class_extends_rec_bad.v new file mode 100644 index 000000000..2470977f8 --- /dev/null +++ b/test_regress/t/t_class_extends_rec_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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class RecursiveExtCls extends RecursiveExtCls; + int i; +endclass + +module t (/*AUTOARG*/); + RecursiveExtCls cls = new; +endmodule diff --git a/test_regress/t/t_class_extends_this.out b/test_regress/t/t_class_extends_this.out deleted file mode 100644 index 87bd383a9..000000000 --- a/test_regress/t/t_class_extends_this.out +++ /dev/null @@ -1,25 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_extends_this.v:22:11: Unsupported: super - 22 | if (super.value != 1) $stop; - | ^~~~~ -%Error: t/t_class_extends_this.v:22:11: Can't find definition of scope/variable: 'super' - 22 | if (super.value != 1) $stop; - | ^~~~~ -%Error-UNSUPPORTED: t/t_class_extends_this.v:23:7: Unsupported: super - 23 | super.test(); - | ^~~~~ -%Error: t/t_class_extends_this.v:23:7: Can't find definition of scope/variable: 'super' - 23 | super.test(); - | ^~~~~ -%Error-UNSUPPORTED: t/t_class_extends_this.v:24:7: Unsupported: super - 24 | super.value = 10; - | ^~~~~ -%Error: t/t_class_extends_this.v:24:7: Can't find definition of scope/variable: 'super' - 24 | super.value = 10; - | ^~~~~ -%Error-UNSUPPORTED: t/t_class_extends_this.v:26:11: Unsupported: super - 26 | if (super.value != 10) $stop; - | ^~~~~ -%Error: t/t_class_extends_this.v:26:11: Can't find definition of scope/variable: 'super' - 26 | if (super.value != 10) $stop; - | ^~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_extends_this.pl b/test_regress/t/t_class_extends_this.pl index 2ad4a887d..aabcde63e 100755 --- a/test_regress/t/t_class_extends_this.pl +++ b/test_regress/t/t_class_extends_this.pl @@ -11,13 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( check_finished => 1, - ) if !$Self->{vlt_all}; + ); ok(1); 1; diff --git a/test_regress/t/t_class_extends_this.v b/test_regress/t/t_class_extends_this.v index 4f72270e9..fb185267d 100644 --- a/test_regress/t/t_class_extends_this.v +++ b/test_regress/t/t_class_extends_this.v @@ -11,20 +11,27 @@ class Base; function void test; if (value != 1) $stop; if (this.value != 1) $stop; + value = 2; + if (value != 2) $stop; + this.value = 3; + if (value != 3) $stop; endfunction endclass class Cls extends Base; - int value = 2; + int value = 20; function void test; - if (value != 2) $stop; - if (this.value != 2) $stop; + if (value != 20) $stop; + if (this.value != 20) $stop; if (super.value != 1) $stop; + super.test(); - super.value = 10; - this.value = 20; - if (super.value != 10) $stop; - if (value != 20) $stop;; + if (this.value != 20) $stop; + + super.value = 9; + this.value = 29; + if (super.value != 9) $stop; + if (value != 29) $stop;; endfunction endclass diff --git a/test_regress/t/t_class_extends_this3.pl b/test_regress/t/t_class_extends_this3.pl new file mode 100755 index 000000000..aabcde63e --- /dev/null +++ b/test_regress/t/t_class_extends_this3.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_extends_this3.v b/test_regress/t/t_class_extends_this3.v new file mode 100644 index 000000000..20a66e469 --- /dev/null +++ b/test_regress/t/t_class_extends_this3.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +typedef class Cls; + +class Base; + int value = 1; + function void testBase; + if (value != 1) $stop; + endfunction +endclass + +class Cls extends Base; + function void testDerived; + if (value != 1) $stop; + endfunction +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c; + c = new; + c.testBase(); + c.testDerived(); + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_extern.v b/test_regress/t/t_class_extern.v index eb15c625b..94a71825f 100644 --- a/test_regress/t/t_class_extern.v +++ b/test_regress/t/t_class_extern.v @@ -5,23 +5,46 @@ // SPDX-License-Identifier: CC0-1.0 class Cls; - extern task extcls(); - extern function int extone(); + int value; + extern function int ext_f_np; + extern function int ext_f_p(); + extern function int ext_f_i(int in); + extern task ext_t_np; + extern task ext_t_p(); + extern task ext_t_i(int in); endclass -function int Cls::extone(); +function int Cls::ext_f_np; return 1; endfunction -task Cls::extcls(); +function int Cls::ext_f_p(); + return value; +endfunction + +function int Cls::ext_f_i(int in); + return in+1; +endfunction + +task Cls::ext_t_np(); $write("*-* All Finished *-*\n"); +endtask +task Cls::ext_t_p(); $finish; endtask +task Cls::ext_t_i(int in); + if (in != 2) $stop; + value = in; +endtask module t (/*AUTOARG*/); initial begin Cls c = new; - if (c.extone() != 1) $stop; - c.extcls(); + c.ext_t_i(2); + c.ext_t_np(); + c.ext_t_p(); + if (c.ext_f_np() != 1) $stop; + if (c.ext_f_p() != 2) $stop; + if (c.ext_f_i(10) != 11) $stop; end endmodule diff --git a/test_regress/t/t_class_local.v b/test_regress/t/t_class_local.v index fb7ff5ae9..0a5b6cf78 100644 --- a/test_regress/t/t_class_local.v +++ b/test_regress/t/t_class_local.v @@ -4,27 +4,68 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -module t (/*AUTOARG*/); - class Cls; typedef enum {A = 10, B = 20, C = 30} en_t; + int m_pub = 1; local int m_loc = 2; protected int m_prot = B; + task f_pub; endtask + local task f_loc; endtask + protected task f_prot; endtask + static task s_pub; endtask + static local task s_loc; endtask + static protected task s_prot; endtask + task check; + Cls o; + if (m_pub != 1) $stop; + if (m_loc != 2) $stop; + if (m_prot != 20) $stop; + f_pub(); // Ok + f_loc(); // Ok + f_prot(); // Ok + s_pub(); // Ok + s_loc(); // Ok + s_prot(); // Ok + Cls::s_pub(); // Ok + Cls::s_loc(); // Ok + Cls::s_prot(); // Ok + endtask endclass +class Ext extends Cls; + task check; + if (m_pub != 1) $stop; + if (m_prot != 20) $stop; + f_pub(); // Ok + f_prot(); // Ok + s_pub(); // Ok + s_prot(); // Ok + Cls::s_pub(); // Ok + Cls::s_prot(); // Ok + endtask +endclass + +module t (/*AUTOARG*/); const Cls mod_c = new; initial begin Cls c; + Ext e; if (c.A != 10) $stop; c = new; - if (c.m_loc != 2) $stop; - c.m_loc = 10; - if (c.m_loc != 10) $stop; - if (c.m_prot != 20) $stop; + e = new; + if (c.m_pub != 1) $stop; // if (mod_c.A != 10) $stop; + // + c.check(); + e.check(); + // + Cls::s_pub(); // Ok + c.s_pub(); // Ok + e.s_pub(); // Ok + // $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_local_bad.out b/test_regress/t/t_class_local_bad.out new file mode 100644 index 000000000..102a251d1 --- /dev/null +++ b/test_regress/t/t_class_local_bad.out @@ -0,0 +1,106 @@ +%Error-ENCAPSULATED: t/t_class_local_bad.v:71:20: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 71 | bad(); if (c.m_loc != 2) $stop; + | ^~~~~ + t/t_class_local_bad.v:71:20: ... Location of definition + 15 | local int m_loc = 2; + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:72:20: 'm_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 72 | bad(); if (c.m_prot != 20) $stop; + | ^~~~~~ + t/t_class_local_bad.v:72:20: ... Location of definition + 16 | protected int m_prot = 3; + | ^~~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:74:20: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 74 | bad(); if (e.m_loc != 2) $stop; + | ^~~~~ + t/t_class_local_bad.v:74:20: ... Location of definition + 15 | local int m_loc = 2; + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:75:20: 'm_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 75 | bad(); if (e.m_prot != 20) $stop; + | ^~~~~~ + t/t_class_local_bad.v:75:20: ... Location of definition + 16 | protected int m_prot = 3; + | ^~~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:77:16: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 77 | bad(); c.f_loc(); + | ^~~~~ + t/t_class_local_bad.v:77:16: ... Location of definition + 18 | local task f_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:78:16: 'f_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 78 | bad(); c.f_prot(); + | ^~~~~~ + t/t_class_local_bad.v:78:16: ... Location of definition + 19 | protected task f_prot; endtask + | ^~~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:80:16: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 80 | bad(); c.s_loc(); + | ^~~~~ + t/t_class_local_bad.v:80:16: ... Location of definition + 21 | static local task s_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:81:16: 's_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 81 | bad(); c.s_prot(); + | ^~~~~~ + t/t_class_local_bad.v:81:16: ... Location of definition + 22 | static protected task s_prot; endtask + | ^~~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:83:19: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 83 | bad(); Cls::s_loc(); + | ^~~~~ + t/t_class_local_bad.v:83:19: ... Location of definition + 21 | static local task s_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:84:19: 's_prot' is hidden as 'protected' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 84 | bad(); Cls::s_prot(); + | ^~~~~~ + t/t_class_local_bad.v:84:19: ... Location of definition + 22 | static protected task s_prot; endtask + | ^~~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:47:18: 'm_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 47 | bad(); if (m_loc != 10) $stop; + | ^~~~~ + t/t_class_local_bad.v:47:18: ... Location of definition + 15 | local int m_loc = 2; + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:50:14: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 50 | bad(); f_loc(); + | ^~~~~ + t/t_class_local_bad.v:50:14: ... Location of definition + 18 | local task f_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:53:16: 'f_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 53 | bad(); o.f_loc(); + | ^~~~~ + t/t_class_local_bad.v:53:16: ... Location of definition + 18 | local task f_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:56:14: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 56 | bad(); s_loc(); + | ^~~~~ + t/t_class_local_bad.v:56:14: ... Location of definition + 21 | static local task s_loc; endtask + | ^~~~~ +%Error-ENCAPSULATED: t/t_class_local_bad.v:59:19: 's_loc' is hidden as 'local' within this context (IEEE 1800-2017 8.18) + : ... In instance t + 59 | bad(); Cls::s_loc(); + | ^~~~~ + t/t_class_local_bad.v:59:19: ... Location of definition + 21 | static local task s_loc; endtask + | ^~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_local_bad.pl b/test_regress/t/t_class_local_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_local_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_local_bad.v b/test_regress/t/t_class_local_bad.v new file mode 100644 index 000000000..636b89f43 --- /dev/null +++ b/test_regress/t/t_class_local_bad.v @@ -0,0 +1,89 @@ +// 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 + +// Let context messages easily know if given line is expected ok or bad +task ok; +endtask +task bad; +endtask + +class Cls; + int m_pub = 1; + local int m_loc = 2; + protected int m_prot = 3; + task f_pub; endtask + local task f_loc; endtask + protected task f_prot; endtask + static task s_pub; endtask + static local task s_loc; endtask + static protected task s_prot; endtask + task check; + Cls o; + ok(); if (m_pub != 1) $stop; + ok(); if (m_loc != 10) $stop; + ok(); if (m_prot != 20) $stop; + ok(); f_pub(); + ok(); f_loc(); + ok(); f_prot(); + ok(); o.f_pub(); + ok(); o.f_loc(); + ok(); o.f_prot(); + ok(); s_pub(); + ok(); s_loc(); + ok(); s_prot(); + ok(); Cls::s_pub(); + ok(); Cls::s_loc(); + ok(); Cls::s_prot(); + endtask +endclass + +class Ext extends Cls; + task check; + Ext o; + ok(); if (m_pub != 1) $stop; + bad(); if (m_loc != 10) $stop; + ok(); if (m_prot != 20) $stop; + ok(); f_pub(); + bad(); f_loc(); + ok(); f_prot(); + ok(); o.f_pub(); + bad(); o.f_loc(); + ok(); o.f_prot(); + ok(); s_pub(); + bad(); s_loc(); + ok(); s_prot(); + ok(); Cls::s_pub(); + bad(); Cls::s_loc(); + ok(); Cls::s_prot(); + endtask +endclass + +module t (/*AUTOARG*/); + initial begin + Cls c; + Ext e; + c = new; + e = new; + ok(); if (c.m_pub != 1) $stop; + bad(); if (c.m_loc != 2) $stop; + bad(); if (c.m_prot != 20) $stop; + ok(); if (e.m_pub != 1) $stop; + bad(); if (e.m_loc != 2) $stop; + bad(); if (e.m_prot != 20) $stop; + ok(); c.f_pub(); + bad(); c.f_loc(); + bad(); c.f_prot(); + ok(); c.s_pub(); + bad(); c.s_loc(); + bad(); c.s_prot(); + ok(); Cls::s_pub(); + bad(); Cls::s_loc(); + bad(); Cls::s_prot(); + // + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_name.v b/test_regress/t/t_class_name.v index 8aa884a73..0be89d598 100644 --- a/test_regress/t/t_class_name.v +++ b/test_regress/t/t_class_name.v @@ -4,30 +4,158 @@ // any use, without warranty, 2020 by Wilson Snyder. // SPDX-License-Identifier: CC0-1.0 -task unit_name; - $write("unit_name = '%m'\n"); -endtask +`ifdef verilator + `define stop $stop +`else + `define stop +`endif +`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0); + +function string unit_name; + return $sformatf("u %m"); +endfunction class Cls; - static task static_name; - $write("static_name = '%m'\n"); - endtask - task nonstatic_name; - $write("nonstatic_name = '%m'\n"); - endtask -endclass : Cls + // We use the same name for all static_name's to check we resolve right + static function string static_name; + return $sformatf("c %m"); + endfunction + // Different for non_statis to make sure likewise + function string c_auto_name; + return $sformatf("c %m"); + endfunction +endclass -module t (/*AUTOARG*/); - initial begin +package P; +class Cls; + static function string static_name; + return $sformatf("p %m"); + endfunction + function string p_auto_name; + return $sformatf("p %m"); + endfunction +endclass +endpackage + +module M; +class Cls; + static function string static_name; + return $sformatf("m %m"); + endfunction + function string m_auto_name; + return $sformatf("m %m"); + endfunction +endclass + S sub(); + function string cls_static_name; + return Cls::static_name(); + endfunction + function string cls_auto_name; Cls c; c = new; - $write("t = '%m'\n"); - unit_name(); - $write("Below results vary with simulator.\n"); - // E.g. '$unit.\Cls::static_name ' - // E.g. '$unit_x.Cls.static_name' - c.static_name(); - c.nonstatic_name(); + return c.m_auto_name(); + endfunction +endmodule + +module S; +class Cls; + static function string static_name; + return $sformatf("ms %m"); + endfunction + function string ms_auto_name; + return $sformatf("ms %m"); + endfunction +endclass + function string cls_static_name; + return Cls::static_name(); + endfunction + function string cls_auto_name; + Cls c; + c = new; + return c.ms_auto_name(); + endfunction +endmodule + +module t (/*AUTOARG*/); + string s; + + M m(); + + function string mod_func_name; + return $sformatf("tmf %m"); + endfunction + + initial begin + Cls c; + P::Cls p; + p = new; + c = new; + + s = mod_func_name(); + `checks(s, "tmf top.t"); + // UNSUP `checks(s, "tmf top.t.mod_func_name"); + + s = unit_name(); + `checks(s, "u top.$unit"); + // UNSUP `checks(s, "u top.$unit.unit_name"); + // Others: "u $unit_????::unit_name + // Others: "u $unit::unit_name + // Others: "u \\package UnitScopePackage_1\ .UnitScopePackage_1.unit_name + + // *** Below results vary with simulator. + + s = Cls::static_name(); + `checks(s, "c top.$unit.Cls"); + // UNSUP `checks(s, "c top.$unit.Cls.static_name"); + // Others: "c $unit_????.Cls.static_name + // Others: "c $unit::\Cls::static_name + // Others: "c Cls.static_name + s = c.c_auto_name(); + `checks(s, "c top.$unit.Cls"); + // UNSUP `checks(s, "c top.$unit.Cls.c_auto_name"); + // Others: "c $unit_????.Cls.c_auto_name + // Others: "c $unit::\Cls::c_auto_name + // Others: "c Cls.c_auto_name + + //UNSUP s = P::Cls::static_name(); + //UNSUP `checks(s, "p top.P.Cls"); + // UNSUP `checks(s, "p top.P.Cls.static_name"); + // Others: "p P.Cls.static_name + // Others: "p P::Cls.static_name + // Others: "p P::\Cls::static_name + // Others: "p \\package P\ .Cls.static_name + + s = p.p_auto_name(); + `checks(s, "p top.P.Cls"); + // UNSUP `checks(s, "p top.P.Cls.p_auto_name"); + // Others: "p P.Cls.p_auto_name + // Others: "p P::Cls.p_auto_name + // Others: "p P::\Cls::p_auto_name + // Others: "p \\package P\ .Cls.p_auto_name + + s = m.cls_static_name(); + `checks(s, "m top.t.m.Cls"); + // UNSUP `checks(s, "m top.t.m.Cls.static_name"); + // Others: "m top.t.m.Cls.static_name + // Others: "m top.t.m.\Cls::static_name + + s = m.cls_auto_name(); + `checks(s, "m top.t.m.Cls"); + // UNSUP `checks(s, "m top.t.m.Cls.m_auto_name"); + // Others: "m top.t.m.Cls.m_auto_name + // Others: "m top.t.m.\Cls::m_auto_name + + s = m.sub.cls_static_name(); + `checks(s, "ms top.t.m.sub.Cls"); + // UNSUP `checks(s, "ms top.t.m.sub.Cls.static_name"); + // Others: "ms top.t.m.sub.Cls.static_name + // Others: "ms top.t.m.sub.\Cls::static_name + s = m.sub.cls_auto_name(); + `checks(s, "ms top.t.m.sub.Cls"); + // UNSUP `checks(s, "ms top.t.m.sub.Cls.ms_auto_name"); + // Others: "ms top.t.m.sub.Cls.ms_auto_name + // Others: "ms top.t.m.sub.\Cls::ms_auto_name + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_new.v b/test_regress/t/t_class_new.v index f8642e6cf..811693dc5 100644 --- a/test_regress/t/t_class_new.v +++ b/test_regress/t/t_class_new.v @@ -19,6 +19,11 @@ class ClsArg; function int geta; return imembera; endfunction + static function ClsArg create6; + ClsArg obj; + obj = new(6 - 1); + return obj; + endfunction endclass module t (/*AUTOARG*/); @@ -29,10 +34,14 @@ module t (/*AUTOARG*/); c1 = new; if (c1.imembera != 5) $stop; - c2 = new(2); + c2 = new(3 - 1); if (c2.imembera != 3) $stop; if (c2.geta() != 3) $stop; + c2 = ClsArg::create6(); + if (c2.imembera != 6) $stop; + if (c2.geta() != 6) $stop; + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_param_bad.out b/test_regress/t/t_class_param_bad.out new file mode 100644 index 000000000..d7a071bf0 --- /dev/null +++ b/test_regress/t/t_class_param_bad.out @@ -0,0 +1,17 @@ +%Error-UNSUPPORTED: t/t_class_param_bad.v:12:4: Unsupported: parameterized packages + 12 | Cls #(.PARAMBAD(1)) c; + | ^~~ +%Error: t/t_class_param_bad.v:12:11: Parameter pin not found: 'PARAMBAD' + : ... Suggested alternative: 'PARAMB' + 12 | Cls #(.PARAMBAD(1)) c; + | ^~~~~~~~ +%Error-UNSUPPORTED: t/t_class_param_bad.v:13:4: Unsupported: parameterized packages + 13 | Cls #(13, 1) cd; + | ^~~ +%Error: t/t_class_param_bad.v:13:14: Parameter pin not found: '__paramNumber2' + 13 | Cls #(13, 1) cd; + | ^ +%Error-UNSUPPORTED: t/t_class_param_bad.v:7:23: Unsupported: class parameter + 7 | class Cls #(parameter PARAMB = 12); + | ^~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_param_bad.pl b/test_regress/t/t_class_param_bad.pl new file mode 100755 index 000000000..7be596e0f --- /dev/null +++ b/test_regress/t/t_class_param_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_param_bad.v b/test_regress/t/t_class_param_bad.v new file mode 100644 index 000000000..ba12815f1 --- /dev/null +++ b/test_regress/t/t_class_param_bad.v @@ -0,0 +1,15 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class Cls #(parameter PARAMB = 12); +endclass + +module t (/*AUTOARG*/); + + Cls #(.PARAMBAD(1)) c; // Bad param name + Cls #(13, 1) cd; // Bad param number + +endmodule diff --git a/test_regress/t/t_class_static_method.v b/test_regress/t/t_class_static_method.v index 1d408aaef..5b518afb3 100644 --- a/test_regress/t/t_class_static_method.v +++ b/test_regress/t/t_class_static_method.v @@ -16,17 +16,34 @@ class Cls; if (x != 23) $stop; return 42; endfunction - endclass : Cls +class OCls; + int i; + static function OCls create(); + OCls o = new; + o.i = 42; + return o; + endfunction + static task test_obj(OCls o); + if (o.i != 42) $stop; + endtask +endclass + module t (/*AUTOARG*/); initial begin int x; + OCls oc; + Cls::static_task(16); x = Cls::static_function(23); $write("Static function result: %d\n", x); if (x != 42) $stop; + + oc = OCls::create(); + OCls::test_obj(oc); + $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_class_super_bad.out b/test_regress/t/t_class_super_bad.out new file mode 100644 index 000000000..9927708ff --- /dev/null +++ b/test_regress/t/t_class_super_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_super_bad.v:15:12: 'super' used outside class (IEEE 1800-2017 8.15) + 15 | super.addr = 2; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_super_bad.pl b/test_regress/t/t_class_super_bad.pl new file mode 100755 index 000000000..45af9e7a6 --- /dev/null +++ b/test_regress/t/t_class_super_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_super_bad.v b/test_regress/t/t_class_super_bad.v new file mode 100644 index 000000000..20a229969 --- /dev/null +++ b/test_regress/t/t_class_super_bad.v @@ -0,0 +1,19 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Rafal Kapuscik +// SPDX-License-Identifier: CC0-1.0 +// + +module t(/*AUTOARG*/ + // Inputs + clk + ); + input clk; + bit [3:0] addr; + initial begin + super.addr = 2; + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_class_super_bad2.out b/test_regress/t/t_class_super_bad2.out new file mode 100644 index 000000000..b3b195c17 --- /dev/null +++ b/test_regress/t/t_class_super_bad2.out @@ -0,0 +1,4 @@ +%Error: t/t_class_super_bad2.v:10:12: 'super' used on non-extended class (IEEE 1800-2017 8.15) + 10 | super.i = 1; + | ^ +%Error: Exiting due to diff --git a/test_regress/t/t_class_super_bad2.pl b/test_regress/t/t_class_super_bad2.pl new file mode 100755 index 000000000..45af9e7a6 --- /dev/null +++ b/test_regress/t/t_class_super_bad2.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +compile( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_super_bad2.v b/test_regress/t/t_class_super_bad2.v new file mode 100644 index 000000000..ba31d657b --- /dev/null +++ b/test_regress/t/t_class_super_bad2.v @@ -0,0 +1,12 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Rafal Kapuscik +// SPDX-License-Identifier: CC0-1.0 +// + +class Cls; + task t; + super.i = 1; // Bad - no extends + endtask +endclass diff --git a/test_regress/t/t_class_uses_this.v b/test_regress/t/t_class_uses_this.v index d1a30b01a..531c6e1cb 100644 --- a/test_regress/t/t_class_uses_this.v +++ b/test_regress/t/t_class_uses_this.v @@ -4,31 +4,39 @@ // any use, without warranty, 2020 Rafal Kapuscik // SPDX-License-Identifier: CC0-1.0 // -class foo; +class Cls; bit [3:0] addr; - function void set (bit [3:0] addr); + function void set(bit [3:0] addr); begin : body this.addr = addr; end : body endfunction + extern function void setext(bit [3:0] addr); endclass +function void Cls::setext(bit [3:0] addr); + this.addr = addr; +endfunction + module t(/*AUTOARG*/ // Inputs clk ); input clk; - foo bar; - foo baz; + Cls bar; + Cls baz; initial begin - bar = new(); - baz = new(); - bar.set(4); + bar = new(); + baz = new(); + bar.set(4); `ifdef TEST_VERBOSE - $display(bar.addr); - $display(baz.addr); + $display(bar.addr); + $display(baz.addr); `endif - $write("*-* All Finished *-*\n"); - $finish; + if (bar.addr != 4) $stop; + bar.setext(2); + if (bar.addr != 2) $stop; + $write("*-* All Finished *-*\n"); + $finish; end endmodule diff --git a/test_regress/t/t_class_uses_this_bad.out b/test_regress/t/t_class_uses_this_bad.out index 05075f46a..0b2fd0a3c 100644 --- a/test_regress/t/t_class_uses_this_bad.out +++ b/test_regress/t/t_class_uses_this_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_class_uses_this_bad.v:15:12: 'this' used outside class +%Error: t/t_class_uses_this_bad.v:15:12: 'this' used outside class (IEEE 1800-2017 8.11) 15 | this.addr = 2; | ^ %Error: Exiting due to diff --git a/test_regress/t/t_class_virtual_pure.out b/test_regress/t/t_class_virtual_pure.out deleted file mode 100644 index ec7ef63ac..000000000 --- a/test_regress/t/t_class_virtual_pure.out +++ /dev/null @@ -1,7 +0,0 @@ -%Error-UNSUPPORTED: t/t_class_virtual_pure.v:8:22: Unsupported: 'virtual' class method - 8 | pure virtual task hello(); - | ^~~~~ -%Error-UNSUPPORTED: t/t_class_virtual_pure.v:7:9: Unsupported: virtual class - 7 | virtual class VC; - | ^~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_class_virtual_pure_bad.out b/test_regress/t/t_class_virtual_pure_bad.out new file mode 100644 index 000000000..067482f2b --- /dev/null +++ b/test_regress/t/t_class_virtual_pure_bad.out @@ -0,0 +1,4 @@ +%Error: t/t_class_virtual_pure_bad.v:8:22: Illegal to have 'pure virtual' in non-virtual class (IEEE 1800-2017 8.21) + 8 | pure virtual task pure_task; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_class_virtual_pure_bad.pl b/test_regress/t/t_class_virtual_pure_bad.pl new file mode 100755 index 000000000..009248fc5 --- /dev/null +++ b/test_regress/t/t_class_virtual_pure_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_class_virtual_pure_bad.v b/test_regress/t/t_class_virtual_pure_bad.v new file mode 100644 index 000000000..7b3754db3 --- /dev/null +++ b/test_regress/t/t_class_virtual_pure_bad.v @@ -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, 2019 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +class VBase; + pure virtual task pure_task; +endclass diff --git a/test_regress/t/t_class_vparam.out b/test_regress/t/t_class_vparam.out index c5a35f922..1816089b8 100644 --- a/test_regress/t/t_class_vparam.out +++ b/test_regress/t/t_class_vparam.out @@ -1,4 +1,7 @@ %Error-UNSUPPORTED: t/t_class_vparam.v:13:40: Unsupported: parameterized packages 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); | ^~~~~~~~~~~~~~~ +%Error: t/t_class_vparam.v:13:58: Parameter pin not found: '__paramNumber1' + 13 | pure virtual function void funcname(paramed_class_t #(CTYPE_t) v); + | ^~~~~~~ %Error: Exiting due to diff --git a/test_regress/t/t_clk_2in.cpp b/test_regress/t/t_clk_2in.cpp index ba601f846..fc5a0233f 100644 --- a/test_regress/t/t_clk_2in.cpp +++ b/test_regress/t/t_clk_2in.cpp @@ -50,4 +50,7 @@ int main(int argc, char* argv[]) { } topp->check = 1; clockit(0, 0); + + topp->final(); + VL_DO_DANGLING(delete topp, topp); } diff --git a/test_regress/t/t_clocker.pl b/test_regress/t/t_clocker.pl index 1af79252d..46b824b58 100755 --- a/test_regress/t/t_clocker.pl +++ b/test_regress/t/t_clocker.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - verilator_flags2 => ["--trace"] + verilator_flags2 => ["--trace", "-Wno-CLKDATA"] ); execute( diff --git a/test_regress/t/t_clocker.v b/test_regress/t/t_clocker.v index 7a4bdca32..1694ae894 100644 --- a/test_regress/t/t_clocker.v +++ b/test_regress/t/t_clocker.v @@ -18,6 +18,7 @@ module t (/*AUTOARG*/ ); input clk; output reg res; + // When not inlining the below may trigger CLKDATA output reg [7:0] res8; output reg [15:0] res16; @@ -41,23 +42,19 @@ module t (/*AUTOARG*/ // the following two assignment triggers the CLKDATA warning // because on LHS there are a mix of signals both CLOCK and // DATA - /* verilator lint_off CLKDATA */ assign res8 = {clk_3, 1'b0, clk_4}; assign res16 = {count, clk_3, clk_1, clk_4}; - /* verilator lint_on CLKDATA */ initial - count = 0; + count = 0; always @(posedge clk_final or negedge clk_final) begin - count = count + 1; - // the following assignment should trigger the CLKDATA warning - // because CLOCK signal is used as DATA in sequential block - /* verilator lint_off CLKDATA */ - res <= clk_final; - /* verilator lint_on CLKDATA */ + count = count + 1; + // the following assignment should trigger the CLKDATA warning + // because CLOCK signal is used as DATA in sequential block + res <= clk_final; if ( count == 8'hf) begin $write("*-* All Finished *-*\n"); $finish; diff --git a/test_regress/t/t_clocker_bad.out b/test_regress/t/t_clocker_bad.out new file mode 100644 index 000000000..eb3477c3c --- /dev/null +++ b/test_regress/t/t_clocker_bad.out @@ -0,0 +1,11 @@ +%Warning-CLKDATA: t/t_clocker.v:45:17: Clock is assigned to part of data signal 'res8' + 45 | assign res8 = {clk_3, 1'b0, clk_4}; + | ^ + ... Use "/* verilator lint_off CLKDATA */" and lint_on around source to disable this message. +%Warning-CLKDATA: t/t_clocker.v:46:17: Clock is assigned to part of data signal 'res16' + 46 | assign res16 = {count, clk_3, clk_1, clk_4}; + | ^ +%Warning-CLKDATA: t/t_clocker.v:57:14: Clock used as data (on rhs of assignment) in sequential block 'clk' + 57 | res <= clk_final; + | ^~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_clocker_bad.pl b/test_regress/t/t_clocker_bad.pl new file mode 100755 index 000000000..0628b9d18 --- /dev/null +++ b/test_regress/t/t_clocker_bad.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2004 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +top_filename("t/t_clocker.v"); + +lint( + fails => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_debug_emitv.out b/test_regress/t/t_debug_emitv.out index 72286aad6..dc1d81c5a 100644 --- a/test_regress/t/t_debug_emitv.out +++ b/test_regress/t/t_debug_emitv.out @@ -175,6 +175,9 @@ module Vt_debug_emitv; if ((32'sh5 != t.i)) begin $stop; end + t.sum = + ???? // RAND + 32'sha; end /*verilator public_flat_rw @(posedge clk)@(negedge clk) t.pubflat*/ diff --git a/test_regress/t/t_debug_emitv.pl b/test_regress/t/t_debug_emitv.pl index 3532795bc..06a25f291 100755 --- a/test_regress/t/t_debug_emitv.pl +++ b/test_regress/t/t_debug_emitv.pl @@ -13,7 +13,7 @@ scenarios(vlt => 1); lint( # We also have dump-tree turned on, so hit a lot of AstNode*::dump() functions # Likewise XML - v_flags => ["--lint-only --dump-treei 9 --debug-emitv"], + v_flags => ["--lint-only --dump-treei 9 --dump-treei-V3EmitV 9 --debug-emitv"], ); files_identical("$Self->{obj_dir}/$Self->{VM_PREFIX}__preorder.v", $Self->{golden_filename}); diff --git a/test_regress/t/t_debug_emitv.v b/test_regress/t/t_debug_emitv.v index d1ae29ee0..5764cedcf 100644 --- a/test_regress/t/t_debug_emitv.v +++ b/test_regress/t/t_debug_emitv.v @@ -25,9 +25,13 @@ module t (/*AUTOARG*/ typedef struct { logic signed [2:0] a; } us_t; + typedef union { + logic a; + } union_t; const ps_t ps[3]; us_t us; + union_t unu; int array[3]; initial array = '{1,2,3}; @@ -140,6 +144,11 @@ module t (/*AUTOARG*/ $display("%% [%t] [%t] to=%o td=%d", $time, $realtime, $time, $time); $sscanf("foo=5", "foo=%d", i); if (i != 5) $stop; + + sum = $random; + sum = $random(10); + sum = $urandom; + sum = $urandom(10); end endmodule @@ -151,4 +160,30 @@ module sub(); if (v == 0) return 33; return {31'd0, v[2]} + 32'd1; endfunction + real r; + initial begin + r = 1.0; + r = $log10(r); + r = $ln(r); + r = $exp(r); + r = $sqrt(r); + r = $floor(r); + r = $ceil(r); + r = $sin(r); + r = $cos(r); + r = $tan(r); + r = $asin(r); + r = $acos(r); + r = $atan(r); + r = $sinh(r); + r = $cosh(r); + r = $tanh(r); + r = $asinh(r); + r = $acosh(r); + r = $atanh(r); + end endmodule + +package p; + logic pkgvar; +endpackage diff --git a/test_regress/t/t_dist_portability.pl b/test_regress/t/t_dist_portability.pl index 5b6a8e037..78c4d6279 100755 --- a/test_regress/t/t_dist_portability.pl +++ b/test_regress/t/t_dist_portability.pl @@ -22,6 +22,7 @@ if (!-r "$root/.git") { printfll(); cstr(); vsnprintf(); + final(); } ok(1); @@ -30,7 +31,7 @@ sub uint { ### Must trim output before and after our file list #my $files = "*/*.c* */*.h test_regress/t/*.c* test_regress/t/*.h"; # src isn't clean, and probably doesn't need to be (yet?) - my $files = "include/*.c* include/*.h test_c/*.c* test_regress/t/*.c* test_regress/t/*.h"; + my $files = "include/*.c* include/*.h examples/*/*.c* test_regress/t/*.c* test_regress/t/*.h"; my $cmd = "cd $root && fgrep -n int $files | sort"; print "C $cmd\n"; my $grep = `$cmd`; @@ -52,7 +53,7 @@ sub uint { } sub printfll { - my $files = "src/*.c* src/*.h include/*.c* include/*.h test_c/*.c* test_regress/t/*.c* test_regress/t/*.h"; + my $files = "src/*.c* src/*.h include/*.c* include/*.h examples/*/*.c* test_regress/t/*.c* test_regress/t/*.h"; my $cmd = "cd $root && fgrep -n ll $files | sort"; print "C $cmd\n"; my $grep = `$cmd`; @@ -73,7 +74,7 @@ sub printfll { } sub cstr { - my $files = "src/*.c* src/*.h include/*.c* include/*.h test_c/*.c* test_regress/t/*.c* test_regress/t/*.h"; + my $files = "src/*.c* src/*.h include/*.c* include/*.h examples/*/*.c* test_regress/t/*.c* test_regress/t/*.h"; my $cmd = "cd $root && grep -n -P 'c_str|begin|end' $files | sort"; print "C $cmd\n"; my $grep = `$cmd`; @@ -92,7 +93,7 @@ sub cstr { sub vsnprintf { # 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 test_c/*.c*"; + my $files = "src/*.c* src/*.h include/*.c* include/*.h examples/*/*.c*"; my $cmd = "cd $root && grep -n -P '(snprintf|vsnprintf)' $files | sort"; print "C $cmd\n"; my $grep = `$cmd`; @@ -109,4 +110,25 @@ 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"; + print "C $cmd\n"; + my $grep = `$cmd`; + my %names; + foreach my $line (split /\n/, $grep) { + if ($line =~ /:\s*class /) { + next if $line =~ /final|VL_NOT_FINAL/; + next if $line =~ /{}/; # e.g. 'class Foo {};' + next if $line =~ /;/; # e.g. 'class Foo;' + print "$line\n"; + $names{$1} = 1; + } + } + if (keys %names) { + error("Files with classes without final/VL_NOT_FINAL: ",join(' ',sort keys %names)); + } +} + 1; diff --git a/test_regress/t/t_dpi_accessors.cpp b/test_regress/t/t_dpi_accessors.cpp index e3f227ab1..c20c81745 100644 --- a/test_regress/t/t_dpi_accessors.cpp +++ b/test_regress/t/t_dpi_accessors.cpp @@ -69,8 +69,8 @@ int main() { dut->eval(); #ifdef TEST_VERBOSE - cout << "Initial DPI values" << endl; - cout << "==================" << endl; + cout << "Initial DPI values\n"; + cout << "==================\n"; #endif int a = (int)a_read(); @@ -106,8 +106,8 @@ int main() { // Check we can read a scalar register. #ifdef TEST_VERBOSE - cout << "Test of scalar register reading" << endl; - cout << "===============================" << endl; + cout << "Test of scalar register reading\n"; + cout << "===============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -132,8 +132,8 @@ int main() { // Check we can read a vector register. #ifdef TEST_VERBOSE - cout << "Test of vector register reading" << endl; - cout << "===============================" << endl; + cout << "Test of vector register reading\n"; + cout << "===============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -156,8 +156,8 @@ int main() { // Test we can read an array element #ifdef TEST_VERBOSE cout << endl; - cout << "Test of array element reading" << endl; - cout << "=============================" << endl; + cout << "Test of array element reading\n"; + cout << "=============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -180,8 +180,8 @@ int main() { // Check we can read a scalar wire #ifdef TEST_VERBOSE cout << endl; - cout << "Test of scalar wire reading" << endl; - cout << "===========================" << endl; + cout << "Test of scalar wire reading\n"; + cout << "===========================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -209,8 +209,8 @@ int main() { // Check we can read a vector wire #ifdef TEST_VERBOSE cout << endl; - cout << "Test of vector wire reading" << endl; - cout << "===========================" << endl; + cout << "Test of vector wire reading\n"; + cout << "===========================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -239,8 +239,8 @@ int main() { // Check we can write a scalar register #ifdef TEST_VERBOSE cout << endl; - cout << "Test of scalar register writing" << endl; - cout << "===============================" << endl; + cout << "Test of scalar register writing\n"; + cout << "===============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -268,8 +268,8 @@ int main() { // Check we can write a vector register #ifdef TEST_VERBOSE cout << endl; - cout << "Test of vector register writing" << endl; - cout << "===============================" << endl; + cout << "Test of vector register writing\n"; + cout << "===============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -297,8 +297,8 @@ int main() { // Test we can write an array element #ifdef TEST_VERBOSE cout << endl; - cout << "Test of array element writing" << endl; - cout << "=============================" << endl; + cout << "Test of array element writing\n"; + cout << "=============================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -326,8 +326,8 @@ int main() { // Check we can read a vector register slice #ifdef TEST_VERBOSE cout << endl; - cout << "Test of vector register slice reading" << endl; - cout << "=====================================" << endl; + cout << "Test of vector register slice reading\n"; + cout << "=====================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -353,8 +353,8 @@ int main() { // Test we can read an array element slice #ifdef TEST_VERBOSE cout << endl; - cout << "Test of array element slice reading" << endl; - cout << "===================================" << endl; + cout << "Test of array element slice reading\n"; + cout << "===================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -382,8 +382,8 @@ int main() { // Check we can read a vector wire slice #ifdef TEST_VERBOSE cout << endl; - cout << "Test of vector wire slice reading" << endl; - cout << "=================================" << endl; + cout << "Test of vector wire slice reading\n"; + cout << "=================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -413,8 +413,8 @@ int main() { // Check we can write a vector register slice #ifdef TEST_VERBOSE cout << endl; - cout << "Test of vector register slice writing" << endl; - cout << "=====================================" << endl; + cout << "Test of vector register slice writing\n"; + cout << "=====================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -452,8 +452,8 @@ int main() { // Test we can write an array element slice #ifdef TEST_VERBOSE cout << endl; - cout << "Test of array element slice writing" << endl; - cout << "===================================" << endl; + cout << "Test of array element slice writing\n"; + cout << "===================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -497,8 +497,8 @@ int main() { // Check we can read complex registers #ifdef TEST_VERBOSE cout << endl; - cout << "Test of complex register reading" << endl; - cout << "================================" << endl; + cout << "Test of complex register reading\n"; + cout << "================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -577,8 +577,8 @@ int main() { // Test we can write a complex register #ifdef TEST_VERBOSE cout << endl; - cout << "Test of complex register writing" << endl; - cout << "================================" << endl; + cout << "Test of complex register writing\n"; + cout << "================================\n"; #endif for (int i = 0; !Verilated::gotFinish() && (i < 4); i++) { @@ -673,7 +673,8 @@ int main() { // Tidy up dut->final(); - cout << "*-* All Finished *-*" << endl; + VL_DO_DANGLING(delete dut, dut); + cout << "*-* All Finished *-*\n"; } // Local Variables: diff --git a/test_regress/t/t_dpi_arg_inout_unpack.cpp b/test_regress/t/t_dpi_arg_inout_unpack.cpp new file mode 100644 index 000000000..9b029bfbd --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_unpack.cpp @@ -0,0 +1,860 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Yutetsu TAKATSUKASA. 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 +#include +#include +#include +#include + +// clang-format off +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_inout_unpack__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +# define NO_UNPACK_STRUCT +# define CONSTARG const +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define CONSTARG const +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +// Sadly NC does not declare pass-by reference input arguments as const +# define CONSTARG +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +# define CONSTARG const +#else +# error "Unknown simulator for DPI test" +#endif +// clang-format on + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +namespace { // unnamed namespace + +const bool VERBOSE_MESSAGE = false; + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void set_uint(svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselLogic(v0, i, (val >> i) & 1); + else + svPutBitselLogic(v0, i, 0); + } +} + +void set_uint(svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselBit(v0, i, (val >> i) & 1); + else + svPutBitselBit(v0, i, 0); + } +} + +template bool compare(const T& act, const T& exp) { + if (exp == act) { + if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + return true; + } else { + std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; + return false; + } +} + +bool compare(const svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselLogic(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +bool compare(const svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselBit(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +template bool update_0d(T* v) { + if (!compare(*v, 42)) return false; + ++(*v); + return true; +} + +template bool update_1d(T* v) { + if (!compare(v[0], 43)) return false; + if (!compare(v[1], 44)) return false; + ++v[0]; + ++v[1]; + return true; +} + +template bool update_2d(T* v) { + if (!compare(v[0 * 2 + 1], 45)) return false; + if (!compare(v[1 * 2 + 1], 46)) return false; + if (!compare(v[2 * 2 + 1], 47)) return false; + ++v[0 * 2 + 1]; + ++v[1 * 2 + 1]; + ++v[2 * 2 + 1]; + return true; +} + +template bool update_3d(T* v) { + if (!compare(v[(0 * 3 + 0) * 2 + 0], 48)) return false; + if (!compare(v[(1 * 3 + 0) * 2 + 0], 49)) return false; + if (!compare(v[(2 * 3 + 0) * 2 + 0], 50)) return false; + if (!compare(v[(3 * 3 + 0) * 2 + 0], 51)) return false; + ++v[(0 * 3 + 0) * 2 + 0]; + ++v[(1 * 3 + 0) * 2 + 0]; + ++v[(2 * 3 + 0) * 2 + 0]; + ++v[(3 * 3 + 0) * 2 + 0]; + return true; +} + +template bool update_0d(T* v, int bitwidth) { + if (!compare(v, 42, bitwidth)) return false; + set_uint(v, 43, bitwidth); + return true; +} +template bool update_1d(T* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + if (!compare(v + unit * 0, 43, bitwidth)) return false; + if (!compare(v + unit * 1, 44, bitwidth)) return false; + set_uint(v + unit * 0, 44, bitwidth); + set_uint(v + unit * 1, 45, bitwidth); + return true; +} +template bool update_2d(T* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + if (!compare(v + unit * (0 * 2 + 1), 45, bitwidth)) return false; + if (!compare(v + unit * (1 * 2 + 1), 46, bitwidth)) return false; + if (!compare(v + unit * (2 * 2 + 1), 47, bitwidth)) return false; + set_uint(v + unit * (0 * 2 + 1), 46, bitwidth); + set_uint(v + unit * (1 * 2 + 1), 47, bitwidth); + set_uint(v + unit * (2 * 2 + 1), 48, bitwidth); + return true; +} +template bool update_3d(T* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + if (!compare(v + unit * ((0 * 3 + 0) * 2 + 0), 48, bitwidth)) return false; + if (!compare(v + unit * ((1 * 3 + 0) * 2 + 0), 49, bitwidth)) return false; + if (!compare(v + unit * ((2 * 3 + 0) * 2 + 0), 50, bitwidth)) return false; + if (!compare(v + unit * ((3 * 3 + 0) * 2 + 0), 51, bitwidth)) return false; + set_uint(v + unit * ((0 * 3 + 0) * 2 + 0), 49, bitwidth); + set_uint(v + unit * ((1 * 3 + 0) * 2 + 0), 50, bitwidth); + set_uint(v + unit * ((2 * 3 + 0) * 2 + 0), 51, bitwidth); + set_uint(v + unit * ((3 * 3 + 0) * 2 + 0), 52, bitwidth); + return true; +} + +template void set_values(T (&v)[4][3][2]) { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) v[i][j][k] = 0; + v[3][2][1] = 42; + v[2][1][0] = 43; + v[2][1][1] = 44; + v[1][0][1] = 45; + v[1][1][1] = 46; + v[1][2][1] = 47; + v[0][0][0] = 48; + v[1][0][0] = 49; + v[2][0][0] = 50; + v[3][0][0] = 51; +} + +template void set_values(T (&v)[4][3][2][N], int bitwidth) { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) set_uint(v[i][j][k], 0, bitwidth); + set_uint(v[3][2][1], 42, bitwidth); + set_uint(v[2][1][0], 43, bitwidth); + set_uint(v[2][1][1], 44, bitwidth); + set_uint(v[1][0][1], 45, bitwidth); + set_uint(v[1][1][1], 46, bitwidth); + set_uint(v[1][2][1], 47, bitwidth); + set_uint(v[0][0][0], 48, bitwidth); + set_uint(v[1][0][0], 49, bitwidth); + set_uint(v[2][0][0], 50, bitwidth); + set_uint(v[3][0][0], 51, bitwidth); +} + +template bool check_0d(T v) { return compare(v, 43); } +template bool check_1d(const T (&v)[2]) { + return compare(v[0], 44) && compare(v[1], 45); +} +template bool check_2d(const T (&v)[3][2]) { + return compare(v[0][1], 46) && compare(v[1][1], 47) && compare(v[2][1], 48); +} +template bool check_3d(const T (&v)[4][3][2]) { + return compare(v[0][0][0], 49) && compare(v[1][0][0], 50) && compare(v[2][0][0], 51) + && compare(v[3][0][0], 52); +} + +template bool check_0d(const T (&v)[N], unsigned int bitwidth) { + return compare(v, 43, bitwidth); +} +template bool check_1d(const T (&v)[2][N], unsigned int bitwidth) { + return compare(v[0], 44, bitwidth) && compare(v[1], 45, bitwidth); +} +template bool check_2d(const T (&v)[3][2][N], unsigned int bitwidth) { + return compare(v[0][1], 46, bitwidth) && compare(v[1][1], 47, bitwidth) + && compare(v[2][1], 48, bitwidth); +} +template bool check_3d(const T (&v)[4][3][2][N], unsigned int bitwidth) { + return compare(v[0][0][0], 49, bitwidth) && compare(v[1][0][0], 50, bitwidth) + && compare(v[2][0][0], 51, bitwidth) && compare(v[3][0][0], 52, bitwidth); +} + +} // unnamed namespace + +void* get_non_null() { + static int v; + return &v; +} + +void i_byte_0d(char* v) { + if (!update_0d(v)) stop(); +} +void i_byte_1d(char* v) { + if (!update_1d(v)) stop(); +} +void i_byte_2d(char* v) { + if (!update_2d(v)) stop(); +} +void i_byte_3d(char* v) { + if (!update_3d(v)) stop(); +} + +void i_byte_unsigned_0d(unsigned char* v) { + if (!update_0d(v)) stop(); +} +void i_byte_unsigned_1d(unsigned char* v) { + if (!update_1d(v)) stop(); +} +void i_byte_unsigned_2d(unsigned char* v) { + if (!update_2d(v)) stop(); +} +void i_byte_unsigned_3d(unsigned char* v) { + if (!update_3d(v)) stop(); +} + +void i_shortint_0d(short* v) { + if (!update_0d(v)) stop(); +} +void i_shortint_1d(short* v) { + if (!update_1d(v)) stop(); +} +void i_shortint_2d(short* v) { + if (!update_2d(v)) stop(); +} +void i_shortint_3d(short* v) { + if (!update_3d(v)) stop(); +} + +void i_shortint_unsigned_0d(unsigned short* v) { + if (!update_0d(v)) stop(); +} +void i_shortint_unsigned_1d(unsigned short* v) { + if (!update_1d(v)) stop(); +} +void i_shortint_unsigned_2d(unsigned short* v) { + if (!update_2d(v)) stop(); +} +void i_shortint_unsigned_3d(unsigned short* v) { + if (!update_3d(v)) stop(); +} + +void i_int_0d(int* v) { + if (!update_0d(v)) stop(); +} +void i_int_1d(int* v) { + if (!update_1d(v)) stop(); +} +void i_int_2d(int* v) { + if (!update_2d(v)) stop(); +} +void i_int_3d(int* v) { + if (!update_3d(v)) stop(); +} + +void i_int_unsigned_0d(unsigned int* v) { + if (!update_0d(v)) stop(); +} +void i_int_unsigned_1d(unsigned int* v) { + if (!update_1d(v)) stop(); +} +void i_int_unsigned_2d(unsigned int* v) { + if (!update_2d(v)) stop(); +} +void i_int_unsigned_3d(unsigned int* v) { + if (!update_3d(v)) stop(); +} + +void i_longint_0d(sv_longint_t* v) { + if (!update_0d(v)) stop(); +} +void i_longint_1d(sv_longint_t* v) { + if (!update_1d(v)) stop(); +} +void i_longint_2d(sv_longint_t* v) { + if (!update_2d(v)) stop(); +} +void i_longint_3d(sv_longint_t* v) { + if (!update_3d(v)) stop(); +} + +void i_longint_unsigned_0d(sv_longint_unsigned_t* v) { + if (!update_0d(v)) stop(); +} +void i_longint_unsigned_1d(sv_longint_unsigned_t* v) { + if (!update_1d(v)) stop(); +} +void i_longint_unsigned_2d(sv_longint_unsigned_t* v) { + if (!update_2d(v)) stop(); +} +void i_longint_unsigned_3d(sv_longint_unsigned_t* v) { + if (!update_3d(v)) stop(); +} + +#ifndef NO_TIME +void i_time_0d(svLogicVecVal* v) { + if (!update_0d(v, 64)) stop(); +} +void i_time_1d(svLogicVecVal* v) { + if (!update_1d(v, 64)) stop(); +} +void i_time_2d(svLogicVecVal* v) { + if (!update_2d(v, 64)) stop(); +} +void i_time_3d(svLogicVecVal* v) { + if (!update_3d(v, 64)) stop(); +} +#endif + +#ifndef NO_INTEGER +void i_integer_0d(svLogicVecVal* v) { + if (!update_0d(v, 32)) stop(); +} +void i_integer_1d(svLogicVecVal* v) { + if (!update_1d(v, 32)) stop(); +} +void i_integer_2d(svLogicVecVal* v) { + if (!update_2d(v, 32)) stop(); +} +void i_integer_3d(svLogicVecVal* v) { + if (!update_3d(v, 32)) stop(); +} +#endif + +void i_real_0d(double* v) { update_0d(v); } +void i_real_1d(double* v) { update_1d(v); } +void i_real_2d(double* v) { update_2d(v); } +void i_real_3d(double* v) { update_3d(v); } + +#ifndef NO_SHORTREAL +void i_shortreal_0d(float* v) { update_0d(v); } +void i_shortreal_1d(float* v) { update_1d(v); } +void i_shortreal_2d(float* v) { update_2d(v); } +void i_shortreal_3d(float* v) { update_3d(v); } +#endif + +void i_chandle_0d(void** v) { + if (v[0]) stop(); + v[0] = get_non_null(); +} +void i_chandle_1d(void** v) { + if (v[0]) stop(); + if (v[1]) stop(); + v[0] = get_non_null(); + v[1] = get_non_null(); +} +void i_chandle_2d(void** v) { + if (v[2 * 0 + 1]) stop(); + if (v[2 * 1 + 1]) stop(); + if (v[2 * 2 + 1]) stop(); + v[2 * 0 + 1] = get_non_null(); + v[2 * 1 + 1] = get_non_null(); + v[2 * 2 + 1] = get_non_null(); +} +void i_chandle_3d(void** v) { + if (v[(0 * 3 + 0) * 2 + 0]) stop(); + if (v[(1 * 3 + 0) * 2 + 0]) stop(); + if (v[(2 * 3 + 0) * 2 + 0]) stop(); + if (v[(3 * 3 + 0) * 2 + 0]) stop(); + v[(0 * 3 + 0) * 2 + 0] = get_non_null(); + v[(1 * 3 + 0) * 2 + 0] = get_non_null(); + v[(2 * 3 + 0) * 2 + 0] = get_non_null(); + v[(3 * 3 + 0) * 2 + 0] = get_non_null(); +} + +void i_string_0d(const char** v) { + static const char s[] = "43"; + if (!compare(v[0], "42")) stop(); + v[0] = s; +} +void i_string_1d(const char** v) { + static const char s0[] = "44"; + static const char s1[] = "45"; + if (!compare(v[0], "43")) stop(); + if (!compare(v[1], "44")) stop(); + v[0] = s0; + v[1] = s1; +} +void i_string_2d(const char** v) { + static const char s0[] = "46"; + static const char s1[] = "47"; + static const char s2[] = "48"; + if (!compare(v[2 * 0 + 1], "45")) stop(); + if (!compare(v[2 * 1 + 1], "46")) stop(); + if (!compare(v[2 * 2 + 1], "47")) stop(); + v[2 * 0 + 1] = s0; + v[2 * 1 + 1] = s1; + v[2 * 2 + 1] = s2; +} +void i_string_3d(const char** v) { + static const char s0[] = "49"; + static const char s1[] = "50"; + static const char s2[] = "51"; + static const char s3[] = "52"; + if (!compare(v[(0 * 3 + 0) * 2 + 0], "48")) stop(); + if (!compare(v[(1 * 3 + 0) * 2 + 0], "49")) stop(); + if (!compare(v[(2 * 3 + 0) * 2 + 0], "50")) stop(); + if (!compare(v[(3 * 3 + 0) * 2 + 0], "51")) stop(); + v[(0 * 3 + 0) * 2 + 0] = s0; + v[(1 * 3 + 0) * 2 + 0] = s1; + v[(2 * 3 + 0) * 2 + 0] = s2; + v[(3 * 3 + 0) * 2 + 0] = s3; +} + +void i_bit7_0d(svBitVecVal* v) { update_0d(v, 7); } +void i_bit7_1d(svBitVecVal* v) { update_1d(v, 7); } +void i_bit7_2d(svBitVecVal* v) { update_2d(v, 7); } +void i_bit7_3d(svBitVecVal* v) { update_3d(v, 7); } + +void i_bit121_0d(svBitVecVal* v) { update_0d(v, 121); } +void i_bit121_1d(svBitVecVal* v) { update_1d(v, 121); } +void i_bit121_2d(svBitVecVal* v) { update_2d(v, 121); } +void i_bit121_3d(svBitVecVal* v) { update_3d(v, 121); } + +void i_logic7_0d(svLogicVecVal* v) { update_0d(v, 7); } +void i_logic7_1d(svLogicVecVal* v) { update_1d(v, 7); } +void i_logic7_2d(svLogicVecVal* v) { update_2d(v, 7); } +void i_logic7_3d(svLogicVecVal* v) { update_3d(v, 7); } + +void i_logic121_0d(svLogicVecVal* v) { update_0d(v, 121); } +void i_logic121_1d(svLogicVecVal* v) { update_1d(v, 121); } +void i_logic121_2d(svLogicVecVal* v) { update_2d(v, 121); } +void i_logic121_3d(svLogicVecVal* v) { update_3d(v, 121); } + +void i_pack_struct_0d(svLogicVecVal* v) { update_0d(v, 7); } +void i_pack_struct_1d(svLogicVecVal* v) { update_1d(v, 7); } +void i_pack_struct_2d(svLogicVecVal* v) { update_2d(v, 7); } +void i_pack_struct_3d(svLogicVecVal* v) { update_3d(v, 7); } + +#ifndef NO_UNPACK_STRUCT +void i_unpack_struct_0d(unpack_struct_t* v) { + if (!compare(v->val, 42, 121)) stop(); + set_uint(v->val, 43, 121); +} +void i_unpack_struct_1d(unpack_struct_t* v) { + if (!compare(v[0].val, 43, 121)) stop(); + if (!compare(v[1].val, 44, 121)) stop(); + set_uint(v[0].val, 44, 121); + set_uint(v[1].val, 45, 121); +} +void i_unpack_struct_2d(unpack_struct_t* v) { + if (!compare(v[0 * 2 + 1].val, 45, 121)) stop(); + if (!compare(v[1 * 2 + 1].val, 46, 121)) stop(); + if (!compare(v[2 * 2 + 1].val, 47, 121)) stop(); + set_uint(v[0 * 2 + 1].val, 46, 121); + set_uint(v[1 * 2 + 1].val, 47, 121); + set_uint(v[2 * 2 + 1].val, 48, 121); +} +void i_unpack_struct_3d(unpack_struct_t* v) { + if (!compare(v[(0 * 3 + 0) * 2 + 0].val, 48, 121)) stop(); + if (!compare(v[(1 * 3 + 0) * 2 + 0].val, 49, 121)) stop(); + if (!compare(v[(2 * 3 + 0) * 2 + 0].val, 50, 121)) stop(); + if (!compare(v[(3 * 3 + 0) * 2 + 0].val, 51, 121)) stop(); + set_uint(v[(0 * 3 + 0) * 2 + 0].val, 49, 121); + set_uint(v[(1 * 3 + 0) * 2 + 0].val, 50, 121); + set_uint(v[(2 * 3 + 0) * 2 + 0].val, 51, 121); + set_uint(v[(3 * 3 + 0) * 2 + 0].val, 52, 121); +} +#endif + +void check_exports() { + { + char byte_array[4][3][2]; + set_values(byte_array); + e_byte_0d(&byte_array[3][2][1]); + if (!check_0d(byte_array[3][2][1])) stop(); + e_byte_1d(&byte_array[2][1][0]); + if (!check_1d(byte_array[2][1])) stop(); + e_byte_2d(&byte_array[1][0][0]); + if (!check_2d(byte_array[1])) stop(); + e_byte_3d(&byte_array[0][0][0]); + if (!check_3d(byte_array)) stop(); + } + { + unsigned char byte_unsigned_array[4][3][2]; + set_values(byte_unsigned_array); + e_byte_unsigned_0d(&byte_unsigned_array[3][2][1]); + if (!check_0d(byte_unsigned_array[3][2][1])) stop(); + e_byte_unsigned_1d(&byte_unsigned_array[2][1][0]); + if (!check_1d(byte_unsigned_array[2][1])) stop(); + e_byte_unsigned_2d(&byte_unsigned_array[1][0][0]); + if (!check_2d(byte_unsigned_array[1])) stop(); + e_byte_unsigned_3d(&byte_unsigned_array[0][0][0]); + if (!check_3d(byte_unsigned_array)) stop(); + } + { + short shortint_array[4][3][2]; + set_values(shortint_array); + e_shortint_0d(&shortint_array[3][2][1]); + if (!check_0d(shortint_array[3][2][1])) stop(); + e_shortint_1d(&shortint_array[2][1][0]); + if (!check_1d(shortint_array[2][1])) stop(); + e_shortint_2d(&shortint_array[1][0][0]); + if (!check_2d(shortint_array[1])) stop(); + e_shortint_3d(&shortint_array[0][0][0]); + if (!check_3d(shortint_array)) stop(); + } + { + unsigned short shortint_unsigned_array[4][3][2]; + set_values(shortint_unsigned_array); + e_shortint_unsigned_0d(&shortint_unsigned_array[3][2][1]); + if (!check_0d(shortint_unsigned_array[3][2][1])) stop(); + e_shortint_unsigned_1d(&shortint_unsigned_array[2][1][0]); + if (!check_1d(shortint_unsigned_array[2][1])) stop(); + e_shortint_unsigned_2d(&shortint_unsigned_array[1][0][0]); + if (!check_2d(shortint_unsigned_array[1])) stop(); + e_shortint_unsigned_3d(&shortint_unsigned_array[0][0][0]); + if (!check_3d(shortint_unsigned_array)) stop(); + } + + { + int int_array[4][3][2]; + set_values(int_array); + e_int_0d(&int_array[3][2][1]); + if (!check_0d(int_array[3][2][1])) stop(); + e_int_1d(&int_array[2][1][0]); + if (!check_1d(int_array[2][1])) stop(); + e_int_2d(&int_array[1][0][0]); + if (!check_2d(int_array[1])) stop(); + e_int_3d(&int_array[0][0][0]); + if (!check_3d(int_array)) stop(); + } + { + unsigned int int_unsigned_array[4][3][2]; + set_values(int_unsigned_array); + e_int_unsigned_0d(&int_unsigned_array[3][2][1]); + if (!check_0d(int_unsigned_array[3][2][1])) stop(); + e_int_unsigned_1d(&int_unsigned_array[2][1][0]); + if (!check_1d(int_unsigned_array[2][1])) stop(); + e_int_unsigned_2d(&int_unsigned_array[1][0][0]); + if (!check_2d(int_unsigned_array[1])) stop(); + e_int_unsigned_3d(&int_unsigned_array[0][0][0]); + if (!check_3d(int_unsigned_array)) stop(); + } + + { + sv_longint_t longint_array[4][3][2]; + set_values(longint_array); + e_longint_0d(&longint_array[3][2][1]); + if (!check_0d(longint_array[3][2][1])) stop(); + e_longint_1d(&longint_array[2][1][0]); + if (!check_1d(longint_array[2][1])) stop(); + e_longint_2d(&longint_array[1][0][0]); + if (!check_2d(longint_array[1])) stop(); + e_longint_3d(&longint_array[0][0][0]); + if (!check_3d(longint_array)) stop(); + } + { + sv_longint_unsigned_t longint_unsigned_array[4][3][2]; + set_values(longint_unsigned_array); + e_longint_unsigned_0d(&longint_unsigned_array[3][2][1]); + if (!check_0d(longint_unsigned_array[3][2][1])) stop(); + e_longint_unsigned_1d(&longint_unsigned_array[2][1][0]); + if (!check_1d(longint_unsigned_array[2][1])) stop(); + e_longint_unsigned_2d(&longint_unsigned_array[1][0][0]); + if (!check_2d(longint_unsigned_array[1])) stop(); + e_longint_unsigned_3d(&longint_unsigned_array[0][0][0]); + if (!check_3d(longint_unsigned_array)) stop(); + } + +#ifndef NO_TIME + { + svLogicVecVal time_array[4][3][2][2]; + set_values(time_array, 64); + e_time_0d(time_array[3][2][1]); + if (!check_0d(time_array[3][2][1], 64)) stop(); + e_time_1d(time_array[2][1][0]); + if (!check_1d(time_array[2][1], 64)) stop(); + e_time_2d(time_array[1][0][0]); + if (!check_2d(time_array[1], 64)) stop(); + e_time_3d(time_array[0][0][0]); + if (!check_3d(time_array, 64)) stop(); + } +#endif + +#ifndef NO_INTEGER + { + svLogicVecVal integer_array[4][3][2][1]; + set_values(integer_array, 32); + e_integer_0d(integer_array[3][2][1]); + if (!check_0d(integer_array[3][2][1], 32)) stop(); + e_integer_1d(integer_array[2][1][0]); + if (!check_1d(integer_array[2][1], 32)) stop(); + e_integer_2d(integer_array[1][0][0]); + if (!check_2d(integer_array[1], 32)) stop(); + e_integer_3d(integer_array[0][0][0]); + if (!check_3d(integer_array, 32)) stop(); + } +#endif + + { + double real_array[4][3][2]; + set_values(real_array); + e_real_0d(&real_array[3][2][1]); + if (!check_0d(real_array[3][2][1])) stop(); + e_real_1d(&real_array[2][1][0]); + if (!check_1d(real_array[2][1])) stop(); + e_real_2d(&real_array[1][0][0]); + if (!check_2d(real_array[1])) stop(); + e_real_3d(&real_array[0][0][0]); + if (!check_3d(real_array)) stop(); + } +#ifndef NO_SHORTREAL + { + float shortreal_array[4][3][2]; + set_values(shortreal_array); + e_shortreal_0d(&shortreal_array[3][2][1]); + if (!check_0d(shortreal_array[3][2][1])) stop(); + e_shortreal_1d(&shortreal_array[2][1][0]); + if (!check_1d(shortreal_array[2][1])) stop(); + e_shortreal_2d(&shortreal_array[1][0][0]); + if (!check_2d(shortreal_array[1])) stop(); + e_shortreal_3d(&shortreal_array[0][0][0]); + if (!check_3d(shortreal_array)) stop(); + } +#endif + + { + void* chandle_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) chandle_array[i][j][k] = NULL; + chandle_array[3][2][1] = get_non_null(); + e_chandle_0d(&chandle_array[3][2][1]); + if (chandle_array[3][2][1]) stop(); + + chandle_array[2][1][0] = get_non_null(); + chandle_array[2][1][1] = get_non_null(); + e_chandle_1d(&chandle_array[2][1][0]); + if (chandle_array[2][1][0]) stop(); + if (chandle_array[2][1][1]) stop(); + + chandle_array[1][0][1] = get_non_null(); + chandle_array[1][1][1] = get_non_null(); + chandle_array[1][2][1] = get_non_null(); + e_chandle_2d(&chandle_array[1][0][0]); + if (chandle_array[1][0][1]) stop(); + if (chandle_array[1][1][1]) stop(); + if (chandle_array[1][2][1]) stop(); + + chandle_array[0][0][0] = get_non_null(); + chandle_array[1][0][0] = get_non_null(); + chandle_array[2][0][0] = get_non_null(); + chandle_array[3][0][0] = get_non_null(); + e_chandle_3d(&chandle_array[0][0][0]); + if (chandle_array[0][0][0]) stop(); + if (chandle_array[1][0][0]) stop(); + if (chandle_array[2][0][0]) stop(); + if (chandle_array[3][0][0]) stop(); + } + + { + const char* string_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) string_array[i][j][k] = ""; + string_array[3][2][1] = "42"; + e_string_0d(&string_array[3][2][1]); + if (!compare(string_array[3][2][1], "43")) stop(); + + string_array[2][1][0] = "43"; + string_array[2][1][1] = "44"; + e_string_1d(&string_array[2][1][0]); + if (!compare(string_array[2][1][0], "44")) stop(); + if (!compare(string_array[2][1][1], "45")) stop(); + + string_array[1][0][1] = "45"; + string_array[1][1][1] = "46"; + string_array[1][2][1] = "47"; + e_string_2d(&string_array[1][0][0]); + if (!compare(string_array[1][0][1], "46")) stop(); + if (!compare(string_array[1][1][1], "47")) stop(); + if (!compare(string_array[1][2][1], "48")) stop(); + + string_array[0][0][0] = "48"; + string_array[1][0][0] = "49"; + string_array[2][0][0] = "50"; + string_array[3][0][0] = "51"; + e_string_3d(&string_array[0][0][0]); + if (!compare(string_array[0][0][0], "49")) stop(); + if (!compare(string_array[1][0][0], "50")) stop(); + if (!compare(string_array[2][0][0], "51")) stop(); + if (!compare(string_array[3][0][0], "52")) stop(); + } + + { + svBitVecVal bit7_array[4][3][2][1]; + set_values(bit7_array, 7); + e_bit7_0d(bit7_array[3][2][1]); + if (!check_0d(bit7_array[3][2][1], 7)) stop(); + e_bit7_1d(bit7_array[2][1][0]); + if (!check_1d(bit7_array[2][1], 7)) stop(); + e_bit7_2d(bit7_array[1][0][0]); + if (!check_2d(bit7_array[1], 7)) stop(); + e_bit7_3d(bit7_array[0][0][0]); + if (!check_3d(bit7_array, 7)) stop(); + } + { + svBitVecVal bit121_array[4][3][2][4]; + set_values(bit121_array, 121); + e_bit121_0d(bit121_array[3][2][1]); + if (!check_0d(bit121_array[3][2][1], 121)) stop(); + e_bit121_1d(bit121_array[2][1][0]); + if (!check_1d(bit121_array[2][1], 121)) stop(); + e_bit121_2d(bit121_array[1][0][0]); + if (!check_2d(bit121_array[1], 121)) stop(); + e_bit121_3d(bit121_array[0][0][0]); + if (!check_3d(bit121_array, 121)) stop(); + } + + { + svLogicVecVal logic7_array[4][3][2][1]; + set_values(logic7_array, 7); + e_logic7_0d(logic7_array[3][2][1]); + if (!check_0d(logic7_array[3][2][1], 7)) stop(); + e_logic7_1d(logic7_array[2][1][0]); + if (!check_1d(logic7_array[2][1], 7)) stop(); + e_logic7_2d(logic7_array[1][0][0]); + if (!check_2d(logic7_array[1], 7)) stop(); + e_logic7_3d(logic7_array[0][0][0]); + if (!check_3d(logic7_array, 7)) stop(); + } + { + svLogicVecVal logic121_array[4][3][2][4]; + set_values(logic121_array, 121); + e_logic121_0d(logic121_array[3][2][1]); + if (!check_0d(logic121_array[3][2][1], 121)) stop(); + e_logic121_1d(logic121_array[2][1][0]); + if (!check_1d(logic121_array[2][1], 121)) stop(); + e_logic121_2d(logic121_array[1][0][0]); + if (!check_2d(logic121_array[1], 121)) stop(); + e_logic121_3d(logic121_array[0][0][0]); + if (!check_3d(logic121_array, 121)) stop(); + } + + { + svLogicVecVal pack_struct_array[4][3][2][1]; + set_values(pack_struct_array, 7); + e_pack_struct_0d(pack_struct_array[3][2][1]); + if (!check_0d(pack_struct_array[3][2][1], 7)) stop(); + e_pack_struct_1d(pack_struct_array[2][1][0]); + if (!check_1d(pack_struct_array[2][1], 7)) stop(); + e_pack_struct_2d(pack_struct_array[1][0][0]); + if (!check_2d(pack_struct_array[1], 7)) stop(); + e_pack_struct_3d(pack_struct_array[0][0][0]); + if (!check_3d(pack_struct_array, 7)) stop(); + } + +#ifndef NO_UNPACK_STRUCT + { + unpack_struct_t unpack_struct_array[4][3][2]; + set_uint(unpack_struct_array[3][2][1].val, 42, 121); + e_unpack_struct_0d(&unpack_struct_array[3][2][1]); + if (!compare(unpack_struct_array[3][2][1].val, 43, 121)) stop(); + + set_uint(unpack_struct_array[2][1][0].val, 43, 121); + set_uint(unpack_struct_array[2][1][1].val, 44, 121); + e_unpack_struct_1d(&unpack_struct_array[2][1][0]); + if (!compare(unpack_struct_array[2][1][0].val, 44, 121)) stop(); + if (!compare(unpack_struct_array[2][1][1].val, 45, 121)) stop(); + + set_uint(unpack_struct_array[1][0][1].val, 45, 121); + set_uint(unpack_struct_array[1][1][1].val, 46, 121); + set_uint(unpack_struct_array[1][2][1].val, 47, 121); + e_unpack_struct_2d(&unpack_struct_array[1][0][0]); + if (!compare(unpack_struct_array[1][0][1].val, 46, 121)) stop(); + if (!compare(unpack_struct_array[1][1][1].val, 47, 121)) stop(); + if (!compare(unpack_struct_array[1][2][1].val, 48, 121)) stop(); + + set_uint(unpack_struct_array[0][0][0].val, 48, 121); + set_uint(unpack_struct_array[1][0][0].val, 49, 121); + set_uint(unpack_struct_array[2][0][0].val, 50, 121); + set_uint(unpack_struct_array[3][0][0].val, 51, 121); + e_unpack_struct_3d(&unpack_struct_array[0][0][0]); + if (!compare(unpack_struct_array[0][0][0].val, 49, 121)) stop(); + if (!compare(unpack_struct_array[1][0][0].val, 50, 121)) stop(); + if (!compare(unpack_struct_array[2][0][0].val, 51, 121)) stop(); + if (!compare(unpack_struct_array[3][0][0].val, 52, 121)) stop(); + } +#endif +} diff --git a/test_regress/t/t_dpi_arg_inout_unpack.pl b/test_regress/t/t_dpi_arg_inout_unpack.pl new file mode 100755 index 000000000..59dfe0252 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_unpack.pl @@ -0,0 +1,44 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_inout_unpack.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_inout_unpack__Dpi.h", + "t/t_dpi_arg_inout_unpack__Dpi.out" + ); +} + +execute( + check_finished => 1, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_inout_unpack.v b/test_regress/t/t_dpi_arg_inout_unpack.v new file mode 100644 index 000000000..a37a24cc2 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_unpack.v @@ -0,0 +1,1162 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Yutetsu TAKATSUKASA. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NO_UNPACK_STRUCT +//%Error-TASKNSVAR: Unsupported: Function/task input argument is not simple variable + `define NO_INOUT_COMPLEX_TYPE +`else +`endif + +`define CHECK_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":", (act), " as expected"); \ + end else begin \ + $display("Mismatch %s expected:%d actual:%d at %d", `"act`", int'(exp), int'(act), `__LINE__); \ + $stop; \ + end + +`define CHECK_CHANDLE_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":non-null as expected"); \ + end else begin \ + $display("Mismatch %s expected:%s but %s at %d", `"act`", \ + (exp) != null ? "null" : "non-null", \ + (act) != null ? "null" : "non-null", `__LINE__); \ + $stop; \ + end + +`define CHECK_STRING_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":", (act), " as expected"); \ + end else begin \ + $display("Mismatch %s expected:%s actual:%s at %d", `"act`", (exp), (act), `__LINE__); \ + $stop; \ + end + +`define UPDATE_VAL(var, val) `CHECK_VAL(var, val); var += 1 +`define UPDATE_0D(val) `UPDATE_VAL(val, 42) +`define UPDATE_1D(val) `UPDATE_VAL(val[0], 43); \ +`UPDATE_VAL(val[1], 44) +`define UPDATE_2D(val) `UPDATE_VAL(val[0][1], 45); \ +`UPDATE_VAL(val[1][1], 46); \ +`UPDATE_VAL(val[2][1], 47) +`define UPDATE_3D(val) `UPDATE_VAL(val[0][0][0], 48); \ +`UPDATE_VAL(val[1][0][0], 49); \ +`UPDATE_VAL(val[2][0][0], 50); \ +`UPDATE_VAL(val[3][0][0], 51) + +`define CHECK_0D(val) `CHECK_VAL((val), 43) +`define CHECK_1D(val) `CHECK_VAL(val[0], 44); \ +`CHECK_VAL(val[1], 45) +`define CHECK_2D(val) `CHECK_VAL(val[0][1], 46); \ +`CHECK_VAL(val[1][1], 47); `CHECK_VAL(val[2][1], 48) +`define CHECK_3D(val) `CHECK_VAL(val[0][0][0], 49); \ +`CHECK_VAL(val[1][0][0], 50); \ +`CHECK_VAL(val[2][0][0], 51); \ +`CHECK_VAL(val[3][0][0], 52) + +`define CHECK_DOUBLE_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display("%s:%f as expected", `"act`", (act)); \ + end else begin \ + $display("Mismatch %s expected:%d actual:%f at %f", `"act`", (exp), (act), `__LINE__); \ + $stop; \ + end + +`define CHECK_DOUBLE_0D(val) `CHECK_DOUBLE_VAL((val), 43.0) +`define CHECK_DOUBLE_1D(val) `CHECK_DOUBLE_VAL(val[0], 44.0); \ +`CHECK_DOUBLE_VAL(val[1], 45.0) +`define CHECK_DOUBLE_2D(val) `CHECK_DOUBLE_VAL(val[0][1], 46.0); \ +`CHECK_DOUBLE_VAL(val[1][1], 47.0); \ +`CHECK_DOUBLE_VAL(val[2][1], 48.0) +`define CHECK_DOUBLE_3D(val) `CHECK_DOUBLE_VAL(val[0][0][0], 49.0); \ +`CHECK_DOUBLE_VAL(val[1][0][0], 50.0); \ +`CHECK_DOUBLE_VAL(val[2][0][0], 51.0); \ +`CHECK_DOUBLE_VAL(val[3][0][0], 52.0) + +`define SET_VALUE_0D(val) val = 42 +`define SET_VALUE_1D(val) val[0] = 43; val[1] = 44 +`define SET_VALUE_2D(val) val[0][1] = 45; val[1][1] = 46; val[2][1] = 47 +`define SET_VALUES(val) \ +val[3][2][1] = 42; \ +val[2][1][0] = 43; val[2][1][1] = 44; \ +val[1][0][1] = 45; val[1][1][1] = 46; val[1][2][1] = 47; \ +val[0][0][0] = 48; val[1][0][0] = 49; val[2][0][0] = 50; val[3][0][0] = 51 + +module t; + + localparam ENABLE_VERBOSE_MESSAGE = 0; + + // Legal output argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + typedef byte byte_t; + typedef byte_t byte_array_t[4][3][2]; + typedef byte unsigned byte_unsigned_t; + typedef byte_unsigned_t byte_unsigned_array_t[4][3][2]; + typedef shortint shortint_t; + typedef shortint_t shortint_array_t[4][3][2]; + typedef shortint unsigned shortint_unsigned_t; + typedef shortint_unsigned_t shortint_unsigned_array_t[4][3][2]; + typedef int int_t; + typedef int_t int_array_t[4][3][2]; + typedef int unsigned int_unsigned_t; + typedef int_unsigned_t int_unsigned_array_t[4][3][2]; + typedef longint longint_t; + typedef longint_t longint_array_t[4][3][2]; + typedef longint unsigned longint_unsigned_t; + typedef longint_unsigned_t longint_unsigned_array_t[4][3][2]; +`ifndef NO_TIME + typedef time time_t; + typedef time_t time_array_t[4][3][2]; +`endif +`ifndef NO_INTEGER + typedef integer integer_t; + typedef integer_t integer_array_t[4][3][2]; +`endif + typedef real real_t; + typedef real_t real_array_t[4][3][2]; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_t; + typedef shortreal_t shortreal_array_t[4][3][2]; +`endif + typedef chandle chandle_t; + typedef chandle_t chandle_array_t[4][3][2]; + typedef string string_t; + typedef string_t string_array_t[4][3][2]; + typedef bit [6:0] bit7_t; + typedef bit7_t bit7_array_t[4][3][2]; + typedef bit [120:0] bit121_t; + typedef bit121_t bit121_array_t[4][3][2]; + typedef logic [6:0] logic7_t; + typedef logic7_t logic7_array_t[4][3][2]; + typedef logic [120:0] logic121_t; + typedef logic121_t logic121_array_t[4][3][2]; + + typedef struct packed { + logic [6:0] val; + } pack_struct_t; + typedef pack_struct_t pack_struct_array_t[4][3][2]; +`ifndef NO_UNPACK_STRUCT + typedef struct { + logic [120:0] val; + } unpack_struct_t; + typedef unpack_struct_t unpack_struct_array_t[4][3][2]; +`endif + + //====================================================================== + // Imports + //====================================================================== + + // Returns non-null pointer + import "DPI-C" function chandle get_non_null(); + + import "DPI-C" function void i_byte_0d(inout byte_t val); + import "DPI-C" function void i_byte_1d(inout byte_t val[2]); + import "DPI-C" function void i_byte_2d(inout byte_t val[3][2]); + import "DPI-C" function void i_byte_3d(inout byte_array_t val); + + import "DPI-C" function void i_byte_unsigned_0d(inout byte unsigned val); + import "DPI-C" function void i_byte_unsigned_1d(inout byte unsigned val[2]); + import "DPI-C" function void i_byte_unsigned_2d(inout byte unsigned val[3][2]); + import "DPI-C" function void i_byte_unsigned_3d(inout byte_unsigned_array_t val); + + import "DPI-C" function void i_shortint_0d(inout shortint val); + import "DPI-C" function void i_shortint_1d(inout shortint val[2]); + import "DPI-C" function void i_shortint_2d(inout shortint val[3][2]); + import "DPI-C" function void i_shortint_3d(inout shortint_array_t val); + + import "DPI-C" function void i_shortint_unsigned_0d(inout shortint unsigned val); + import "DPI-C" function void i_shortint_unsigned_1d(inout shortint unsigned val[2]); + import "DPI-C" function void i_shortint_unsigned_2d(inout shortint unsigned val[3][2]); + import "DPI-C" function void i_shortint_unsigned_3d(inout shortint_unsigned_array_t val); + + import "DPI-C" function void i_int_0d(inout int val); + import "DPI-C" function void i_int_1d(inout int val[2]); + import "DPI-C" function void i_int_2d(inout int val[3][2]); + import "DPI-C" function void i_int_3d(inout int_array_t val); + + import "DPI-C" function void i_int_unsigned_0d(inout int unsigned val); + import "DPI-C" function void i_int_unsigned_1d(inout int unsigned val[2]); + import "DPI-C" function void i_int_unsigned_2d(inout int unsigned val[3][2]); + import "DPI-C" function void i_int_unsigned_3d(inout int_unsigned_array_t val); + + import "DPI-C" function void i_longint_0d(inout longint val); + import "DPI-C" function void i_longint_1d(inout longint val[2]); + import "DPI-C" function void i_longint_2d(inout longint val[3][2]); + import "DPI-C" function void i_longint_3d(inout longint_array_t val); + + import "DPI-C" function void i_longint_unsigned_0d(inout longint unsigned val); + import "DPI-C" function void i_longint_unsigned_1d(inout longint unsigned val[2]); + import "DPI-C" function void i_longint_unsigned_2d(inout longint unsigned val[3][2]); + import "DPI-C" function void i_longint_unsigned_3d(inout longint_unsigned_array_t val); + +`ifndef NO_TIME + import "DPI-C" function void i_time_0d(inout time val); + import "DPI-C" function void i_time_1d(inout time val[2]); + import "DPI-C" function void i_time_2d(inout time val[3][2]); + import "DPI-C" function void i_time_3d(inout time_array_t val); +`endif + +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_0d(inout integer val); + import "DPI-C" function void i_integer_1d(inout integer val[2]); + import "DPI-C" function void i_integer_2d(inout integer val[3][2]); + import "DPI-C" function void i_integer_3d(inout integer_array_t val); +`endif + + import "DPI-C" function void i_real_0d(inout real val); + import "DPI-C" function void i_real_1d(inout real val[2]); + import "DPI-C" function void i_real_2d(inout real val[3][2]); + import "DPI-C" function void i_real_3d(inout real_array_t val); + +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_0d(inout shortreal val); + import "DPI-C" function void i_shortreal_1d(inout shortreal val[2]); + import "DPI-C" function void i_shortreal_2d(inout shortreal val[3][2]); + import "DPI-C" function void i_shortreal_3d(inout shortreal_array_t val); +`endif + + import "DPI-C" function void i_chandle_0d(inout chandle val); + import "DPI-C" function void i_chandle_1d(inout chandle val[2]); + import "DPI-C" function void i_chandle_2d(inout chandle val[3][2]); + import "DPI-C" function void i_chandle_3d(inout chandle_array_t val); + + import "DPI-C" function void i_string_0d(inout string val); + import "DPI-C" function void i_string_1d(inout string val[2]); + import "DPI-C" function void i_string_2d(inout string val[3][2]); + import "DPI-C" function void i_string_3d(inout string_array_t val); + + import "DPI-C" function void i_bit7_0d(inout bit[6:0] val); + import "DPI-C" function void i_bit7_1d(inout bit[6:0] val[2]); + import "DPI-C" function void i_bit7_2d(inout bit[6:0] val[3][2]); + import "DPI-C" function void i_bit7_3d(inout bit7_array_t val); + + import "DPI-C" function void i_bit121_0d(inout bit[120:0] val); + import "DPI-C" function void i_bit121_1d(inout bit[120:0] val[2]); + import "DPI-C" function void i_bit121_2d(inout bit[120:0] val[3][2]); + import "DPI-C" function void i_bit121_3d(inout bit121_array_t val); + + import "DPI-C" function void i_logic7_0d(inout logic[6:0] val); + import "DPI-C" function void i_logic7_1d(inout logic[6:0] val[2]); + import "DPI-C" function void i_logic7_2d(inout logic[6:0] val[3][2]); + import "DPI-C" function void i_logic7_3d(inout logic7_array_t val); + + import "DPI-C" function void i_logic121_0d(inout logic[120:0] val); + import "DPI-C" function void i_logic121_1d(inout logic[120:0] val[2]); + import "DPI-C" function void i_logic121_2d(inout logic[120:0] val[3][2]); + import "DPI-C" function void i_logic121_3d(inout logic121_array_t val); + + import "DPI-C" function void i_pack_struct_0d(inout pack_struct_t val); + import "DPI-C" function void i_pack_struct_1d(inout pack_struct_t val[2]); + import "DPI-C" function void i_pack_struct_2d(inout pack_struct_t val[3][2]); + import "DPI-C" function void i_pack_struct_3d(inout pack_struct_array_t val); + +`ifndef NO_UNPACK_STRUCT + import "DPI-C" function void i_unpack_struct_0d(inout unpack_struct_t val); + import "DPI-C" function void i_unpack_struct_1d(inout unpack_struct_t val[2]); + import "DPI-C" function void i_unpack_struct_2d(inout unpack_struct_t val[3][2]); + import "DPI-C" function void i_unpack_struct_3d(inout unpack_struct_array_t val); +`endif + + //====================================================================== + // Exports + //====================================================================== + export "DPI-C" function e_byte_0d; + export "DPI-C" function e_byte_1d; + export "DPI-C" function e_byte_2d; + export "DPI-C" function e_byte_3d; + + export "DPI-C" function e_byte_unsigned_0d; + export "DPI-C" function e_byte_unsigned_1d; + export "DPI-C" function e_byte_unsigned_2d; + export "DPI-C" function e_byte_unsigned_3d; + + export "DPI-C" function e_shortint_0d; + export "DPI-C" function e_shortint_1d; + export "DPI-C" function e_shortint_2d; + export "DPI-C" function e_shortint_3d; + + export "DPI-C" function e_shortint_unsigned_0d; + export "DPI-C" function e_shortint_unsigned_1d; + export "DPI-C" function e_shortint_unsigned_2d; + export "DPI-C" function e_shortint_unsigned_3d; + + export "DPI-C" function e_int_0d; + export "DPI-C" function e_int_1d; + export "DPI-C" function e_int_2d; + export "DPI-C" function e_int_3d; + + export "DPI-C" function e_int_unsigned_0d; + export "DPI-C" function e_int_unsigned_1d; + export "DPI-C" function e_int_unsigned_2d; + export "DPI-C" function e_int_unsigned_3d; + + export "DPI-C" function e_longint_0d; + export "DPI-C" function e_longint_1d; + export "DPI-C" function e_longint_2d; + export "DPI-C" function e_longint_3d; + + export "DPI-C" function e_longint_unsigned_0d; + export "DPI-C" function e_longint_unsigned_1d; + export "DPI-C" function e_longint_unsigned_2d; + export "DPI-C" function e_longint_unsigned_3d; + +`ifndef NO_TIME + export "DPI-C" function e_time_0d; + export "DPI-C" function e_time_1d; + export "DPI-C" function e_time_2d; + export "DPI-C" function e_time_3d; +`endif + +`ifndef NO_INTEGER + export "DPI-C" function e_integer_0d; + export "DPI-C" function e_integer_1d; + export "DPI-C" function e_integer_2d; + export "DPI-C" function e_integer_3d; +`endif + + export "DPI-C" function e_real_0d; + export "DPI-C" function e_real_1d; + export "DPI-C" function e_real_2d; + export "DPI-C" function e_real_3d; + +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_0d; + export "DPI-C" function e_shortreal_1d; + export "DPI-C" function e_shortreal_2d; + export "DPI-C" function e_shortreal_3d; +`endif + + export "DPI-C" function e_chandle_0d; + export "DPI-C" function e_chandle_1d; + export "DPI-C" function e_chandle_2d; + export "DPI-C" function e_chandle_3d; + + export "DPI-C" function e_string_0d; + export "DPI-C" function e_string_1d; + export "DPI-C" function e_string_2d; + export "DPI-C" function e_string_3d; + + export "DPI-C" function e_bit7_0d; + export "DPI-C" function e_bit7_1d; + export "DPI-C" function e_bit7_2d; + export "DPI-C" function e_bit7_3d; + + export "DPI-C" function e_bit121_0d; + export "DPI-C" function e_bit121_1d; + export "DPI-C" function e_bit121_2d; + export "DPI-C" function e_bit121_3d; + + export "DPI-C" function e_logic7_0d; + export "DPI-C" function e_logic7_1d; + export "DPI-C" function e_logic7_2d; + export "DPI-C" function e_logic7_3d; + + export "DPI-C" function e_logic121_0d; + export "DPI-C" function e_logic121_1d; + export "DPI-C" function e_logic121_2d; + export "DPI-C" function e_logic121_3d; + + export "DPI-C" function e_pack_struct_0d; + export "DPI-C" function e_pack_struct_1d; + export "DPI-C" function e_pack_struct_2d; + export "DPI-C" function e_pack_struct_3d; + +`ifndef NO_UNPACK_STRUCT + export "DPI-C" function e_unpack_struct_0d; + export "DPI-C" function e_unpack_struct_1d; + export "DPI-C" function e_unpack_struct_2d; + export "DPI-C" function e_unpack_struct_3d; +`endif + //====================================================================== + // Definitions of exported functions + //====================================================================== + + function void e_byte_0d(inout byte val); `UPDATE_0D(val); endfunction + function void e_byte_1d(inout byte val[2]); `UPDATE_1D(val); endfunction + function void e_byte_2d(inout byte val[3][2]); `UPDATE_2D(val); endfunction + function void e_byte_3d(inout byte_array_t val); `UPDATE_3D(val); endfunction + + function void e_byte_unsigned_0d(inout byte unsigned val); `UPDATE_0D(val); endfunction + function void e_byte_unsigned_1d(inout byte unsigned val[2]); `UPDATE_1D(val); endfunction + function void e_byte_unsigned_2d(inout byte unsigned val[3][2]); `UPDATE_2D(val); endfunction + function void e_byte_unsigned_3d(inout byte_unsigned_array_t val); `UPDATE_3D(val); endfunction + + function void e_shortint_0d(inout shortint val); `UPDATE_0D(val); endfunction + function void e_shortint_1d(inout shortint val[2]); `UPDATE_1D(val); endfunction + function void e_shortint_2d(inout shortint val[3][2]); `UPDATE_2D(val); endfunction + function void e_shortint_3d(inout shortint_array_t val); `UPDATE_3D(val); endfunction + + function void e_shortint_unsigned_0d(inout shortint unsigned val); `UPDATE_0D(val); endfunction + function void e_shortint_unsigned_1d(inout shortint unsigned val[2]); `UPDATE_1D(val); endfunction + function void e_shortint_unsigned_2d(inout shortint unsigned val[3][2]); `UPDATE_2D(val); endfunction + function void e_shortint_unsigned_3d(inout shortint_unsigned_array_t val); `UPDATE_3D(val); endfunction + + + function void e_int_0d(inout int val); `UPDATE_0D(val); endfunction + function void e_int_1d(inout int val[2]); `UPDATE_1D(val); endfunction + function void e_int_2d(inout int val[3][2]); `UPDATE_2D(val); endfunction + function void e_int_3d(inout int_array_t val); `UPDATE_3D(val); endfunction + + function void e_int_unsigned_0d(inout int unsigned val); `UPDATE_0D(val); endfunction + function void e_int_unsigned_1d(inout int unsigned val[2]); `UPDATE_1D(val); endfunction + function void e_int_unsigned_2d(inout int unsigned val[3][2]); `UPDATE_2D(val); endfunction + function void e_int_unsigned_3d(inout int_unsigned_array_t val); `UPDATE_3D(val); endfunction + + + + function void e_longint_0d(inout longint val); `UPDATE_0D(val); endfunction + function void e_longint_1d(inout longint val[2]); `UPDATE_1D(val); endfunction + function void e_longint_2d(inout longint val[3][2]); `UPDATE_2D(val); endfunction + function void e_longint_3d(inout longint_array_t val); `UPDATE_3D(val); endfunction + + function void e_longint_unsigned_0d(inout longint unsigned val); `UPDATE_0D(val); endfunction + function void e_longint_unsigned_1d(inout longint unsigned val[2]); `UPDATE_1D(val); endfunction + function void e_longint_unsigned_2d(inout longint unsigned val[3][2]); `UPDATE_2D(val); endfunction + function void e_longint_unsigned_3d(inout longint_unsigned_array_t val); `UPDATE_3D(val); endfunction + +`ifndef NO_TIME + function void e_time_0d(inout time val); `UPDATE_0D(val); endfunction + function void e_time_1d(inout time val[2]); `UPDATE_1D(val); endfunction + function void e_time_2d(inout time val[3][2]); `UPDATE_2D(val); endfunction + function void e_time_3d(inout time_array_t val); `UPDATE_3D(val); endfunction +`endif + +`ifndef NO_INTEGER + function void e_integer_0d(inout integer val); `UPDATE_0D(val); endfunction + function void e_integer_1d(inout integer val[2]); `UPDATE_1D(val); endfunction + function void e_integer_2d(inout integer val[3][2]); `UPDATE_2D(val); endfunction + function void e_integer_3d(inout integer_array_t val); `UPDATE_3D(val); endfunction +`endif + + function void e_real_0d(inout real val); `UPDATE_0D(val); endfunction + function void e_real_1d(inout real val[2]); `UPDATE_1D(val); endfunction + function void e_real_2d(inout real val[3][2]); `UPDATE_2D(val); endfunction + function void e_real_3d(inout real_array_t val); `UPDATE_3D(val); endfunction + +`ifndef NO_SHORTREAL + function void e_shortreal_0d(inout shortreal val); `UPDATE_0D(val); endfunction + function void e_shortreal_1d(inout shortreal val[2]); `UPDATE_1D(val); endfunction + function void e_shortreal_2d(inout shortreal val[3][2]); `UPDATE_2D(val); endfunction + function void e_shortreal_3d(inout shortreal_array_t val); `UPDATE_3D(val); endfunction +`endif + + + function void e_chandle_0d(inout chandle val); + `CHECK_CHANDLE_VAL(val, get_non_null()); + val = null; + endfunction + function void e_chandle_1d(inout chandle val[2]); + `CHECK_CHANDLE_VAL(val[0], get_non_null()); + `CHECK_CHANDLE_VAL(val[1], get_non_null()); + val[0] = null; + val[1] = null; + endfunction + function void e_chandle_2d(inout chandle val[3][2]); + `CHECK_CHANDLE_VAL(val[0][1], get_non_null()); + `CHECK_CHANDLE_VAL(val[1][1], get_non_null()); + `CHECK_CHANDLE_VAL(val[2][1], get_non_null()); + val[0][1] = null; + val[1][1] = null; + val[2][1] = null; + endfunction + function void e_chandle_3d(inout chandle_array_t val); + `CHECK_CHANDLE_VAL(val[0][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(val[1][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(val[2][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(val[3][0][0], get_non_null()); + val[0][0][0] = null; + val[1][0][0] = null; + val[2][0][0] = null; + val[3][0][0] = null; + endfunction + + + function void e_string_0d(inout string val); + `CHECK_STRING_VAL(val, "42"); + val = "43"; + endfunction + function void e_string_1d(inout string val[2]); + `CHECK_STRING_VAL(val[0], "43"); + `CHECK_STRING_VAL(val[1], "44"); + val[0] = "44"; + val[1] = "45"; + endfunction + function void e_string_2d(inout string val[3][2]); + `CHECK_STRING_VAL(val[0][1], "45"); + `CHECK_STRING_VAL(val[1][1], "46"); + `CHECK_STRING_VAL(val[2][1], "47"); + val[0][1] = "46"; + val[1][1] = "47"; + val[2][1] = "48"; + endfunction + function void e_string_3d(inout string_array_t val); + `CHECK_STRING_VAL(val[0][0][0], "48"); + `CHECK_STRING_VAL(val[1][0][0], "49"); + `CHECK_STRING_VAL(val[2][0][0], "50"); + `CHECK_STRING_VAL(val[3][0][0], "51"); + val[0][0][0] = "49"; + val[1][0][0] = "50"; + val[2][0][0] = "51"; + val[3][0][0] = "52"; + endfunction + + function void e_bit7_0d(inout bit[6:0] val); `UPDATE_0D(val); endfunction + function void e_bit7_1d(inout bit[6:0] val[2]); `UPDATE_1D(val); endfunction + function void e_bit7_2d(inout bit[6:0] val[3][2]); `UPDATE_2D(val); endfunction + function void e_bit7_3d(inout bit7_array_t val); `UPDATE_3D(val); endfunction + + function void e_bit121_0d(inout bit[120:0] val); `UPDATE_0D(val); endfunction + function void e_bit121_1d(inout bit[120:0] val[2]); `UPDATE_1D(val); endfunction + function void e_bit121_2d(inout bit[120:0] val[3][2]); `UPDATE_2D(val); endfunction + function void e_bit121_3d(inout bit121_array_t val); `UPDATE_3D(val); endfunction + + function void e_logic7_0d(inout logic[6:0] val); `UPDATE_0D(val); endfunction + function void e_logic7_1d(inout logic[6:0] val[2]); `UPDATE_1D(val); endfunction + function void e_logic7_2d(inout logic[6:0] val[3][2]); `UPDATE_2D(val); endfunction + function void e_logic7_3d(inout logic7_array_t val); `UPDATE_3D(val); endfunction + + function void e_logic121_0d(inout logic[120:0] val); `UPDATE_0D(val); endfunction + function void e_logic121_1d(inout logic[120:0] val[2]); `UPDATE_1D(val); endfunction + function void e_logic121_2d(inout logic[120:0] val[3][2]); `UPDATE_2D(val); endfunction + function void e_logic121_3d(inout logic121_array_t val); `UPDATE_3D(val); endfunction + + function void e_pack_struct_0d(inout pack_struct_t val); `UPDATE_0D(val); endfunction + function void e_pack_struct_1d(inout pack_struct_t val[2]); `UPDATE_1D(val); endfunction + function void e_pack_struct_2d(inout pack_struct_t val[3][2]); `UPDATE_2D(val); endfunction + function void e_pack_struct_3d(inout pack_struct_array_t val); `UPDATE_3D(val); endfunction + +`ifndef NO_UNPACK_STRUCT + function void e_unpack_struct_0d(inout unpack_struct_t val); + `CHECK_VAL(val.val, 42); + val.val = 43; + endfunction + function void e_unpack_struct_1d(inout unpack_struct_t val[2]); + `CHECK_VAL(val[0].val, 43); + `CHECK_VAL(val[1].val, 44); + val[0].val = 44; + val[1].val = 45; + endfunction + function void e_unpack_struct_2d(inout unpack_struct_t val[3][2]); + `CHECK_VAL(val[0][1].val, 45); + `CHECK_VAL(val[1][1].val, 46); + `CHECK_VAL(val[2][1].val, 47); + val[0][1].val = 46; + val[1][1].val = 47; + val[2][1].val = 48; + endfunction + function void e_unpack_struct_3d(inout unpack_struct_array_t val); + `CHECK_VAL(val[0][0][0].val, 48); + `CHECK_VAL(val[1][0][0].val, 49); + `CHECK_VAL(val[2][0][0].val, 50); + `CHECK_VAL(val[3][0][0].val, 51); + val[0][0][0].val = 49; + val[1][0][0].val = 50; + val[2][0][0].val = 51; + val[3][0][0].val = 52; + endfunction +`endif + + //====================================================================== + // Invoke all imported functions + //====================================================================== + + import "DPI-C" context function void check_exports(); + initial begin + byte_t byte_array_0d; + byte_t byte_array_1d[2]; + byte_t byte_array_2d[3][2]; + byte_array_t byte_array; + byte_unsigned_t byte_unsigned_array_0d; + byte_unsigned_t byte_unsigned_array_1d[2]; + byte_unsigned_t byte_unsigned_array_2d[3][2]; + byte_unsigned_array_t byte_unsigned_array; + shortint_t shortint_array_0d; + shortint_t shortint_array_1d[2]; + shortint_t shortint_array_2d[3][2]; + shortint_array_t shortint_array; + shortint_unsigned_t shortint_unsigned_array_0d; + shortint_unsigned_t shortint_unsigned_array_1d[2]; + shortint_unsigned_t shortint_unsigned_array_2d[3][2]; + shortint_unsigned_array_t shortint_unsigned_array; + int_t int_array_0d; + int_t int_array_1d[2]; + int_t int_array_2d[3][2]; + int_array_t int_array; + int_unsigned_t int_unsigned_array_0d; + int_unsigned_t int_unsigned_array_1d[2]; + int_unsigned_t int_unsigned_array_2d[3][2]; + int_unsigned_array_t int_unsigned_array; + longint_t longint_array_0d; + longint_t longint_array_1d[2]; + longint_t longint_array_2d[3][2]; + longint_array_t longint_array; + longint_unsigned_t longint_unsigned_array_0d; + longint_unsigned_t longint_unsigned_array_1d[2]; + longint_unsigned_t longint_unsigned_array_2d[3][2]; + longint_unsigned_array_t longint_unsigned_array; +`ifndef NO_TIME + time_t time_array_0d; + time_t time_array_1d[2]; + time_t time_array_2d[3][2]; + time_array_t time_array; +`endif +`ifndef NO_INTEGER + integer_t integer_array_0d; + integer_t integer_array_1d[2]; + integer_t integer_array_2d[3][2]; + integer_array_t integer_array; +`endif + real_t real_array_0d; + real_t real_array_1d[2]; + real_t real_array_2d[3][2]; + real_array_t real_array; +`ifndef NO_SHORTREAL + shortreal_t shortreal_array_0d; + shortreal_t shortreal_array_1d[2]; + shortreal_t shortreal_array_2d[3][2]; + shortreal_array_t shortreal_array; +`endif + chandle_t chandle_array_0d; + chandle_t chandle_array_1d[2]; + chandle_t chandle_array_2d[3][2]; + chandle_array_t chandle_array; + + string_t string_array_0d; + string_t string_array_1d[2]; + string_t string_array_2d[3][2]; + string_array_t string_array; + + bit7_t bit7_array_0d; + bit7_t bit7_array_1d[2]; + bit7_t bit7_array_2d[3][2]; + bit7_array_t bit7_array; + + bit121_t bit121_array_0d; + bit121_t bit121_array_1d[2]; + bit121_t bit121_array_2d[3][2]; + bit121_array_t bit121_array; + + logic7_t logic7_array_0d; + logic7_t logic7_array_1d[2]; + logic7_t logic7_array_2d[3][2]; + logic7_array_t logic7_array; + + logic121_t logic121_array_0d; + logic121_t logic121_array_1d[2]; + logic121_t logic121_array_2d[3][2]; + logic121_array_t logic121_array; + + pack_struct_t pack_struct_array_0d; + pack_struct_t pack_struct_array_1d[2]; + pack_struct_t pack_struct_array_2d[3][2]; + pack_struct_array_t pack_struct_array; + +`ifndef NO_UNPACK_STRUCT + unpack_struct_t unpack_struct_array_0d; + unpack_struct_t unpack_struct_array_1d[2]; + unpack_struct_t unpack_struct_array_2d[3][2]; + unpack_struct_array_t unpack_struct_array; +`endif + + `SET_VALUES(byte_array); + `SET_VALUE_0D(byte_array_0d); + `SET_VALUE_1D(byte_array_1d); + `SET_VALUE_2D(byte_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_byte_0d(byte_array[3][2][1]); + `CHECK_0D(byte_array[3][2][1]); + i_byte_1d(byte_array[2][1]); + `CHECK_1D(byte_array[2][1]); + i_byte_2d(byte_array[1]); + `CHECK_2D(byte_array[1]); +`endif + i_byte_0d(byte_array_0d); + `CHECK_0D(byte_array_0d); + i_byte_1d(byte_array_1d); + `CHECK_1D(byte_array_1d); + i_byte_2d(byte_array_2d); + `CHECK_2D(byte_array_2d); + i_byte_3d(byte_array); + `CHECK_3D(byte_array); + + `SET_VALUES(byte_unsigned_array); + `SET_VALUE_0D(byte_unsigned_array_0d); + `SET_VALUE_1D(byte_unsigned_array_1d); + `SET_VALUE_2D(byte_unsigned_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_byte_unsigned_0d(byte_unsigned_array[3][2][1]); + `CHECK_0D(byte_unsigned_array[3][2][1]); + i_byte_unsigned_1d(byte_unsigned_array[2][1]); + `CHECK_1D(byte_unsigned_array[2][1]); + i_byte_unsigned_2d(byte_unsigned_array[1]); + `CHECK_2D(byte_unsigned_array[1]); +`endif + i_byte_unsigned_0d(byte_unsigned_array_0d); + `CHECK_0D(byte_unsigned_array_0d); + i_byte_unsigned_1d(byte_unsigned_array_1d); + `CHECK_1D(byte_unsigned_array_1d); + i_byte_unsigned_2d(byte_unsigned_array_2d); + `CHECK_2D(byte_unsigned_array_2d); + i_byte_unsigned_3d(byte_unsigned_array); + `CHECK_3D(byte_unsigned_array); + + `SET_VALUES(shortint_array); + `SET_VALUE_0D(shortint_array_0d); + `SET_VALUE_1D(shortint_array_1d); + `SET_VALUE_2D(shortint_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_shortint_0d(shortint_array[3][2][1]); + `CHECK_0D(shortint_array[3][2][1]); + i_shortint_1d(shortint_array[2][1]); + `CHECK_1D(shortint_array[2][1]); + i_shortint_2d(shortint_array[1]); + `CHECK_2D(shortint_array[1]); +`endif + i_shortint_0d(shortint_array_0d); + `CHECK_0D(shortint_array_0d); + i_shortint_1d(shortint_array_1d); + `CHECK_1D(shortint_array_1d); + i_shortint_2d(shortint_array_2d); + `CHECK_2D(shortint_array_2d); + i_shortint_3d(shortint_array); + `CHECK_3D(shortint_array); + + `SET_VALUES(shortint_unsigned_array); + `SET_VALUE_0D(shortint_unsigned_array_0d); + `SET_VALUE_1D(shortint_unsigned_array_1d); + `SET_VALUE_2D(shortint_unsigned_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_shortint_unsigned_0d(shortint_unsigned_array[3][2][1]); + `CHECK_0D(shortint_unsigned_array[3][2][1]); + i_shortint_unsigned_1d(shortint_unsigned_array[2][1]); + `CHECK_1D(shortint_unsigned_array[2][1]); + i_shortint_unsigned_2d(shortint_unsigned_array[1]); + `CHECK_2D(shortint_unsigned_array[1]); +`endif + i_shortint_unsigned_0d(shortint_unsigned_array_0d); + `CHECK_0D(shortint_unsigned_array_0d); + i_shortint_unsigned_1d(shortint_unsigned_array_1d); + `CHECK_1D(shortint_unsigned_array_1d); + i_shortint_unsigned_2d(shortint_unsigned_array_2d); + `CHECK_2D(shortint_unsigned_array_2d); + i_shortint_unsigned_3d(shortint_unsigned_array); + `CHECK_3D(shortint_unsigned_array); + + `SET_VALUES(int_array); + `SET_VALUE_0D(int_array_0d); + `SET_VALUE_1D(int_array_1d); + `SET_VALUE_2D(int_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_int_0d(int_array[3][2][1]); + `CHECK_0D(int_array[3][2][1]); + i_int_1d(int_array[2][1]); + `CHECK_1D(int_array[2][1]); + i_int_2d(int_array[1]); + `CHECK_2D(int_array[1]); +`endif + i_int_0d(int_array_0d); + `CHECK_0D(int_array_0d); + i_int_1d(int_array_1d); + `CHECK_1D(int_array_1d); + i_int_2d(int_array_2d); + `CHECK_2D(int_array_2d); + i_int_3d(int_array); + `CHECK_3D(int_array); + + `SET_VALUES(int_unsigned_array); + `SET_VALUE_0D(int_unsigned_array_0d); + `SET_VALUE_1D(int_unsigned_array_1d); + `SET_VALUE_2D(int_unsigned_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_int_unsigned_0d(int_unsigned_array[3][2][1]); + `CHECK_0D(int_unsigned_array[3][2][1]); + i_int_unsigned_1d(int_unsigned_array[2][1]); + `CHECK_1D(int_unsigned_array[2][1]); + i_int_unsigned_2d(int_unsigned_array[1]); + `CHECK_2D(int_unsigned_array[1]); +`endif + i_int_unsigned_0d(int_unsigned_array_0d); + `CHECK_0D(int_unsigned_array_0d); + i_int_unsigned_1d(int_unsigned_array_1d); + `CHECK_1D(int_unsigned_array_1d); + i_int_unsigned_2d(int_unsigned_array_2d); + `CHECK_2D(int_unsigned_array_2d); + i_int_unsigned_3d(int_unsigned_array); + `CHECK_3D(int_unsigned_array); + + `SET_VALUES(longint_array); + `SET_VALUE_0D(longint_array_0d); + `SET_VALUE_1D(longint_array_1d); + `SET_VALUE_2D(longint_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_longint_0d(longint_array[3][2][1]); + `CHECK_0D(longint_array[3][2][1]); + i_longint_1d(longint_array[2][1]); + `CHECK_1D(longint_array[2][1]); + i_longint_2d(longint_array[1]); + `CHECK_2D(longint_array[1]); +`endif + i_longint_0d(longint_array_0d); + `CHECK_0D(longint_array_0d); + i_longint_1d(longint_array_1d); + `CHECK_1D(longint_array_1d); + i_longint_2d(longint_array_2d); + `CHECK_2D(longint_array_2d); + i_longint_3d(longint_array); + `CHECK_3D(longint_array); + + `SET_VALUES(longint_unsigned_array); + `SET_VALUE_0D(longint_unsigned_array_0d); + `SET_VALUE_1D(longint_unsigned_array_1d); + `SET_VALUE_2D(longint_unsigned_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_longint_unsigned_0d(longint_unsigned_array[3][2][1]); + `CHECK_0D(longint_unsigned_array[3][2][1]); + i_longint_unsigned_1d(longint_unsigned_array[2][1]); + `CHECK_1D(longint_unsigned_array[2][1]); + i_longint_unsigned_2d(longint_unsigned_array[1]); + `CHECK_2D(longint_unsigned_array[1]); +`endif + i_longint_unsigned_0d(longint_unsigned_array_0d); + `CHECK_0D(longint_unsigned_array_0d); + i_longint_unsigned_1d(longint_unsigned_array_1d); + `CHECK_1D(longint_unsigned_array_1d); + i_longint_unsigned_2d(longint_unsigned_array_2d); + `CHECK_2D(longint_unsigned_array_2d); + i_longint_unsigned_3d(longint_unsigned_array); + `CHECK_3D(longint_unsigned_array); + +`ifndef NO_TIME + `SET_VALUES(time_array); + `SET_VALUE_0D(time_array_0d); + `SET_VALUE_1D(time_array_1d); + `SET_VALUE_2D(time_array_2d); + `ifndef NO_INOUT_COMPLEX_TYPE + i_time_0d(time_array[3][2][1]); + `CHECK_0D(time_array[3][2][1]); + i_time_1d(time_array[2][1]); + `CHECK_1D(time_array[2][1]); + i_time_2d(time_array[1]); + `CHECK_2D(time_array[1]); + `endif + i_time_0d(time_array_0d); + `CHECK_0D(time_array_0d); + i_time_1d(time_array_1d); + `CHECK_1D(time_array_1d); + i_time_2d(time_array_2d); + `CHECK_2D(time_array_2d); + i_time_3d(time_array); + `CHECK_3D(time_array); +`endif + +`ifndef NO_INTEGER + `SET_VALUES(integer_array); + `SET_VALUE_0D(integer_array_0d); + `SET_VALUE_1D(integer_array_1d); + `SET_VALUE_2D(integer_array_2d); + `ifndef NO_INOUT_COMPLEX_TYPE + i_integer_0d(integer_array[3][2][1]); + `CHECK_0D(integer_array[3][2][1]); + i_integer_1d(integer_array[2][1]); + `CHECK_1D(integer_array[2][1]); + i_integer_2d(integer_array[1]); + `CHECK_2D(integer_array[1]); + `endif + i_integer_0d(integer_array_0d); + `CHECK_0D(integer_array_0d); + i_integer_1d(integer_array_1d); + `CHECK_1D(integer_array_1d); + i_integer_2d(integer_array_2d); + `CHECK_2D(integer_array_2d); + i_integer_3d(integer_array); + `CHECK_3D(integer_array); +`endif + + `SET_VALUES(real_array); + `SET_VALUE_0D(real_array_0d); + `SET_VALUE_1D(real_array_1d); + `SET_VALUE_2D(real_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_real_0d(real_array[3][2][1]); + `CHECK_DOUBLE_0D(real_array[3][2][1]); + i_real_1d(real_array[2][1]); + `CHECK_DOUBLE_1D(real_array[2][1]); + i_real_2d(real_array[1]); + `CHECK_DOUBLE_2D(real_array[1]); +`endif + i_real_0d(real_array_0d); + `CHECK_DOUBLE_0D(real_array_0d); + i_real_1d(real_array_1d); + `CHECK_DOUBLE_1D(real_array_1d); + i_real_2d(real_array_2d); + `CHECK_DOUBLE_2D(real_array_2d); + i_real_3d(real_array); + `CHECK_DOUBLE_3D(real_array); + +`ifndef NO_SHORTREAL + `SET_VALUES(shortreal_array); + `SET_VALUE_0D(shortreal_array_0d); + `SET_VALUE_1D(shortreal_array_1d); + `SET_VALUE_2D(shortreal_array_2d); + `ifndef NO_INOUT_COMPLEX_TYPE + i_shortreal_0d(shortreal_array[3][2][1]); + `CHECK_DOUBLE_0D(shortreal_array[3][2][1]); + i_shortreal_1d(shortreal_array[2][1]); + `CHECK_DOUBLE_1D(shortreal_array[2][1]); + i_shortreal_2d(shortreal_array[1]); + `CHECK_DOUBLE_2D(shortreal_array[1]); + `endif + i_shortreal_0d(shortreal_array_0d); + `CHECK_DOUBLE_0D(shortreal_array_0d); + i_shortreal_1d(shortreal_array_1d); + `CHECK_DOUBLE_1D(shortreal_array_1d); + i_shortreal_2d(shortreal_array_2d); + `CHECK_DOUBLE_2D(shortreal_array_2d); + i_shortreal_3d(shortreal_array); + `CHECK_DOUBLE_3D(shortreal_array); +`endif + + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) + chandle_array[i][j][k] = null; +`ifndef NO_INOUT_COMPLEX_TYPE + i_chandle_0d(chandle_array[3][2][1]); + `CHECK_CHANDLE_VAL(chandle_array[3][2][1], get_non_null()); + i_chandle_1d(chandle_array[2][1]); + `CHECK_CHANDLE_VAL(chandle_array[2][1][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[2][1][1], get_non_null()); + i_chandle_2d(chandle_array[1]); + `CHECK_CHANDLE_VAL(chandle_array[1][0][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][1][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][2][1], get_non_null()); +`endif + chandle_array_0d = null; + i_chandle_0d(chandle_array_0d); + `CHECK_CHANDLE_VAL(chandle_array_0d, get_non_null()); + chandle_array_1d[0] = null; + chandle_array_1d[1] = null; + i_chandle_1d(chandle_array_1d); + `CHECK_CHANDLE_VAL(chandle_array_1d[0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array_1d[1], get_non_null()); + chandle_array_2d[0][1] = null; + chandle_array_2d[1][1] = null; + chandle_array_2d[2][1] = null; + i_chandle_2d(chandle_array_2d); + `CHECK_CHANDLE_VAL(chandle_array_2d[0][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array_2d[1][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array_2d[2][1], get_non_null()); + i_chandle_3d(chandle_array); + `CHECK_CHANDLE_VAL(chandle_array[0][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[2][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[3][0][0], get_non_null()); + +`ifndef NO_INOUT_COMPLEX_TYPE + string_array[3][2][1] = "42"; + i_string_0d(string_array[3][2][1]); + `CHECK_STRING_VAL(string_array[3][2][1], "43"); + + string_array[2][1][0] = "43"; + string_array[2][1][1] = "44"; + i_string_1d(string_array[2][1]); + `CHECK_STRING_VAL(string_array[2][1][0], "44"); + `CHECK_STRING_VAL(string_array[2][1][1], "45"); + + string_array[1][0][1] = "45"; + string_array[1][1][1] = "46"; + string_array[1][2][1] = "47"; + i_string_2d(string_array[1]); + `CHECK_STRING_VAL(string_array[1][0][1], "46"); + `CHECK_STRING_VAL(string_array[1][1][1], "47"); + `CHECK_STRING_VAL(string_array[1][2][1], "48"); +`endif + string_array_0d = "42"; + i_string_0d(string_array_0d); + `CHECK_STRING_VAL(string_array_0d, "43"); + string_array_1d[0] = "43"; + string_array_1d[1] = "44"; + i_string_1d(string_array_1d); + `CHECK_STRING_VAL(string_array_1d[0], "44"); + `CHECK_STRING_VAL(string_array_1d[1], "45"); + + string_array_2d[0][1] = "45"; + string_array_2d[1][1] = "46"; + string_array_2d[2][1] = "47"; + i_string_2d(string_array_2d); + `CHECK_STRING_VAL(string_array_2d[0][1], "46"); + `CHECK_STRING_VAL(string_array_2d[1][1], "47"); + `CHECK_STRING_VAL(string_array_2d[2][1], "48"); + + string_array[0][0][0] = "48"; + string_array[1][0][0] = "49"; + string_array[2][0][0] = "50"; + string_array[3][0][0] = "51"; + i_string_3d(string_array); + `CHECK_STRING_VAL(string_array[0][0][0], "49"); + `CHECK_STRING_VAL(string_array[1][0][0], "50"); + `CHECK_STRING_VAL(string_array[2][0][0], "51"); + `CHECK_STRING_VAL(string_array[3][0][0], "52"); + + `SET_VALUES(bit7_array); + `SET_VALUE_0D(bit7_array_0d); + `SET_VALUE_1D(bit7_array_1d); + `SET_VALUE_2D(bit7_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_bit7_0d(bit7_array[3][2][1]); + `CHECK_0D(bit7_array[3][2][1]); + i_bit7_1d(bit7_array[2][1]); + `CHECK_1D(bit7_array[2][1]); + i_bit7_2d(bit7_array[1]); + `CHECK_2D(bit7_array[1]); +`endif + i_bit7_0d(bit7_array_0d); + `CHECK_0D(bit7_array_0d); + i_bit7_1d(bit7_array_1d); + `CHECK_1D(bit7_array_1d); + i_bit7_2d(bit7_array_2d); + `CHECK_2D(bit7_array_2d); + i_bit7_3d(bit7_array); + `CHECK_3D(bit7_array); + + `SET_VALUES(bit121_array); + `SET_VALUE_0D(bit121_array_0d); + `SET_VALUE_1D(bit121_array_1d); + `SET_VALUE_2D(bit121_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_bit121_0d(bit121_array[3][2][1]); + `CHECK_0D(bit121_array[3][2][1]); + i_bit121_1d(bit121_array[2][1]); + `CHECK_1D(bit121_array[2][1]); + i_bit121_2d(bit121_array[1]); + `CHECK_2D(bit121_array[1]); +`endif + i_bit121_0d(bit121_array_0d); + `CHECK_0D(bit121_array_0d); + i_bit121_1d(bit121_array_1d); + `CHECK_1D(bit121_array_1d); + i_bit121_2d(bit121_array_2d); + `CHECK_2D(bit121_array_2d); + i_bit121_3d(bit121_array); + `CHECK_3D(bit121_array); + + `SET_VALUES(logic7_array); + `SET_VALUE_0D(logic7_array_0d); + `SET_VALUE_1D(logic7_array_1d); + `SET_VALUE_2D(logic7_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_logic7_0d(logic7_array[3][2][1]); + `CHECK_0D(logic7_array[3][2][1]); + i_logic7_1d(logic7_array[2][1]); + `CHECK_1D(logic7_array[2][1]); + i_logic7_2d(logic7_array[1]); + `CHECK_2D(logic7_array[1]); +`endif + i_logic7_0d(logic7_array_0d); + `CHECK_0D(logic7_array_0d); + i_logic7_1d(logic7_array_1d); + `CHECK_1D(logic7_array_1d); + i_logic7_2d(logic7_array_2d); + `CHECK_2D(logic7_array_2d); + i_logic7_3d(logic7_array); + `CHECK_3D(logic7_array); + + `SET_VALUES(logic121_array); + `SET_VALUE_0D(logic121_array_0d); + `SET_VALUE_1D(logic121_array_1d); + `SET_VALUE_2D(logic121_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_logic121_0d(logic121_array[3][2][1]); + `CHECK_0D(logic121_array[3][2][1]); + i_logic121_1d(logic121_array[2][1]); + `CHECK_1D(logic121_array[2][1]); + i_logic121_2d(logic121_array[1]); + `CHECK_2D(logic121_array[1]); +`endif + i_logic121_0d(logic121_array_0d); + `CHECK_0D(logic121_array_0d); + i_logic121_1d(logic121_array_1d); + `CHECK_1D(logic121_array_1d); + i_logic121_2d(logic121_array_2d); + `CHECK_2D(logic121_array_2d); + i_logic121_3d(logic121_array); + `CHECK_3D(logic121_array); + + `SET_VALUES(pack_struct_array); + `SET_VALUE_0D(pack_struct_array_0d); + `SET_VALUE_1D(pack_struct_array_1d); + `SET_VALUE_2D(pack_struct_array_2d); +`ifndef NO_INOUT_COMPLEX_TYPE + i_pack_struct_0d(pack_struct_array[3][2][1]); + `CHECK_0D(pack_struct_array[3][2][1]); + i_pack_struct_1d(pack_struct_array[2][1]); + `CHECK_1D(pack_struct_array[2][1]); + i_pack_struct_2d(pack_struct_array[1]); + `CHECK_2D(pack_struct_array[1]); +`endif + i_pack_struct_0d(pack_struct_array_0d); + `CHECK_0D(pack_struct_array_0d); + i_pack_struct_1d(pack_struct_array_1d); + `CHECK_1D(pack_struct_array_1d); + i_pack_struct_2d(pack_struct_array_2d); + `CHECK_2D(pack_struct_array_2d); + i_pack_struct_3d(pack_struct_array); + `CHECK_3D(pack_struct_array); + +`ifndef NO_UNPACK_STRUCT + unpack_struct_array[3][2][1].val = 42; + i_unpack_struct_0d(unpack_struct_array[3][2][1]); + `CHECK_VAL(unpack_struct_array[3][2][1].val, 43); + + unpack_struct_array[2][1][0].val = 43; + unpack_struct_array[2][1][1].val = 44; + i_unpack_struct_1d(unpack_struct_array[2][1]); + `CHECK_VAL(unpack_struct_array[2][1][0].val, 44); + `CHECK_VAL(unpack_struct_array[2][1][1].val, 45); + + unpack_struct_array[1][0][1].val = 45; + unpack_struct_array[1][1][1].val = 46; + unpack_struct_array[1][2][1].val = 47; + i_unpack_struct_2d(unpack_struct_array[1]); + `CHECK_VAL(unpack_struct_array[1][0][1].val, 46); + `CHECK_VAL(unpack_struct_array[1][1][1].val, 47); + `CHECK_VAL(unpack_struct_array[1][2][1].val, 48); + + unpack_struct_array[0][0][0].val = 48; + unpack_struct_array[1][0][0].val = 49; + unpack_struct_array[2][0][0].val = 50; + unpack_struct_array[3][0][0].val = 51; + i_unpack_struct_3d(unpack_struct_array); + `CHECK_VAL(unpack_struct_array[0][0][0].val, 49); + `CHECK_VAL(unpack_struct_array[1][0][0].val, 50); + `CHECK_VAL(unpack_struct_array[2][0][0].val, 51); + `CHECK_VAL(unpack_struct_array[3][0][0].val, 52); +`endif + + check_exports(); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out new file mode 100644 index 000000000..c525fa429 --- /dev/null +++ b/test_regress/t/t_dpi_arg_inout_unpack__Dpi.out @@ -0,0 +1,313 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_inout_unpack.v:529:18 + extern void e_bit121_0d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:530:18 + extern void e_bit121_1d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:531:18 + extern void e_bit121_2d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:532:18 + extern void e_bit121_3d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:524:18 + extern void e_bit7_0d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:525:18 + extern void e_bit7_1d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:526:18 + extern void e_bit7_2d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:527:18 + extern void e_bit7_3d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:395:18 + extern void e_byte_0d(char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:396:18 + extern void e_byte_1d(char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:397:18 + extern void e_byte_2d(char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:398:18 + extern void e_byte_3d(char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:400:18 + extern void e_byte_unsigned_0d(unsigned char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:401:18 + extern void e_byte_unsigned_1d(unsigned char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:402:18 + extern void e_byte_unsigned_2d(unsigned char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:403:18 + extern void e_byte_unsigned_3d(unsigned char* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:465:18 + extern void e_chandle_0d(void** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:469:18 + extern void e_chandle_1d(void** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:475:18 + extern void e_chandle_2d(void** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:483:18 + extern void e_chandle_3d(void** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:416:18 + extern void e_int_0d(int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:417:18 + extern void e_int_1d(int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:418:18 + extern void e_int_2d(int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:419:18 + extern void e_int_3d(int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:421:18 + extern void e_int_unsigned_0d(unsigned int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:422:18 + extern void e_int_unsigned_1d(unsigned int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:423:18 + extern void e_int_unsigned_2d(unsigned int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:424:18 + extern void e_int_unsigned_3d(unsigned int* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:446:18 + extern void e_integer_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:447:18 + extern void e_integer_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:448:18 + extern void e_integer_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:449:18 + extern void e_integer_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:539:18 + extern void e_logic121_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:540:18 + extern void e_logic121_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:541:18 + extern void e_logic121_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:542:18 + extern void e_logic121_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:534:18 + extern void e_logic7_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:535:18 + extern void e_logic7_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:536:18 + extern void e_logic7_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:537:18 + extern void e_logic7_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:428:18 + extern void e_longint_0d(long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:429:18 + extern void e_longint_1d(long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:430:18 + extern void e_longint_2d(long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:431:18 + extern void e_longint_3d(long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:433:18 + extern void e_longint_unsigned_0d(unsigned long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:434:18 + extern void e_longint_unsigned_1d(unsigned long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:435:18 + extern void e_longint_unsigned_2d(unsigned long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:436:18 + extern void e_longint_unsigned_3d(unsigned long long* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:544:18 + extern void e_pack_struct_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:545:18 + extern void e_pack_struct_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:546:18 + extern void e_pack_struct_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:547:18 + extern void e_pack_struct_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:452:18 + extern void e_real_0d(double* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:453:18 + extern void e_real_1d(double* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:454:18 + extern void e_real_2d(double* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:455:18 + extern void e_real_3d(double* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:405:18 + extern void e_shortint_0d(short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:406:18 + extern void e_shortint_1d(short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:407:18 + extern void e_shortint_2d(short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:408:18 + extern void e_shortint_3d(short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:410:18 + extern void e_shortint_unsigned_0d(unsigned short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:411:18 + extern void e_shortint_unsigned_1d(unsigned short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:412:18 + extern void e_shortint_unsigned_2d(unsigned short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:413:18 + extern void e_shortint_unsigned_3d(unsigned short* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:495:18 + extern void e_string_0d(const char** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:499:18 + extern void e_string_1d(const char** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:505:18 + extern void e_string_2d(const char** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:513:18 + extern void e_string_3d(const char** val); + // DPI export at t/t_dpi_arg_inout_unpack.v:439:18 + extern void e_time_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:440:18 + extern void e_time_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:441:18 + extern void e_time_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_inout_unpack.v:442:18 + extern void e_time_3d(svLogicVecVal* val); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_inout_unpack.v:584:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_inout_unpack.v:171:36 + extern void* get_non_null(); + // DPI import at t/t_dpi_arg_inout_unpack.v:254:33 + extern void i_bit121_0d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:255:33 + extern void i_bit121_1d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:256:33 + extern void i_bit121_2d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:257:33 + extern void i_bit121_3d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:249:33 + extern void i_bit7_0d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:250:33 + extern void i_bit7_1d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:251:33 + extern void i_bit7_2d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:252:33 + extern void i_bit7_3d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:173:33 + extern void i_byte_0d(char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:174:33 + extern void i_byte_1d(char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:175:33 + extern void i_byte_2d(char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:176:33 + extern void i_byte_3d(char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:178:33 + extern void i_byte_unsigned_0d(unsigned char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:179:33 + extern void i_byte_unsigned_1d(unsigned char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:180:33 + extern void i_byte_unsigned_2d(unsigned char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:181:33 + extern void i_byte_unsigned_3d(unsigned char* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:239:33 + extern void i_chandle_0d(void** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:240:33 + extern void i_chandle_1d(void** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:241:33 + extern void i_chandle_2d(void** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:242:33 + extern void i_chandle_3d(void** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:193:33 + extern void i_int_0d(int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:194:33 + extern void i_int_1d(int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:195:33 + extern void i_int_2d(int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:196:33 + extern void i_int_3d(int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:198:33 + extern void i_int_unsigned_0d(unsigned int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:199:33 + extern void i_int_unsigned_1d(unsigned int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:200:33 + extern void i_int_unsigned_2d(unsigned int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:201:33 + extern void i_int_unsigned_3d(unsigned int* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:221:33 + extern void i_integer_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:222:33 + extern void i_integer_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:223:33 + extern void i_integer_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:224:33 + extern void i_integer_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:264:33 + extern void i_logic121_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:265:33 + extern void i_logic121_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:266:33 + extern void i_logic121_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:267:33 + extern void i_logic121_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:259:33 + extern void i_logic7_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:260:33 + extern void i_logic7_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:261:33 + extern void i_logic7_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:262:33 + extern void i_logic7_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:203:33 + extern void i_longint_0d(long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:204:33 + extern void i_longint_1d(long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:205:33 + extern void i_longint_2d(long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:206:33 + extern void i_longint_3d(long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:208:33 + extern void i_longint_unsigned_0d(unsigned long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:209:33 + extern void i_longint_unsigned_1d(unsigned long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:210:33 + extern void i_longint_unsigned_2d(unsigned long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:211:33 + extern void i_longint_unsigned_3d(unsigned long long* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:269:33 + extern void i_pack_struct_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:270:33 + extern void i_pack_struct_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:271:33 + extern void i_pack_struct_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:272:33 + extern void i_pack_struct_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:227:33 + extern void i_real_0d(double* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:228:33 + extern void i_real_1d(double* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:229:33 + extern void i_real_2d(double* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:230:33 + extern void i_real_3d(double* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:183:33 + extern void i_shortint_0d(short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:184:33 + extern void i_shortint_1d(short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:185:33 + extern void i_shortint_2d(short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:186:33 + extern void i_shortint_3d(short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:188:33 + extern void i_shortint_unsigned_0d(unsigned short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:189:33 + extern void i_shortint_unsigned_1d(unsigned short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:190:33 + extern void i_shortint_unsigned_2d(unsigned short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:191:33 + extern void i_shortint_unsigned_3d(unsigned short* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:244:33 + extern void i_string_0d(const char** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:245:33 + extern void i_string_1d(const char** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:246:33 + extern void i_string_2d(const char** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:247:33 + extern void i_string_3d(const char** val); + // DPI import at t/t_dpi_arg_inout_unpack.v:214:33 + extern void i_time_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:215:33 + extern void i_time_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:216:33 + extern void i_time_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_inout_unpack.v:217:33 + extern void i_time_3d(svLogicVecVal* val); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_arg_input_unpack.cpp b/test_regress/t/t_dpi_arg_input_unpack.cpp new file mode 100644 index 000000000..695cedc6c --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_unpack.cpp @@ -0,0 +1,778 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Yutetsu TAKATSUKASA. 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 +#include +#include +#include +#include + +// clang-format off +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_input_unpack__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +typedef const void** sv_chandle_array_ptr_t; +# define NO_SHORTREAL +# define NO_UNPACK_STRUCT +# define CONSTARG const +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +typedef void** sv_chandle_array_ptr_t; +# define NO_TIME +# define CONSTARG const +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +typedef void** sv_chandle_array_ptr_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +// Sadly NC does not declare pass-by reference input arguments as const +# define CONSTARG +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +typedef const void** sv_chandle_array_ptr_t; +# define CONSTARG const +#else +# error "Unknown simulator for DPI test" +#endif +// clang-format on + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +namespace { // unnamed namespace + +const bool VERBOSE_MESSAGE = false; + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +template bool compare(const T& act, const T& exp) { + if (exp == act) { + if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + return true; + } else { + std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; + return false; + } +} + +bool compare(const svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselLogic(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +bool compare(const svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselBit(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +template bool check_0d(T v) { return compare(v, 42); } +template bool check_1d(const T* v) { + return compare(v[0], 43) && compare(v[1], 44); +} +template bool check_2d(const T* v) { + return compare(v[0 * 2 + 1], 45) && compare(v[1 * 2 + 1], 46) + && compare(v[2 * 2 + 1], 47); +} +template bool check_3d(const T* v) { + return compare(v[(0 * 3 + 0) * 2 + 0], 48) && compare(v[(1 * 3 + 0) * 2 + 0], 49) + && compare(v[(2 * 3 + 0) * 2 + 0], 50) && compare(v[(3 * 3 + 0) * 2 + 0], 51); +} + +bool check_0d(const svLogicVecVal* v, int bitwidth) { return compare(v, 42, bitwidth); } +bool check_1d(const svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * 0, 43, bitwidth) && compare(v + unit * 1, 44, bitwidth); +} +bool check_2d(const svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * (0 * 2 + 1), 45, bitwidth) + && compare(v + unit * (1 * 2 + 1), 46, bitwidth) + && compare(v + unit * (2 * 2 + 1), 47, bitwidth); +} +bool check_3d(const svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * ((0 * 3 + 0) * 2 + 0), 48, bitwidth) + && compare(v + unit * ((1 * 3 + 0) * 2 + 0), 49, bitwidth) + && compare(v + unit * ((2 * 3 + 0) * 2 + 0), 50, bitwidth) + && compare(v + unit * ((3 * 3 + 0) * 2 + 0), 51, bitwidth); +} + +bool check_0d(const svBitVecVal* v, int bitwidth) { return compare(v, 42, bitwidth); } +bool check_1d(const svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * 0, 43, bitwidth) && compare(v + unit * 1, 44, bitwidth); +} +bool check_2d(const svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * (0 * 2 + 1), 45, bitwidth) + && compare(v + unit * (1 * 2 + 1), 46, bitwidth) + && compare(v + unit * (2 * 2 + 1), 47, bitwidth); +} +bool check_3d(const svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + return compare(v + unit * ((0 * 3 + 0) * 2 + 0), 48, bitwidth) + && compare(v + unit * ((1 * 3 + 0) * 2 + 0), 49, bitwidth) + && compare(v + unit * ((2 * 3 + 0) * 2 + 0), 50, bitwidth) + && compare(v + unit * ((3 * 3 + 0) * 2 + 0), 51, bitwidth); +} + +bool check_0d(const char* v) { return compare(v, "42"); } +bool check_1d(const char** v) { + return compare(v[0], "43") && compare(v[1], "44"); +} +bool check_2d(const char** v) { + return compare(v[0 * 2 + 1], "45") && compare(v[1 * 2 + 1], "46") + && compare(v[2 * 2 + 1], "47"); +} +bool check_3d(const char** v) { + return compare(v[(0 * 3 + 0) * 2 + 0], "48") + && compare(v[(1 * 3 + 0) * 2 + 0], "49") + && compare(v[(2 * 3 + 0) * 2 + 0], "50") + && compare(v[(3 * 3 + 0) * 2 + 0], "51"); +} + +template void set_values(T (&v)[4][3][2]) { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) v[i][j][k] = 0; + v[3][2][1] = 42; + v[2][1][0] = 43; + v[2][1][1] = 44; + v[1][0][1] = 45; + v[1][1][1] = 46; + v[1][2][1] = 47; + v[0][0][0] = 48; + v[1][0][0] = 49; + v[2][0][0] = 50; + v[3][0][0] = 51; +} + +void set_uint(svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselLogic(v0, i, (val >> i) & 1); + else + svPutBitselLogic(v0, i, 0); + } +} + +void set_uint(svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselBit(v0, i, (val >> i) & 1); + else + svPutBitselBit(v0, i, 0); + } +} + +template void set_values(svLogicVecVal (&v)[4][3][2][N], int bitwidth) { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) set_uint(v[i][j][k], 0, bitwidth); + set_uint(v[3][2][1], 42, bitwidth); + + set_uint(v[2][1][0], 43, bitwidth); + set_uint(v[2][1][1], 44, bitwidth); + + set_uint(v[1][0][1], 45, bitwidth); + set_uint(v[1][1][1], 46, bitwidth); + set_uint(v[1][2][1], 47, bitwidth); + + set_uint(v[0][0][0], 48, bitwidth); + set_uint(v[1][0][0], 49, bitwidth); + set_uint(v[2][0][0], 50, bitwidth); + set_uint(v[3][0][0], 51, bitwidth); +} + +template void set_values(svBitVecVal (&v)[4][3][2][N], int bitwidth) { + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) set_uint(v[i][j][k], 0, bitwidth); + set_uint(v[3][2][1], 42, bitwidth); + + set_uint(v[2][1][0], 43, bitwidth); + set_uint(v[2][1][1], 44, bitwidth); + + set_uint(v[1][0][1], 45, bitwidth); + set_uint(v[1][1][1], 46, bitwidth); + set_uint(v[1][2][1], 47, bitwidth); + + set_uint(v[0][0][0], 48, bitwidth); + set_uint(v[1][0][0], 49, bitwidth); + set_uint(v[2][0][0], 50, bitwidth); + set_uint(v[3][0][0], 51, bitwidth); +} + +sv_chandle_array_ptr_t add_const(void** ptr) { + return static_cast(static_cast(ptr)); +} + +} // unnamed namespace + +void* get_non_null() { + static int v; + return &v; +} + +void i_byte_0d(char v) { + if (!check_0d(v)) stop(); +} +void i_byte_1d(const char* v) { + if (!check_1d(v)) stop(); +} +void i_byte_2d(const char* v) { + if (!check_2d(v)) stop(); +} +void i_byte_3d(const char* v) { + if (!check_3d(v)) stop(); +} + +void i_byte_unsigned_0d(unsigned char v) { + if (!check_0d(v)) stop(); +} +void i_byte_unsigned_1d(const unsigned char* v) { + if (!check_1d(v)) stop(); +} +void i_byte_unsigned_2d(const unsigned char* v) { + if (!check_2d(v)) stop(); +} +void i_byte_unsigned_3d(const unsigned char* v) { + if (!check_3d(v)) stop(); +} + +void i_shortint_0d(short v) { + if (!check_0d(v)) stop(); +} +void i_shortint_1d(const short* v) { + if (!check_1d(v)) stop(); +} +void i_shortint_2d(const short* v) { + if (!check_2d(v)) stop(); +} +void i_shortint_3d(const short* v) { + if (!check_3d(v)) stop(); +} + +void i_shortint_unsigned_0d(unsigned short v) { + if (!check_0d(v)) stop(); +} +void i_shortint_unsigned_1d(const unsigned short* v) { + if (!check_1d(v)) stop(); +} +void i_shortint_unsigned_2d(const unsigned short* v) { + if (!check_2d(v)) stop(); +} +void i_shortint_unsigned_3d(const unsigned short* v) { + if (!check_3d(v)) stop(); +} + +void i_int_0d(int v) { + if (!check_0d(v)) stop(); +} +void i_int_1d(const int* v) { + if (!check_1d(v)) stop(); +} +void i_int_2d(const int* v) { + if (!check_2d(v)) stop(); +} +void i_int_3d(const int* v) { + if (!check_3d(v)) stop(); +} + +void i_int_unsigned_0d(unsigned v) { + if (!check_0d(v)) stop(); +} +void i_int_unsigned_1d(const unsigned* v) { + if (!check_1d(v)) stop(); +} +void i_int_unsigned_2d(const unsigned* v) { + if (!check_2d(v)) stop(); +} +void i_int_unsigned_3d(const unsigned* v) { + if (!check_3d(v)) stop(); +} + +void i_longint_0d(sv_longint_t v) { + if (!check_0d(v)) stop(); +} +void i_longint_1d(const sv_longint_t* v) { + if (!check_1d(v)) stop(); +} +void i_longint_2d(const sv_longint_t* v) { + if (!check_2d(v)) stop(); +} +void i_longint_3d(const sv_longint_t* v) { + if (!check_3d(v)) stop(); +} + +void i_longint_unsigned_0d(sv_longint_unsigned_t v) { + if (!check_0d(v)) stop(); +} +void i_longint_unsigned_1d(const sv_longint_unsigned_t* v) { + if (!check_1d(v)) stop(); +} +void i_longint_unsigned_2d(const sv_longint_unsigned_t* v) { + if (!check_2d(v)) stop(); +} +void i_longint_unsigned_3d(const sv_longint_unsigned_t* v) { + if (!check_3d(v)) stop(); +} + +#ifndef NO_TIME +void i_time_0d(CONSTARG svLogicVecVal* v) { + if (!check_0d(v, 64)) stop(); +} +void i_time_1d(CONSTARG svLogicVecVal* v) { + if (!check_1d(v, 64)) stop(); +} +void i_time_2d(CONSTARG svLogicVecVal* v) { + if (!check_2d(v, 64)) stop(); +} +void i_time_3d(CONSTARG svLogicVecVal* v) { + if (!check_3d(v, 64)) stop(); +} +#endif + +#ifndef NO_INTEGER +void i_integer_0d(CONSTARG svLogicVecVal* v) { + if (!check_0d(v, 32)) stop(); +} +void i_integer_1d(CONSTARG svLogicVecVal* v) { + if (!check_1d(v, 32)) stop(); +} +void i_integer_2d(CONSTARG svLogicVecVal* v) { + if (!check_2d(v, 32)) stop(); +} +void i_integer_3d(CONSTARG svLogicVecVal* v) { + if (!check_3d(v, 32)) stop(); +} +#endif + +void i_real_0d(double v) { + if (!check_0d(v)) stop(); +} +void i_real_1d(CONSTARG double* v) { + if (!check_1d(v)) stop(); +} +void i_real_2d(CONSTARG double* v) { + if (!check_2d(v)) stop(); +} +void i_real_3d(CONSTARG double* v) { + if (!check_3d(v)) stop(); +} + +#ifndef NO_SHORTREAL +void i_shortreal_0d(float v) { + if (!check_0d(v)) stop(); +} +void i_shortreal_1d(CONSTARG float* v) { + if (!check_1d(v)) stop(); +} +void i_shortreal_2d(CONSTARG float* v) { + if (!check_2d(v)) stop(); +} +void i_shortreal_3d(CONSTARG float* v) { + if (!check_3d(v)) stop(); +} +#endif + +void i_chandle_0d(void* v) { + if (!v) stop(); +} +void i_chandle_1d(sv_chandle_array_ptr_t v) { + if (!v[0]) stop(); + if (!v[1]) stop(); +} +void i_chandle_2d(sv_chandle_array_ptr_t v) { + if (!v[2 * 0 + 1]) stop(); + if (!v[2 * 1 + 1]) stop(); + if (!v[2 * 2 + 1]) stop(); +} +void i_chandle_3d(sv_chandle_array_ptr_t v) { + if (!v[(0 * 3 + 0) * 2 + 0]) stop(); + if (!v[(1 * 3 + 0) * 2 + 0]) stop(); + if (!v[(2 * 3 + 0) * 2 + 0]) stop(); + if (!v[(3 * 3 + 0) * 2 + 0]) stop(); +} + +void i_string_0d(CONSTARG char* v) { + if (!check_0d(v)) stop(); +} +void i_string_1d(CONSTARG char** v) { + if (!check_1d(v)) stop(); +} +void i_string_2d(CONSTARG char** v) { + if (!check_2d(v)) stop(); +} +void i_string_3d(CONSTARG char** v) { + if (!check_3d(v)) stop(); +} + +void i_bit7_0d(CONSTARG svBitVecVal* v) { + if (!check_0d(v, 7)) stop(); +} +void i_bit7_1d(CONSTARG svBitVecVal* v) { + if (!check_1d(v, 7)) stop(); +} +void i_bit7_2d(CONSTARG svBitVecVal* v) { + if (!check_2d(v, 7)) stop(); +} +void i_bit7_3d(CONSTARG svBitVecVal* v) { + if (!check_3d(v, 7)) stop(); +} + +void i_bit121_0d(CONSTARG svBitVecVal* v) { + if (!check_0d(v, 121)) stop(); +} +void i_bit121_1d(CONSTARG svBitVecVal* v) { + if (!check_1d(v, 121)) stop(); +} +void i_bit121_2d(CONSTARG svBitVecVal* v) { + if (!check_2d(v, 121)) stop(); +} +void i_bit121_3d(CONSTARG svBitVecVal* v) { + if (!check_3d(v, 121)) stop(); +} + +void i_logic7_0d(CONSTARG svLogicVecVal* v) { + if (!check_0d(v, 7)) stop(); +} +void i_logic7_1d(CONSTARG svLogicVecVal* v) { + if (!check_1d(v, 7)) stop(); +} +void i_logic7_2d(CONSTARG svLogicVecVal* v) { + if (!check_2d(v, 7)) stop(); +} +void i_logic7_3d(CONSTARG svLogicVecVal* v) { + if (!check_3d(v, 7)) stop(); +} + +void i_logic121_0d(CONSTARG svLogicVecVal* v) { + if (!check_0d(v, 121)) stop(); +} +void i_logic121_1d(CONSTARG svLogicVecVal* v) { + if (!check_1d(v, 121)) stop(); +} +void i_logic121_2d(CONSTARG svLogicVecVal* v) { + if (!check_2d(v, 121)) stop(); +} +void i_logic121_3d(CONSTARG svLogicVecVal* v) { + if (!check_3d(v, 121)) stop(); +} + +void i_pack_struct_0d(CONSTARG svLogicVecVal* v) { + if (!check_0d(v, 7)) stop(); +} +void i_pack_struct_1d(CONSTARG svLogicVecVal* v) { + if (!check_1d(v, 7)) stop(); +} +void i_pack_struct_2d(CONSTARG svLogicVecVal* v) { + if (!check_2d(v, 7)) stop(); +} +void i_pack_struct_3d(CONSTARG svLogicVecVal* v) { + if (!check_3d(v, 7)) stop(); +} + +#ifndef NO_UNPACK_STRUCT +void i_unpack_struct_0d(CONSTARG unpack_struct_t* v) { + if (!compare(v->val, 42, 121)) stop(); +} +void i_unpack_struct_1d(CONSTARG unpack_struct_t* v) { + if (!compare(v[0].val, 43, 121)) stop(); + if (!compare(v[1].val, 44, 121)) stop(); +} +void i_unpack_struct_2d(CONSTARG unpack_struct_t* v) { + if (!compare(v[0 * 2 + 1].val, 45, 121)) stop(); + if (!compare(v[1 * 2 + 1].val, 46, 121)) stop(); + if (!compare(v[2 * 2 + 1].val, 47, 121)) stop(); +} +void i_unpack_struct_3d(CONSTARG unpack_struct_t* v) { + if (!compare(v[(0 * 3 + 0) * 2 + 0].val, 48, 121)) stop(); + if (!compare(v[(1 * 3 + 0) * 2 + 0].val, 49, 121)) stop(); + if (!compare(v[(2 * 3 + 0) * 2 + 0].val, 50, 121)) stop(); + if (!compare(v[(3 * 3 + 0) * 2 + 0].val, 51, 121)) stop(); +} +#endif + +void check_exports() { + { + char byte_array[4][3][2]; + set_values(byte_array); + e_byte_0d(byte_array[3][2][1]); + e_byte_1d(&byte_array[2][1][0]); + e_byte_2d(&byte_array[1][0][0]); + e_byte_3d(&byte_array[0][0][0]); + } + { + unsigned char byte_unsigned_array[4][3][2]; + set_values(byte_unsigned_array); + e_byte_unsigned_0d(byte_unsigned_array[3][2][1]); + e_byte_unsigned_1d(&byte_unsigned_array[2][1][0]); + e_byte_unsigned_2d(&byte_unsigned_array[1][0][0]); + e_byte_unsigned_3d(&byte_unsigned_array[0][0][0]); + } + { + short shortint_array[4][3][2]; + set_values(shortint_array); + e_shortint_0d(shortint_array[3][2][1]); + e_shortint_1d(&shortint_array[2][1][0]); + e_shortint_2d(&shortint_array[1][0][0]); + e_shortint_3d(&shortint_array[0][0][0]); + } + { + unsigned short shortint_unsigned_array[4][3][2]; + set_values(shortint_unsigned_array); + e_shortint_unsigned_0d(shortint_unsigned_array[3][2][1]); + e_shortint_unsigned_1d(&shortint_unsigned_array[2][1][0]); + e_shortint_unsigned_2d(&shortint_unsigned_array[1][0][0]); + e_shortint_unsigned_3d(&shortint_unsigned_array[0][0][0]); + } + { + int int_array[4][3][2]; + set_values(int_array); + e_int_0d(int_array[3][2][1]); + e_int_1d(&int_array[2][1][0]); + e_int_2d(&int_array[1][0][0]); + e_int_3d(&int_array[0][0][0]); + } + { + unsigned int int_unsigned_array[4][3][2]; + set_values(int_unsigned_array); + e_int_unsigned_0d(int_unsigned_array[3][2][1]); + e_int_unsigned_1d(&int_unsigned_array[2][1][0]); + e_int_unsigned_2d(&int_unsigned_array[1][0][0]); + e_int_unsigned_3d(&int_unsigned_array[0][0][0]); + } + { + sv_longint_t longint_array[4][3][2]; + set_values(longint_array); + e_longint_0d(longint_array[3][2][1]); + e_longint_1d(&longint_array[2][1][0]); + e_longint_2d(&longint_array[1][0][0]); + e_longint_3d(&longint_array[0][0][0]); + } + { + sv_longint_unsigned_t longint_unsigned_array[4][3][2]; + set_values(longint_unsigned_array); + e_longint_unsigned_0d(longint_unsigned_array[3][2][1]); + e_longint_unsigned_1d(&longint_unsigned_array[2][1][0]); + e_longint_unsigned_2d(&longint_unsigned_array[1][0][0]); + e_longint_unsigned_3d(&longint_unsigned_array[0][0][0]); + } +#ifndef NO_TIME + { + svLogicVecVal time_array[4][3][2][2]; + set_values(time_array, 64); + e_time_0d(time_array[3][2][1]); + e_time_1d(time_array[2][1][0]); + e_time_2d(&time_array[1][0][0][0]); + e_time_3d(time_array[0][0][0]); + } +#endif + +#ifndef NO_INTEGER + { + svLogicVecVal integer_array[4][3][2][1]; + set_values(integer_array, 32); + e_integer_0d(integer_array[3][2][1]); + e_integer_1d(integer_array[2][1][0]); + e_integer_2d(&integer_array[1][0][0][0]); + e_integer_3d(integer_array[0][0][0]); + } +#endif + + { + double real_array[4][3][2]; + set_values(real_array); + e_real_0d(real_array[3][2][1]); + e_real_1d(&real_array[2][1][0]); + e_real_2d(&real_array[1][0][0]); + e_real_3d(&real_array[0][0][0]); + } +#ifndef NO_SHORTREAL + { + float shortreal_array[4][3][2]; + set_values(shortreal_array); + e_shortreal_0d(shortreal_array[3][2][1]); + e_shortreal_1d(&shortreal_array[2][1][0]); + e_shortreal_2d(&shortreal_array[1][0][0]); + e_shortreal_3d(&shortreal_array[0][0][0]); + } +#endif + + { + void* chandle_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) chandle_array[i][j][k] = NULL; + chandle_array[3][2][1] = get_non_null(); + chandle_array[2][1][0] = get_non_null(); + chandle_array[2][1][1] = get_non_null(); + + chandle_array[1][0][1] = get_non_null(); + chandle_array[1][1][1] = get_non_null(); + chandle_array[1][2][1] = get_non_null(); + + chandle_array[0][0][0] = get_non_null(); + chandle_array[1][0][0] = get_non_null(); + chandle_array[2][0][0] = get_non_null(); + chandle_array[3][0][0] = get_non_null(); + + e_chandle_0d(chandle_array[3][2][1]); + e_chandle_1d(add_const(&chandle_array[2][1][0])); + e_chandle_2d(add_const(&chandle_array[1][0][0])); + e_chandle_3d(add_const(&chandle_array[0][0][0])); + } + + { + std::vector buf; + buf.resize(4 * 3 * 2 * 16, '\0'); + buf[((3 * 3 + 2) * 2 + 1) * 16 + 0] = '4'; + buf[((3 * 3 + 2) * 2 + 1) * 16 + 1] = '2'; + buf[((2 * 3 + 1) * 2 + 0) * 16 + 0] = '4'; + buf[((2 * 3 + 1) * 2 + 0) * 16 + 1] = '3'; + buf[((2 * 3 + 1) * 2 + 1) * 16 + 0] = '4'; + buf[((2 * 3 + 1) * 2 + 1) * 16 + 1] = '4'; + buf[((1 * 3 + 0) * 2 + 1) * 16 + 0] = '4'; + buf[((1 * 3 + 0) * 2 + 1) * 16 + 1] = '5'; + buf[((1 * 3 + 1) * 2 + 1) * 16 + 0] = '4'; + buf[((1 * 3 + 1) * 2 + 1) * 16 + 1] = '6'; + buf[((1 * 3 + 2) * 2 + 1) * 16 + 0] = '4'; + buf[((1 * 3 + 2) * 2 + 1) * 16 + 1] = '7'; + buf[((0 * 3 + 0) * 2 + 0) * 16 + 0] = '4'; + buf[((0 * 3 + 0) * 2 + 0) * 16 + 1] = '8'; + buf[((1 * 3 + 0) * 2 + 0) * 16 + 0] = '4'; + buf[((1 * 3 + 0) * 2 + 0) * 16 + 1] = '9'; + buf[((2 * 3 + 0) * 2 + 0) * 16 + 0] = '5'; + buf[((2 * 3 + 0) * 2 + 0) * 16 + 1] = '0'; + buf[((3 * 3 + 0) * 2 + 0) * 16 + 0] = '5'; + buf[((3 * 3 + 0) * 2 + 0) * 16 + 1] = '1'; + const char* string_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) + string_array[i][j][k] = buf.data() + ((i * 3 + j) * 2 + k) * 16; + e_string_0d(string_array[3][2][1]); + e_string_1d(&string_array[2][1][0]); + e_string_2d(&string_array[1][0][0]); + e_string_3d(&string_array[0][0][0]); + } + + { + svBitVecVal bit7_array[4][3][2][1]; + set_values(bit7_array, 7); + e_bit7_0d(bit7_array[3][2][1]); + e_bit7_1d(bit7_array[2][1][0]); + e_bit7_2d(bit7_array[1][0][0]); + e_bit7_3d(bit7_array[0][0][0]); + } + + { + svBitVecVal bit121_array[4][3][2][4]; + set_values(bit121_array, 121); + e_bit121_0d(bit121_array[3][2][1]); + e_bit121_1d(bit121_array[2][1][0]); + e_bit121_2d(bit121_array[1][0][0]); + e_bit121_3d(bit121_array[0][0][0]); + } + + { + svLogicVecVal logic7_array[4][3][2][1]; + set_values(logic7_array, 7); + e_logic7_0d(logic7_array[3][2][1]); + e_logic7_1d(logic7_array[2][1][0]); + e_logic7_2d(logic7_array[1][0][0]); + e_logic7_3d(logic7_array[0][0][0]); + } + + { + svLogicVecVal logic121_array[4][3][2][4]; + set_values(logic121_array, 121); + e_logic121_0d(logic121_array[3][2][1]); + e_logic121_1d(logic121_array[2][1][0]); + e_logic121_2d(logic121_array[1][0][0]); + e_logic121_3d(logic121_array[0][0][0]); + } + + { + svLogicVecVal pack_struct_array[4][3][2][1]; + set_values(pack_struct_array, 7); + e_pack_struct_0d(pack_struct_array[3][2][1]); + e_pack_struct_1d(pack_struct_array[2][1][0]); + e_pack_struct_2d(pack_struct_array[1][0][0]); + e_pack_struct_3d(pack_struct_array[0][0][0]); + } + +#ifndef NO_UNPACK_STRUCT + { + unpack_struct_t unpack_struct_array[4][3][2]; + set_uint(unpack_struct_array[3][2][1].val, 42, 121); + + set_uint(unpack_struct_array[2][1][0].val, 43, 121); + set_uint(unpack_struct_array[2][1][1].val, 44, 121); + + set_uint(unpack_struct_array[1][0][1].val, 45, 121); + set_uint(unpack_struct_array[1][1][1].val, 46, 121); + set_uint(unpack_struct_array[1][2][1].val, 47, 121); + + set_uint(unpack_struct_array[0][0][0].val, 48, 121); + set_uint(unpack_struct_array[1][0][0].val, 49, 121); + set_uint(unpack_struct_array[2][0][0].val, 50, 121); + set_uint(unpack_struct_array[3][0][0].val, 51, 121); + e_unpack_struct_0d(&unpack_struct_array[3][2][1]); + e_unpack_struct_1d(&unpack_struct_array[2][1][0]); + e_unpack_struct_2d(&unpack_struct_array[1][0][0]); + e_unpack_struct_3d(&unpack_struct_array[0][0][0]); + } +#endif +} diff --git a/test_regress/t/t_dpi_arg_input_unpack.pl b/test_regress/t/t_dpi_arg_input_unpack.pl new file mode 100755 index 000000000..364897b82 --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_unpack.pl @@ -0,0 +1,44 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_input_unpack.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_input_unpack__Dpi.h", + "t/t_dpi_arg_input_unpack__Dpi.out" + ); +} + +execute( + check_finished => 1, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_input_unpack.v b/test_regress/t/t_dpi_arg_input_unpack.v new file mode 100644 index 000000000..0a698e905 --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_unpack.v @@ -0,0 +1,770 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Yutetsu TAKATSUKASA. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NO_UNPACK_STRUCT + `define NULL 64'd0 +`else + `define NULL null +`endif + +`define CHECK_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":", (act), " as expected"); \ + end else begin \ + $display("Mismatch %s expected:%d actual:%d at %d", `"act`", \ + int'(exp), int'(act), `__LINE__); \ + $stop; \ + end + +`define CHECK_0D(val) `CHECK_VAL((val), 42) +`define CHECK_1D(val) `CHECK_VAL(val[0], 43); \ +`CHECK_VAL(val[1], 44) +`define CHECK_2D(val) `CHECK_VAL(val[0][1], 45); \ +`CHECK_VAL(val[1][1], 46); \ +`CHECK_VAL(val[2][1], 47) +`define CHECK_3D(val) `CHECK_VAL(val[0][0][0], 48); \ +`CHECK_VAL(val[1][0][0], 49); \ +`CHECK_VAL(val[2][0][0], 50); \ +`CHECK_VAL(val[3][0][0], 51) + +`define SET_VALUES(val) \ +val[3][2][1] = 42; \ +val[2][1][0] = 43; val[2][1][1] = 44; \ +val[1][0][1] = 45; val[1][1][1] = 46; val[1][2][1] = 47; \ +val[0][0][0] = 48; val[1][0][0] = 49; val[2][0][0] = 50; val[3][0][0] = 51 + +module t; + + localparam ENABLE_VERBOSE_MESSAGE = 0; + + // Legal input argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + typedef byte byte_array_t[4][3][2]; + typedef byte unsigned byte_unsigned_array_t[4][3][2]; + typedef shortint shortint_array_t[4][3][2]; + typedef shortint unsigned shortint_unsigned_array_t[4][3][2]; + typedef int int_array_t[4][3][2]; + typedef int unsigned int_unsigned_array_t[4][3][2]; + typedef longint longint_array_t[4][3][2]; + typedef longint unsigned longint_unsigned_array_t[4][3][2]; +`ifndef NO_TIME + typedef time time_array_t[4][3][2]; +`endif +`ifndef NO_INTEGER + typedef integer integer_array_t[4][3][2]; +`endif + typedef real real_array_t[4][3][2]; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_array_t[4][3][2]; +`endif + typedef chandle chandle_array_t[4][3][2]; + typedef string string_array_t[4][3][2]; + typedef bit [6:0] bit7_array_t[4][3][2]; + typedef bit [120:0] bit121_array_t[4][3][2]; + typedef logic [6:0] logic7_array_t[4][3][2]; + typedef logic [120:0] logic121_array_t[4][3][2]; + + typedef struct packed { + logic [6:0] val; + } pack_struct_t; + typedef pack_struct_t pack_struct_array_t[4][3][2]; +`ifndef NO_UNPACK_STRUCT + typedef struct { + logic [120:0] val; + } unpack_struct_t; + typedef unpack_struct_t unpack_struct_array_t[4][3][2]; +`endif + + //====================================================================== + // Imports + //====================================================================== + + // Returns non-null pointer + import "DPI-C" function chandle get_non_null(); + + import "DPI-C" function void i_byte_0d(input byte val); + import "DPI-C" function void i_byte_1d(input byte val[2]); + import "DPI-C" function void i_byte_2d(input byte val[3][2]); + import "DPI-C" function void i_byte_3d(input byte_array_t val); + + import "DPI-C" function void i_byte_unsigned_0d(input byte unsigned val); + import "DPI-C" function void i_byte_unsigned_1d(input byte unsigned val[2]); + import "DPI-C" function void i_byte_unsigned_2d(input byte unsigned val[3][2]); + import "DPI-C" function void i_byte_unsigned_3d(input byte_unsigned_array_t val); + + import "DPI-C" function void i_shortint_0d(input shortint val); + import "DPI-C" function void i_shortint_1d(input shortint val[2]); + import "DPI-C" function void i_shortint_2d(input shortint val[3][2]); + import "DPI-C" function void i_shortint_3d(input shortint_array_t val); + + import "DPI-C" function void i_shortint_unsigned_0d(input shortint unsigned val); + import "DPI-C" function void i_shortint_unsigned_1d(input shortint unsigned val[2]); + import "DPI-C" function void i_shortint_unsigned_2d(input shortint unsigned val[3][2]); + import "DPI-C" function void i_shortint_unsigned_3d(input shortint_unsigned_array_t val); + + import "DPI-C" function void i_int_0d(input int val); + import "DPI-C" function void i_int_1d(input int val[2]); + import "DPI-C" function void i_int_2d(input int val[3][2]); + import "DPI-C" function void i_int_3d(input int_array_t val); + + import "DPI-C" function void i_int_unsigned_0d(input int unsigned val); + import "DPI-C" function void i_int_unsigned_1d(input int unsigned val[2]); + import "DPI-C" function void i_int_unsigned_2d(input int unsigned val[3][2]); + import "DPI-C" function void i_int_unsigned_3d(input int_unsigned_array_t val); + + import "DPI-C" function void i_longint_0d(input longint val); + import "DPI-C" function void i_longint_1d(input longint val[2]); + import "DPI-C" function void i_longint_2d(input longint val[3][2]); + import "DPI-C" function void i_longint_3d(input longint_array_t val); + + import "DPI-C" function void i_longint_unsigned_0d(input longint unsigned val); + import "DPI-C" function void i_longint_unsigned_1d(input longint unsigned val[2]); + import "DPI-C" function void i_longint_unsigned_2d(input longint unsigned val[3][2]); + import "DPI-C" function void i_longint_unsigned_3d(input longint_unsigned_array_t val); + +`ifndef NO_TIME + import "DPI-C" function void i_time_0d(input time val); + import "DPI-C" function void i_time_1d(input time val[2]); + import "DPI-C" function void i_time_2d(input time val[3][2]); + import "DPI-C" function void i_time_3d(input time_array_t val); +`endif + +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_0d(input integer val); + import "DPI-C" function void i_integer_1d(input integer val[2]); + import "DPI-C" function void i_integer_2d(input integer val[3][2]); + import "DPI-C" function void i_integer_3d(input integer_array_t val); +`endif + + import "DPI-C" function void i_real_0d(input real val); + import "DPI-C" function void i_real_1d(input real val[2]); + import "DPI-C" function void i_real_2d(input real val[3][2]); + import "DPI-C" function void i_real_3d(input real_array_t val); + +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_0d(input shortreal val); + import "DPI-C" function void i_shortreal_1d(input shortreal val[2]); + import "DPI-C" function void i_shortreal_2d(input shortreal val[3][2]); + import "DPI-C" function void i_shortreal_3d(input shortreal_array_t val); +`endif + + import "DPI-C" function void i_chandle_0d(input chandle val); + import "DPI-C" function void i_chandle_1d(input chandle val[2]); + import "DPI-C" function void i_chandle_2d(input chandle val[3][2]); + import "DPI-C" function void i_chandle_3d(input chandle_array_t val); + + import "DPI-C" function void i_string_0d(input string val); + import "DPI-C" function void i_string_1d(input string val[2]); + import "DPI-C" function void i_string_2d(input string val[3][2]); + import "DPI-C" function void i_string_3d(input string_array_t val); + + import "DPI-C" function void i_bit7_0d(input bit[6:0] val); + import "DPI-C" function void i_bit7_1d(input bit[6:0] val[2]); + import "DPI-C" function void i_bit7_2d(input bit[6:0] val[3][2]); + import "DPI-C" function void i_bit7_3d(input bit7_array_t val); + + import "DPI-C" function void i_bit121_0d(input bit[120:0] val); + import "DPI-C" function void i_bit121_1d(input bit[120:0] val[2]); + import "DPI-C" function void i_bit121_2d(input bit[120:0] val[3][2]); + import "DPI-C" function void i_bit121_3d(input bit121_array_t val); + + import "DPI-C" function void i_logic7_0d(input logic[6:0] val); + import "DPI-C" function void i_logic7_1d(input logic[6:0] val[2]); + import "DPI-C" function void i_logic7_2d(input logic[6:0] val[3][2]); + import "DPI-C" function void i_logic7_3d(input logic7_array_t val); + + import "DPI-C" function void i_logic121_0d(input logic[120:0] val); + import "DPI-C" function void i_logic121_1d(input logic[120:0] val[2]); + import "DPI-C" function void i_logic121_2d(input logic[120:0] val[3][2]); + import "DPI-C" function void i_logic121_3d(input logic121_array_t val); + + import "DPI-C" function void i_pack_struct_0d(input pack_struct_t val); + import "DPI-C" function void i_pack_struct_1d(input pack_struct_t val[2]); + import "DPI-C" function void i_pack_struct_2d(input pack_struct_t val[3][2]); + import "DPI-C" function void i_pack_struct_3d(input pack_struct_array_t val); + +`ifndef NO_UNPACK_STRUCT + import "DPI-C" function void i_unpack_struct_0d(input unpack_struct_t val); + import "DPI-C" function void i_unpack_struct_1d(input unpack_struct_t val[2]); + import "DPI-C" function void i_unpack_struct_2d(input unpack_struct_t val[3][2]); + import "DPI-C" function void i_unpack_struct_3d(input unpack_struct_array_t val); +`endif + + + //====================================================================== + // Exports + //====================================================================== + + export "DPI-C" function e_byte_0d; + export "DPI-C" function e_byte_1d; + export "DPI-C" function e_byte_2d; + export "DPI-C" function e_byte_3d; + + export "DPI-C" function e_byte_unsigned_0d; + export "DPI-C" function e_byte_unsigned_1d; + export "DPI-C" function e_byte_unsigned_2d; + export "DPI-C" function e_byte_unsigned_3d; + + export "DPI-C" function e_shortint_0d; + export "DPI-C" function e_shortint_1d; + export "DPI-C" function e_shortint_2d; + export "DPI-C" function e_shortint_3d; + + export "DPI-C" function e_shortint_unsigned_0d; + export "DPI-C" function e_shortint_unsigned_1d; + export "DPI-C" function e_shortint_unsigned_2d; + export "DPI-C" function e_shortint_unsigned_3d; + + export "DPI-C" function e_int_0d; + export "DPI-C" function e_int_1d; + export "DPI-C" function e_int_2d; + export "DPI-C" function e_int_3d; + + export "DPI-C" function e_int_unsigned_0d; + export "DPI-C" function e_int_unsigned_1d; + export "DPI-C" function e_int_unsigned_2d; + export "DPI-C" function e_int_unsigned_3d; + + export "DPI-C" function e_longint_0d; + export "DPI-C" function e_longint_1d; + export "DPI-C" function e_longint_2d; + export "DPI-C" function e_longint_3d; + + export "DPI-C" function e_longint_unsigned_0d; + export "DPI-C" function e_longint_unsigned_1d; + export "DPI-C" function e_longint_unsigned_2d; + export "DPI-C" function e_longint_unsigned_3d; + +`ifndef NO_TIME + export "DPI-C" function e_time_0d; + export "DPI-C" function e_time_1d; + export "DPI-C" function e_time_2d; + export "DPI-C" function e_time_3d; +`endif + +`ifndef NO_INTEGER + export "DPI-C" function e_integer_0d; + export "DPI-C" function e_integer_1d; + export "DPI-C" function e_integer_2d; + export "DPI-C" function e_integer_3d; +`endif + + export "DPI-C" function e_real_0d; + export "DPI-C" function e_real_1d; + export "DPI-C" function e_real_2d; + export "DPI-C" function e_real_3d; + +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_0d; + export "DPI-C" function e_shortreal_1d; + export "DPI-C" function e_shortreal_2d; + export "DPI-C" function e_shortreal_3d; +`endif + + export "DPI-C" function e_chandle_0d; + export "DPI-C" function e_chandle_1d; + export "DPI-C" function e_chandle_2d; + export "DPI-C" function e_chandle_3d; + + export "DPI-C" function e_string_0d; + export "DPI-C" function e_string_1d; + export "DPI-C" function e_string_2d; + export "DPI-C" function e_string_3d; + + export "DPI-C" function e_bit7_0d; + export "DPI-C" function e_bit7_1d; + export "DPI-C" function e_bit7_2d; + export "DPI-C" function e_bit7_3d; + + export "DPI-C" function e_bit121_0d; + export "DPI-C" function e_bit121_1d; + export "DPI-C" function e_bit121_2d; + export "DPI-C" function e_bit121_3d; + + export "DPI-C" function e_logic7_0d; + export "DPI-C" function e_logic7_1d; + export "DPI-C" function e_logic7_2d; + export "DPI-C" function e_logic7_3d; + + export "DPI-C" function e_logic121_0d; + export "DPI-C" function e_logic121_1d; + export "DPI-C" function e_logic121_2d; + export "DPI-C" function e_logic121_3d; + + export "DPI-C" function e_pack_struct_0d; + export "DPI-C" function e_pack_struct_1d; + export "DPI-C" function e_pack_struct_2d; + export "DPI-C" function e_pack_struct_3d; + +`ifndef NO_UNPACK_STRUCT + export "DPI-C" function e_unpack_struct_0d; + export "DPI-C" function e_unpack_struct_1d; + export "DPI-C" function e_unpack_struct_2d; + export "DPI-C" function e_unpack_struct_3d; +`endif + + //====================================================================== + // Definitions of exported functions + //====================================================================== + function void e_byte_0d(input byte val); `CHECK_0D(val); endfunction + function void e_byte_1d(input byte val[2]); `CHECK_1D(val); endfunction + function void e_byte_2d(input byte val[3][2]); `CHECK_2D(val); endfunction + function void e_byte_3d(input byte_array_t val); `CHECK_3D(val); endfunction + + function void e_byte_unsigned_0d(input byte unsigned val); `CHECK_0D(val); endfunction + function void e_byte_unsigned_1d(input byte unsigned val[2]); `CHECK_1D(val); endfunction + function void e_byte_unsigned_2d(input byte unsigned val[3][2]); `CHECK_2D(val); endfunction + function void e_byte_unsigned_3d(input byte_unsigned_array_t val); `CHECK_3D(val); endfunction + + function void e_shortint_0d(input shortint val); `CHECK_0D(val); endfunction + function void e_shortint_1d(input shortint val[2]); `CHECK_1D(val); endfunction + function void e_shortint_2d(input shortint val[3][2]); `CHECK_2D(val); endfunction + function void e_shortint_3d(input shortint_array_t val); `CHECK_3D(val); endfunction + + function void e_shortint_unsigned_0d(input shortint unsigned val); `CHECK_0D(val); endfunction + function void e_shortint_unsigned_1d(input shortint unsigned val[2]); `CHECK_1D(val); endfunction + function void e_shortint_unsigned_2d(input shortint unsigned val[3][2]); `CHECK_2D(val); endfunction + function void e_shortint_unsigned_3d(input shortint_unsigned_array_t val); `CHECK_3D(val); endfunction + + function void e_int_0d(input int val); `CHECK_0D(val); endfunction + function void e_int_1d(input int val[2]); `CHECK_1D(val); endfunction + function void e_int_2d(input int val[3][2]); `CHECK_2D(val); endfunction + function void e_int_3d(input int_array_t val); `CHECK_3D(val); endfunction + + function void e_int_unsigned_0d(input int unsigned val); `CHECK_0D(val); endfunction + function void e_int_unsigned_1d(input int unsigned val[2]); `CHECK_1D(val); endfunction + function void e_int_unsigned_2d(input int unsigned val[3][2]); `CHECK_2D(val); endfunction + function void e_int_unsigned_3d(input int_unsigned_array_t val); `CHECK_3D(val); endfunction + + function void e_longint_0d(input longint val); `CHECK_0D(val); endfunction + function void e_longint_1d(input longint val[2]); `CHECK_1D(val); endfunction + function void e_longint_2d(input longint val[3][2]); `CHECK_2D(val); endfunction + function void e_longint_3d(input longint_array_t val); `CHECK_3D(val); endfunction + + function void e_longint_unsigned_0d(input longint unsigned val); `CHECK_0D(val); endfunction + function void e_longint_unsigned_1d(input longint unsigned val[2]); `CHECK_1D(val); endfunction + function void e_longint_unsigned_2d(input longint unsigned val[3][2]); `CHECK_2D(val); endfunction + function void e_longint_unsigned_3d(input longint_unsigned_array_t val); `CHECK_3D(val); endfunction + +`ifndef NO_TIME + function void e_time_0d(input time val); `CHECK_0D(val); endfunction + function void e_time_1d(input time val[2]); `CHECK_1D(val); endfunction + function void e_time_2d(input time val[3][2]); `CHECK_2D(val); endfunction + function void e_time_3d(input time_array_t val); `CHECK_3D(val); endfunction +`endif + +`ifndef NO_INTEGER + function void e_integer_0d(input integer val); `CHECK_0D(val); endfunction + function void e_integer_1d(input integer val[2]); `CHECK_1D(val); endfunction + function void e_integer_2d(input integer val[3][2]); `CHECK_2D(val); endfunction + function void e_integer_3d(input integer_array_t val); `CHECK_3D(val); endfunction +`endif + + function void e_real_0d(input real val); `CHECK_0D(val); endfunction + function void e_real_1d(input real val[2]); `CHECK_1D(val); endfunction + function void e_real_2d(input real val[3][2]); `CHECK_2D(val); endfunction + function void e_real_3d(input real_array_t val); `CHECK_3D(val); endfunction + +`ifndef NO_SHORTREAL + function void e_shortreal_0d(input shortreal val); `CHECK_0D(val); endfunction + function void e_shortreal_1d(input shortreal val[2]); `CHECK_1D(val); endfunction + function void e_shortreal_2d(input shortreal val[3][2]); `CHECK_2D(val); endfunction + function void e_shortreal_3d(input shortreal_array_t val); `CHECK_3D(val); endfunction +`endif + + function void e_chandle_0d(input chandle val); + if (val == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + endfunction + function void e_chandle_1d(input chandle val[2]); + if (val[0] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[1] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + endfunction + function void e_chandle_2d(input chandle val[3][2]); + if (val[0][1] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[1][1] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[2][1] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + endfunction + function void e_chandle_3d(input chandle_array_t val); + if (val[0][0][0] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[1][0][0] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[2][0][0] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + if (val[3][0][0] == null) begin + $display("Mismatch non null is expected, but not."); + $stop; + end + endfunction + + function void e_string_0d(input string val); + if (val != "42") begin + $display("Mismatch expected:%s actual:%s", "42", val); + $stop; + end + endfunction + function void e_string_1d(input string val[2]); + if (val[0] != "43") begin + $display("Mismatch expected:%s actual:%s", "43", val[0]); + $stop; + end + if (val[1] != "44") begin + $display("Mismatch expected:%s actual:%s", "44", val[1]); + $stop; + end + endfunction + function void e_string_2d(input string val[3][2]); + if (val[0][1] != "45") begin + $display("Mismatch expected:%s actual:%s", "45", val[0][1]); + $stop; + end + if (val[1][1] != "46") begin + $display("Mismatch expected:%s actual:%s", "46", val[1][1]); + $stop; + end + if (val[2][1] != "47") begin + $display("Mismatch expected:%s actual:%s", "47", val[2][1]); + $stop; + end + endfunction + function void e_string_3d(input string_array_t val); + if (val[0][0][0] != "48") begin + $display("Mismatch expected:%s actual:%s", "48", val[0][0][0]); + $stop; + end + if (val[1][0][0] != "49") begin + $display("Mismatch expected:%s actual:%s", "49", val[1][0][0]); + $stop; + end + if (val[2][0][0] != "50") begin + $display("Mismatch expected:%s actual:%s", "50", val[2][0][0]); + $stop; + end + if (val[3][0][0] != "51") begin + $display("Mismatch expected:%s actual:%s", "51", val[3][0][0]); + $stop; + end + endfunction + + function void e_bit7_0d(input bit[6:0] val); `CHECK_0D(val); endfunction + function void e_bit7_1d(input bit[6:0] val[2]); `CHECK_1D(val); endfunction + function void e_bit7_2d(input bit[6:0] val[3][2]); `CHECK_2D(val); endfunction + function void e_bit7_3d(input bit7_array_t val); `CHECK_3D(val); endfunction + + function void e_bit121_0d(input bit[120:0] val); `CHECK_0D(val); endfunction + function void e_bit121_1d(input bit[120:0] val[2]); `CHECK_1D(val); endfunction + function void e_bit121_2d(input bit[120:0] val[3][2]); `CHECK_2D(val); endfunction + function void e_bit121_3d(input bit121_array_t val); `CHECK_3D(val); endfunction + + function void e_logic7_0d(input logic[6:0] val); `CHECK_0D(val); endfunction + function void e_logic7_1d(input logic[6:0] val[2]); `CHECK_1D(val); endfunction + function void e_logic7_2d(input logic[6:0] val[3][2]); `CHECK_2D(val); endfunction + function void e_logic7_3d(input logic7_array_t val); `CHECK_3D(val); endfunction + + function void e_logic121_0d(input logic[120:0] val); `CHECK_0D(val); endfunction + function void e_logic121_1d(input logic[120:0] val[2]); `CHECK_1D(val); endfunction + function void e_logic121_2d(input logic[120:0] val[3][2]); `CHECK_2D(val); endfunction + function void e_logic121_3d(input logic121_array_t val); `CHECK_3D(val); endfunction + + function void e_pack_struct_0d(input pack_struct_t val); `CHECK_0D(val); endfunction + function void e_pack_struct_1d(input pack_struct_t val[2]); `CHECK_1D(val); endfunction + function void e_pack_struct_2d(input pack_struct_t val[3][2]); `CHECK_2D(val); endfunction + function void e_pack_struct_3d(input pack_struct_array_t val); `CHECK_3D(val); endfunction + +`ifndef NO_UNPACK_STRUCT + function void e_unpack_struct_0d(input unpack_struct_t val); + if (val.val != 42) begin + $display("Mismatch expected:%s actual:%s", "42", val.val); + $stop; + end + endfunction + function void e_unpack_struct_1d(input unpack_struct_t val[2]); + if (val[0].val != 43) begin + $display("Mismatch expected:%s actual:%s", "43", val[0].val); + $stop; + end + if (val[1].val != 44) begin + $display("Mismatch expected:%s actual:%s", "44", val[1].val); + $stop; + end + endfunction + function void e_unpack_struct_2d(input unpack_struct_t val[3][2]); + if (val[0][1].val != 45) begin + $display("Mismatch expected:%s actual:%s", "45", val[0][1].val); + $stop; + end + if (val[1][1].val != 46) begin + $display("Mismatch expected:%s actual:%s", "46", val[1][1].val); + $stop; + end + if (val[2][1].val != 47) begin + $display("Mismatch expected:%s actual:%s", "47", val[2][1].val); + $stop; + end + endfunction + function void e_unpack_struct_3d(input unpack_struct_array_t val); + if (val[0][0][0].val != 48) begin + $display("Mismatch expected:%s actual:%s", "48", val[0][0][0].val); + $stop; + end + if (val[1][0][0].val != 49) begin + $display("Mismatch expected:%s actual:%s", "49", val[1][0][0].val); + $stop; + end + if (val[2][0][0].val != 50) begin + $display("Mismatch expected:%s actual:%s", "50", val[2][0][0].val); + $stop; + end + if (val[3][0][0].val != 51) begin + $display("Mismatch expected:%s actual:%s", "51", val[3][0][0].val); + $stop; + end + endfunction +`endif + + //====================================================================== + // Invoke all imported functions + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + byte_array_t byte_array; + byte_unsigned_array_t byte_unsigned_array; + shortint_array_t shortint_array; + shortint_unsigned_array_t shortint_unsigned_array; + int_array_t int_array; + int_unsigned_array_t int_unsigned_array; + longint_array_t longint_array; + longint_unsigned_array_t longint_unsigned_array; +`ifndef NO_TIME + time_array_t time_array; +`endif +`ifndef NO_INTEGER + integer_array_t integer_array; +`endif + real_array_t real_array; +`ifndef NO_SHORTREAL + shortreal_array_t shortreal_array; +`endif + chandle_array_t chandle_array; + string_array_t string_array; + bit7_array_t bit7_array; + bit121_array_t bit121_array; + logic7_array_t logic7_array; + logic121_array_t logic121_array; + pack_struct_array_t pack_struct_array; +`ifndef NO_UNPACK_STRUCT + unpack_struct_array_t unpack_struct_array; +`endif + + `SET_VALUES(byte_array); + i_byte_0d(byte_array[3][2][1]); + i_byte_1d(byte_array[2][1]); + i_byte_2d(byte_array[1]); + i_byte_3d(byte_array); + + `SET_VALUES(byte_unsigned_array); + i_byte_unsigned_0d(byte_unsigned_array[3][2][1]); + i_byte_unsigned_1d(byte_unsigned_array[2][1]); + i_byte_unsigned_2d(byte_unsigned_array[1]); + i_byte_unsigned_3d(byte_unsigned_array); + + `SET_VALUES(shortint_array); + i_shortint_0d(shortint_array[3][2][1]); + i_shortint_1d(shortint_array[2][1]); + i_shortint_2d(shortint_array[1]); + i_shortint_3d(shortint_array); + + `SET_VALUES(shortint_unsigned_array); + i_shortint_unsigned_0d(shortint_unsigned_array[3][2][1]); + i_shortint_unsigned_1d(shortint_unsigned_array[2][1]); + i_shortint_unsigned_2d(shortint_unsigned_array[1]); + i_shortint_unsigned_3d(shortint_unsigned_array); + + `SET_VALUES(int_array); + i_int_0d(int_array[3][2][1]); + i_int_1d(int_array[2][1]); + i_int_2d(int_array[1]); + i_int_3d(int_array); + + `SET_VALUES(int_unsigned_array); + i_int_unsigned_0d(int_unsigned_array[3][2][1]); + i_int_unsigned_1d(int_unsigned_array[2][1]); + i_int_unsigned_2d(int_unsigned_array[1]); + i_int_unsigned_3d(int_unsigned_array); + + `SET_VALUES(longint_array); + i_longint_0d(longint_array[3][2][1]); + i_longint_1d(longint_array[2][1]); + i_longint_2d(longint_array[1]); + i_longint_3d(longint_array); + + `SET_VALUES(longint_unsigned_array); + i_longint_unsigned_0d(longint_unsigned_array[3][2][1]); + i_longint_unsigned_1d(longint_unsigned_array[2][1]); + i_longint_unsigned_2d(longint_unsigned_array[1]); + i_longint_unsigned_3d(longint_unsigned_array); + +`ifndef NO_TIME + `SET_VALUES(time_array); + i_time_0d(time_array[3][2][1]); + i_time_1d(time_array[2][1]); + i_time_2d(time_array[1]); + i_time_3d(time_array); +`endif + +`ifndef NO_INTEGER + `SET_VALUES(integer_array); + i_integer_0d(integer_array[3][2][1]); + i_integer_1d(integer_array[2][1]); + i_integer_2d(integer_array[1]); + i_integer_3d(integer_array); +`endif + + `SET_VALUES(real_array); + i_real_0d(real_array[3][2][1]); + i_real_1d(real_array[2][1]); + i_real_2d(real_array[1]); + i_real_3d(real_array); + +`ifndef NO_SHORTREAL + `SET_VALUES(shortreal_array); + i_shortreal_0d(shortreal_array[3][2][1]); + i_shortreal_1d(shortreal_array[2][1]); + i_shortreal_2d(shortreal_array[1]); + i_shortreal_3d(shortreal_array); +`endif + + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) + chandle_array[i][j][k] = null; + + chandle_array[3][2][1] = get_non_null(); + i_chandle_0d(chandle_array[3][2][1]); + chandle_array[2][1][0] = get_non_null(); + chandle_array[2][1][1] = get_non_null(); + i_chandle_1d(chandle_array[2][1]); + chandle_array[1][0][1] = get_non_null(); + chandle_array[1][1][1] = get_non_null(); + chandle_array[1][2][1] = get_non_null(); + i_chandle_2d(chandle_array[1]); + chandle_array[0][0][0] = get_non_null(); + chandle_array[1][0][0] = get_non_null(); + chandle_array[2][0][0] = get_non_null(); + chandle_array[3][0][0] = get_non_null(); + i_chandle_3d(chandle_array); + + string_array[3][2][1] = "42"; + string_array[2][1][0] = "43"; string_array[2][1][1] = "44"; + string_array[1][0][1] = "45"; string_array[1][1][1] = "46"; string_array[1][2][1] = "47"; + string_array[0][0][0] = "48"; string_array[1][0][0] = "49"; string_array[2][0][0] = "50"; string_array[3][0][0] = "51"; + i_string_0d(string_array[3][2][1]); + i_string_1d(string_array[2][1]); + i_string_2d(string_array[1]); + i_string_3d(string_array); + + `SET_VALUES(bit7_array); + i_bit7_0d(bit7_array[3][2][1]); + i_bit7_1d(bit7_array[2][1]); + i_bit7_2d(bit7_array[1]); + i_bit7_3d(bit7_array); + + `SET_VALUES(bit121_array); + i_bit121_0d(bit121_array[3][2][1]); + i_bit121_1d(bit121_array[2][1]); + i_bit121_2d(bit121_array[1]); + i_bit121_3d(bit121_array); + + `SET_VALUES(logic7_array); + i_logic7_0d(logic7_array[3][2][1]); + i_logic7_1d(logic7_array[2][1]); + i_logic7_2d(logic7_array[1]); + i_logic7_3d(logic7_array); + + `SET_VALUES(logic121_array); + i_logic121_0d(logic121_array[3][2][1]); + i_logic121_1d(logic121_array[2][1]); + i_logic121_2d(logic121_array[1]); + i_logic121_3d(logic121_array); + + `SET_VALUES(pack_struct_array); + i_pack_struct_0d(pack_struct_array[3][2][1]); + i_pack_struct_1d(pack_struct_array[2][1]); + i_pack_struct_2d(pack_struct_array[1]); + i_pack_struct_3d(pack_struct_array); + +`ifndef NO_UNPACK_STRUCT + unpack_struct_array[3][2][1].val = 42; + unpack_struct_array[2][1][0].val = 43; + unpack_struct_array[2][1][1].val = 44; + + unpack_struct_array[1][0][1].val = 45; + unpack_struct_array[1][1][1].val = 46; + unpack_struct_array[1][2][1].val = 47; + + unpack_struct_array[0][0][0].val = 48; + unpack_struct_array[1][0][0].val = 49; + unpack_struct_array[2][0][0].val = 50; + unpack_struct_array[3][0][0].val = 51; + i_unpack_struct_0d(unpack_struct_array[3][2][1]); + i_unpack_struct_1d(unpack_struct_array[2][1]); + i_unpack_struct_2d(unpack_struct_array[1]); + i_unpack_struct_3d(unpack_struct_array); +`endif + + check_exports(); + + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_input_unpack__Dpi.out b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out new file mode 100644 index 000000000..dd53f2061 --- /dev/null +++ b/test_regress/t/t_dpi_arg_input_unpack__Dpi.out @@ -0,0 +1,313 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_input_unpack.v:501:18 + extern void e_bit121_0d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:502:18 + extern void e_bit121_1d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:503:18 + extern void e_bit121_2d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:504:18 + extern void e_bit121_3d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:496:18 + extern void e_bit7_0d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:497:18 + extern void e_bit7_1d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:498:18 + extern void e_bit7_2d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:499:18 + extern void e_bit7_3d(const svBitVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:332:18 + extern void e_byte_0d(char val); + // DPI export at t/t_dpi_arg_input_unpack.v:333:18 + extern void e_byte_1d(const char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:334:18 + extern void e_byte_2d(const char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:335:18 + extern void e_byte_3d(const char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:337:18 + extern void e_byte_unsigned_0d(unsigned char val); + // DPI export at t/t_dpi_arg_input_unpack.v:338:18 + extern void e_byte_unsigned_1d(const unsigned char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:339:18 + extern void e_byte_unsigned_2d(const unsigned char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:340:18 + extern void e_byte_unsigned_3d(const unsigned char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:398:18 + extern void e_chandle_0d(void* val); + // DPI export at t/t_dpi_arg_input_unpack.v:404:18 + extern void e_chandle_1d(const void** val); + // DPI export at t/t_dpi_arg_input_unpack.v:414:18 + extern void e_chandle_2d(const void** val); + // DPI export at t/t_dpi_arg_input_unpack.v:428:18 + extern void e_chandle_3d(const void** val); + // DPI export at t/t_dpi_arg_input_unpack.v:352:18 + extern void e_int_0d(int val); + // DPI export at t/t_dpi_arg_input_unpack.v:353:18 + extern void e_int_1d(const int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:354:18 + extern void e_int_2d(const int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:355:18 + extern void e_int_3d(const int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:357:18 + extern void e_int_unsigned_0d(unsigned int val); + // DPI export at t/t_dpi_arg_input_unpack.v:358:18 + extern void e_int_unsigned_1d(const unsigned int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:359:18 + extern void e_int_unsigned_2d(const unsigned int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:360:18 + extern void e_int_unsigned_3d(const unsigned int* val); + // DPI export at t/t_dpi_arg_input_unpack.v:380:18 + extern void e_integer_0d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:381:18 + extern void e_integer_1d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:382:18 + extern void e_integer_2d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:383:18 + extern void e_integer_3d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:511:18 + extern void e_logic121_0d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:512:18 + extern void e_logic121_1d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:513:18 + extern void e_logic121_2d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:514:18 + extern void e_logic121_3d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:506:18 + extern void e_logic7_0d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:507:18 + extern void e_logic7_1d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:508:18 + extern void e_logic7_2d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:509:18 + extern void e_logic7_3d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:362:18 + extern void e_longint_0d(long long val); + // DPI export at t/t_dpi_arg_input_unpack.v:363:18 + extern void e_longint_1d(const long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:364:18 + extern void e_longint_2d(const long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:365:18 + extern void e_longint_3d(const long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:367:18 + extern void e_longint_unsigned_0d(unsigned long long val); + // DPI export at t/t_dpi_arg_input_unpack.v:368:18 + extern void e_longint_unsigned_1d(const unsigned long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:369:18 + extern void e_longint_unsigned_2d(const unsigned long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:370:18 + extern void e_longint_unsigned_3d(const unsigned long long* val); + // DPI export at t/t_dpi_arg_input_unpack.v:516:18 + extern void e_pack_struct_0d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:517:18 + extern void e_pack_struct_1d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:518:18 + extern void e_pack_struct_2d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:519:18 + extern void e_pack_struct_3d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:386:18 + extern void e_real_0d(double val); + // DPI export at t/t_dpi_arg_input_unpack.v:387:18 + extern void e_real_1d(const double* val); + // DPI export at t/t_dpi_arg_input_unpack.v:388:18 + extern void e_real_2d(const double* val); + // DPI export at t/t_dpi_arg_input_unpack.v:389:18 + extern void e_real_3d(const double* val); + // DPI export at t/t_dpi_arg_input_unpack.v:342:18 + extern void e_shortint_0d(short val); + // DPI export at t/t_dpi_arg_input_unpack.v:343:18 + extern void e_shortint_1d(const short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:344:18 + extern void e_shortint_2d(const short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:345:18 + extern void e_shortint_3d(const short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:347:18 + extern void e_shortint_unsigned_0d(unsigned short val); + // DPI export at t/t_dpi_arg_input_unpack.v:348:18 + extern void e_shortint_unsigned_1d(const unsigned short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:349:18 + extern void e_shortint_unsigned_2d(const unsigned short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:350:18 + extern void e_shortint_unsigned_3d(const unsigned short* val); + // DPI export at t/t_dpi_arg_input_unpack.v:447:18 + extern void e_string_0d(const char* val); + // DPI export at t/t_dpi_arg_input_unpack.v:453:18 + extern void e_string_1d(const char** val); + // DPI export at t/t_dpi_arg_input_unpack.v:463:18 + extern void e_string_2d(const char** val); + // DPI export at t/t_dpi_arg_input_unpack.v:477:18 + extern void e_string_3d(const char** val); + // DPI export at t/t_dpi_arg_input_unpack.v:373:18 + extern void e_time_0d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:374:18 + extern void e_time_1d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:375:18 + extern void e_time_2d(const svLogicVecVal* val); + // DPI export at t/t_dpi_arg_input_unpack.v:376:18 + extern void e_time_3d(const svLogicVecVal* val); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_input_unpack.v:576:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_input_unpack.v:106:36 + extern void* get_non_null(); + // DPI import at t/t_dpi_arg_input_unpack.v:189:33 + extern void i_bit121_0d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:190:33 + extern void i_bit121_1d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:191:33 + extern void i_bit121_2d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:192:33 + extern void i_bit121_3d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:184:33 + extern void i_bit7_0d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:185:33 + extern void i_bit7_1d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:186:33 + extern void i_bit7_2d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:187:33 + extern void i_bit7_3d(const svBitVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:108:33 + extern void i_byte_0d(char val); + // DPI import at t/t_dpi_arg_input_unpack.v:109:33 + extern void i_byte_1d(const char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:110:33 + extern void i_byte_2d(const char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:111:33 + extern void i_byte_3d(const char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:113:33 + extern void i_byte_unsigned_0d(unsigned char val); + // DPI import at t/t_dpi_arg_input_unpack.v:114:33 + extern void i_byte_unsigned_1d(const unsigned char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:115:33 + extern void i_byte_unsigned_2d(const unsigned char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:116:33 + extern void i_byte_unsigned_3d(const unsigned char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:174:33 + extern void i_chandle_0d(void* val); + // DPI import at t/t_dpi_arg_input_unpack.v:175:33 + extern void i_chandle_1d(const void** val); + // DPI import at t/t_dpi_arg_input_unpack.v:176:33 + extern void i_chandle_2d(const void** val); + // DPI import at t/t_dpi_arg_input_unpack.v:177:33 + extern void i_chandle_3d(const void** val); + // DPI import at t/t_dpi_arg_input_unpack.v:128:33 + extern void i_int_0d(int val); + // DPI import at t/t_dpi_arg_input_unpack.v:129:33 + extern void i_int_1d(const int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:130:33 + extern void i_int_2d(const int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:131:33 + extern void i_int_3d(const int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:133:33 + extern void i_int_unsigned_0d(unsigned int val); + // DPI import at t/t_dpi_arg_input_unpack.v:134:33 + extern void i_int_unsigned_1d(const unsigned int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:135:33 + extern void i_int_unsigned_2d(const unsigned int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:136:33 + extern void i_int_unsigned_3d(const unsigned int* val); + // DPI import at t/t_dpi_arg_input_unpack.v:156:33 + extern void i_integer_0d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:157:33 + extern void i_integer_1d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:158:33 + extern void i_integer_2d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:159:33 + extern void i_integer_3d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:199:33 + extern void i_logic121_0d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:200:33 + extern void i_logic121_1d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:201:33 + extern void i_logic121_2d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:202:33 + extern void i_logic121_3d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:194:33 + extern void i_logic7_0d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:195:33 + extern void i_logic7_1d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:196:33 + extern void i_logic7_2d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:197:33 + extern void i_logic7_3d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:138:33 + extern void i_longint_0d(long long val); + // DPI import at t/t_dpi_arg_input_unpack.v:139:33 + extern void i_longint_1d(const long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:140:33 + extern void i_longint_2d(const long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:141:33 + extern void i_longint_3d(const long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:143:33 + extern void i_longint_unsigned_0d(unsigned long long val); + // DPI import at t/t_dpi_arg_input_unpack.v:144:33 + extern void i_longint_unsigned_1d(const unsigned long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:145:33 + extern void i_longint_unsigned_2d(const unsigned long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:146:33 + extern void i_longint_unsigned_3d(const unsigned long long* val); + // DPI import at t/t_dpi_arg_input_unpack.v:204:33 + extern void i_pack_struct_0d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:205:33 + extern void i_pack_struct_1d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:206:33 + extern void i_pack_struct_2d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:207:33 + extern void i_pack_struct_3d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:162:33 + extern void i_real_0d(double val); + // DPI import at t/t_dpi_arg_input_unpack.v:163:33 + extern void i_real_1d(const double* val); + // DPI import at t/t_dpi_arg_input_unpack.v:164:33 + extern void i_real_2d(const double* val); + // DPI import at t/t_dpi_arg_input_unpack.v:165:33 + extern void i_real_3d(const double* val); + // DPI import at t/t_dpi_arg_input_unpack.v:118:33 + extern void i_shortint_0d(short val); + // DPI import at t/t_dpi_arg_input_unpack.v:119:33 + extern void i_shortint_1d(const short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:120:33 + extern void i_shortint_2d(const short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:121:33 + extern void i_shortint_3d(const short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:123:33 + extern void i_shortint_unsigned_0d(unsigned short val); + // DPI import at t/t_dpi_arg_input_unpack.v:124:33 + extern void i_shortint_unsigned_1d(const unsigned short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:125:33 + extern void i_shortint_unsigned_2d(const unsigned short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:126:33 + extern void i_shortint_unsigned_3d(const unsigned short* val); + // DPI import at t/t_dpi_arg_input_unpack.v:179:33 + extern void i_string_0d(const char* val); + // DPI import at t/t_dpi_arg_input_unpack.v:180:33 + extern void i_string_1d(const char** val); + // DPI import at t/t_dpi_arg_input_unpack.v:181:33 + extern void i_string_2d(const char** val); + // DPI import at t/t_dpi_arg_input_unpack.v:182:33 + extern void i_string_3d(const char** val); + // DPI import at t/t_dpi_arg_input_unpack.v:149:33 + extern void i_time_0d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:150:33 + extern void i_time_1d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:151:33 + extern void i_time_2d(const svLogicVecVal* val); + // DPI import at t/t_dpi_arg_input_unpack.v:152:33 + extern void i_time_3d(const svLogicVecVal* val); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_arg_output_unpack.cpp b/test_regress/t/t_dpi_arg_output_unpack.cpp new file mode 100644 index 000000000..417e29cb1 --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_unpack.cpp @@ -0,0 +1,655 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Yutetsu TAKATSUKASA. 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 +#include +#include +#include +#include + +// clang-format off +#if defined(NCSC) +// Used by NC's svdpi.h to pick up svLogicVecVal with _.aval and _.bval fields, +// rather than the IEEE 1800-2005 version which has _.a and _.b fields. +# define DPI_COMPATIBILITY_VERSION_1800v2012 +#endif + +#include "svdpi.h" + +#if defined(VERILATOR) // Verilator +# include "Vt_dpi_arg_output_unpack__Dpi.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_SHORTREAL +# define NO_UNPACK_STRUCT +# define CONSTARG const +#elif defined(VCS) // VCS +# include "../vc_hdrs.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define CONSTARG const +#elif defined(NCSC) // NC +# include "dpi-exp.h" +# include "dpi-imp.h" +typedef long long sv_longint_t; +typedef unsigned long long sv_longint_unsigned_t; +# define NO_TIME +# define NO_INTEGER +# define NO_SHORTREAL +// Sadly NC does not declare pass-by reference input arguments as const +# define CONSTARG +#elif defined(MS) // ModelSim +# include "dpi.h" +typedef int64_t sv_longint_t; +typedef uint64_t sv_longint_unsigned_t; +# define CONSTARG const +#else +# error "Unknown simulator for DPI test" +#endif +// clang-format on + +//====================================================================== +// Implementations of imported functions +//====================================================================== + +namespace { // unnamed namespace + +const bool VERBOSE_MESSAGE = false; + +#define stop() \ + do { \ + printf(__FILE__ ":%d Bad value\n", __LINE__); \ + abort(); \ + } while (0) + +void set_uint(svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselLogic(v0, i, (val >> i) & 1); + else + svPutBitselLogic(v0, i, 0); + } +} + +void set_uint(svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + if (i < 64) + svPutBitselBit(v0, i, (val >> i) & 1); + else + svPutBitselBit(v0, i, 0); + } +} + +template void set_0d(T* v) { *v = 42; } +template void set_1d(T* v) { + v[0] = 43; + v[1] = 44; +} + +template void set_2d(T* v) { + v[0 * 2 + 1] = 45; + v[1 * 2 + 1] = 46; + v[2 * 2 + 1] = 47; +} +template void set_3d(T* v) { + v[(0 * 3 + 0) * 2 + 0] = 48; + v[(1 * 3 + 0) * 2 + 0] = 49; + v[(2 * 3 + 0) * 2 + 0] = 50; + v[(3 * 3 + 0) * 2 + 0] = 51; +} + +void set_0d(svLogicVecVal* v, int bitwidth) { set_uint(v, 42, bitwidth); } + +void set_1d(svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + 0 * unit, 43, bitwidth); + set_uint(v + 1 * unit, 44, bitwidth); +} + +void set_2d(svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + (0 * 2 + 1) * unit, 45, bitwidth); + set_uint(v + (1 * 2 + 1) * unit, 46, bitwidth); + set_uint(v + (2 * 2 + 1) * unit, 47, bitwidth); +} + +void set_3d(svLogicVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + ((0 * 3 + 0) * 2 + 0) * unit, 48, bitwidth); + set_uint(v + ((1 * 3 + 0) * 2 + 0) * unit, 49, bitwidth); + set_uint(v + ((2 * 3 + 0) * 2 + 0) * unit, 50, bitwidth); + set_uint(v + ((3 * 3 + 0) * 2 + 0) * unit, 51, bitwidth); +} + +void set_0d(svBitVecVal* v, int bitwidth) { set_uint(v, 42, bitwidth); } + +void set_1d(svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + 0 * unit, 43, bitwidth); + set_uint(v + 1 * unit, 44, bitwidth); +} + +void set_2d(svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + (0 * 2 + 1) * unit, 45, bitwidth); + set_uint(v + (1 * 2 + 1) * unit, 46, bitwidth); + set_uint(v + (2 * 2 + 1) * unit, 47, bitwidth); +} + +void set_3d(svBitVecVal* v, int bitwidth) { + const int unit = (bitwidth + 31) / 32; + set_uint(v + ((0 * 3 + 0) * 2 + 0) * unit, 48, bitwidth); + set_uint(v + ((1 * 3 + 0) * 2 + 0) * unit, 49, bitwidth); + set_uint(v + ((2 * 3 + 0) * 2 + 0) * unit, 50, bitwidth); + set_uint(v + ((3 * 3 + 0) * 2 + 0) * unit, 51, bitwidth); +} + +template bool compare(const T& act, const T& exp) { + if (exp == act) { + if (VERBOSE_MESSAGE) { std::cout << "OK Exp:" << exp << " actual:" << act << std::endl; } + return true; + } else { + std::cout << "NG Exp:" << exp << " actual:" << act << std::endl; + return false; + } +} + +template bool check_0d(T v) { return compare(v, 42); } +template bool check_1d(const T (&v)[2]) { + return compare(v[0], 43) && compare(v[1], 44); +} +template bool check_2d(const T (&v)[3][2]) { + return compare(v[0][1], 45) && compare(v[1][1], 46) && compare(v[2][1], 47); +} +template bool check_3d(const T (&v)[4][3][2]) { + return compare(v[0][0][0], 48) && compare(v[1][0][0], 49) && compare(v[2][0][0], 50) + && compare(v[3][0][0], 51); +} + +bool compare(const svLogicVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselLogic(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +bool compare(const svBitVecVal* v0, sv_longint_unsigned_t val, int bitwidth) { + for (int i = 0; i < bitwidth; ++i) { + const bool act_bit = svGetBitselBit(v0, i); + const bool exp_bit = (i < 64) ? ((val >> i) & 1) : false; + if (act_bit != exp_bit) { + std::cout << "Mismatch at bit:" << i << " exp:" << exp_bit << " act:" << act_bit; + return false; + } + } + if (VERBOSE_MESSAGE) { + std::cout << "OK " << val << " as expected (width:" << bitwidth << ")" << std::endl; + } + return true; +} + +template bool check_0d(const T (&v)[N], int bitwidth) { + return compare(v, 42, bitwidth); +} +template bool check_1d(const T (&v)[2][N], int bitwidth) { + return compare(v[0], 43, bitwidth) && compare(v[1], 44, bitwidth); +} +template bool check_2d(const T (&v)[3][2][N], int bitwidth) { + return compare(v[0][1], 45, bitwidth) && compare(v[1][1], 46, bitwidth) + && compare(v[2][1], 47, bitwidth); +} +template bool check_3d(const T (&v)[4][3][2][N], int bitwidth) { + return compare(v[0][0][0], 48, bitwidth) && compare(v[1][0][0], 49, bitwidth) + && compare(v[2][0][0], 50, bitwidth) && compare(v[3][0][0], 51, bitwidth); +} + +} // unnamed namespace + +void* get_non_null() { + static int v; + return &v; +} + +void i_byte_0d(char* v) { set_0d(v); } +void i_byte_1d(char* v) { set_1d(v); } +void i_byte_2d(char* v) { set_2d(v); } +void i_byte_3d(char* v) { set_3d(v); } + +void i_byte_unsigned_0d(unsigned char* v) { set_0d(v); } +void i_byte_unsigned_1d(unsigned char* v) { set_1d(v); } +void i_byte_unsigned_2d(unsigned char* v) { set_2d(v); } +void i_byte_unsigned_3d(unsigned char* v) { set_3d(v); } + +void i_shortint_0d(short* v) { set_0d(v); } +void i_shortint_1d(short* v) { set_1d(v); } +void i_shortint_2d(short* v) { set_2d(v); } +void i_shortint_3d(short* v) { set_3d(v); } + +void i_shortint_unsigned_0d(unsigned short* v) { set_0d(v); } +void i_shortint_unsigned_1d(unsigned short* v) { set_1d(v); } +void i_shortint_unsigned_2d(unsigned short* v) { set_2d(v); } +void i_shortint_unsigned_3d(unsigned short* v) { set_3d(v); } + +void i_int_0d(int* v) { set_0d(v); } +void i_int_1d(int* v) { set_1d(v); } +void i_int_2d(int* v) { set_2d(v); } +void i_int_3d(int* v) { set_3d(v); } + +void i_int_unsigned_0d(unsigned int* v) { set_0d(v); } +void i_int_unsigned_1d(unsigned int* v) { set_1d(v); } +void i_int_unsigned_2d(unsigned int* v) { set_2d(v); } +void i_int_unsigned_3d(unsigned int* v) { set_3d(v); } + +void i_longint_0d(sv_longint_t* v) { set_0d(v); } +void i_longint_1d(sv_longint_t* v) { set_1d(v); } +void i_longint_2d(sv_longint_t* v) { set_2d(v); } +void i_longint_3d(sv_longint_t* v) { set_3d(v); } + +void i_longint_unsigned_0d(sv_longint_unsigned_t* v) { set_0d(v); } +void i_longint_unsigned_1d(sv_longint_unsigned_t* v) { set_1d(v); } +void i_longint_unsigned_2d(sv_longint_unsigned_t* v) { set_2d(v); } +void i_longint_unsigned_3d(sv_longint_unsigned_t* v) { set_3d(v); } + +#ifndef NO_TIME +void i_time_0d(svLogicVecVal* v) { set_0d(v, 64); } +void i_time_1d(svLogicVecVal* v) { set_1d(v, 64); } +void i_time_2d(svLogicVecVal* v) { set_2d(v, 64); } +void i_time_3d(svLogicVecVal* v) { set_3d(v, 64); } +#endif + +#ifndef NO_INTEGER +void i_integer_0d(svLogicVecVal* v) { set_0d(v, 32); } +void i_integer_1d(svLogicVecVal* v) { set_1d(v, 32); } +void i_integer_2d(svLogicVecVal* v) { set_2d(v, 32); } +void i_integer_3d(svLogicVecVal* v) { set_3d(v, 32); } +#endif + +void i_real_0d(double* v) { set_0d(v); } +void i_real_1d(double* v) { set_1d(v); } +void i_real_2d(double* v) { set_2d(v); } +void i_real_3d(double* v) { set_3d(v); } + +#ifndef NO_SHORTREAL +void i_shortreal_0d(float* v) { set_0d(v); } +void i_shortreal_1d(float* v) { set_1d(v); } +void i_shortreal_2d(float* v) { set_2d(v); } +void i_shortreal_3d(float* v) { set_3d(v); } +#endif + +void i_chandle_0d(void** v) { v[0] = get_non_null(); } +void i_chandle_1d(void** v) { + v[0] = get_non_null(); + v[1] = get_non_null(); +} +void i_chandle_2d(void** v) { + v[2 * 0 + 1] = get_non_null(); + v[2 * 1 + 1] = get_non_null(); + v[2 * 2 + 1] = get_non_null(); +} +void i_chandle_3d(void** v) { + v[(0 * 3 + 0) * 2 + 0] = get_non_null(); + v[(1 * 3 + 0) * 2 + 0] = get_non_null(); + v[(2 * 3 + 0) * 2 + 0] = get_non_null(); + v[(3 * 3 + 0) * 2 + 0] = get_non_null(); +} + +void i_string_0d(const char** v) { + static const char s[] = "42"; + v[0] = s; +} +void i_string_1d(const char** v) { + static const char s0[] = "43"; + static const char s1[] = "44"; + v[0] = s0; + v[1] = s1; +} +void i_string_2d(const char** v) { + static const char empty[] = ""; + static const char s0[] = "45"; + static const char s1[] = "46"; + static const char s2[] = "47"; + for (int i = 0; i < 3 * 2; ++i) v[i] = empty; + v[2 * 0 + 1] = s0; + v[2 * 1 + 1] = s1; + v[2 * 2 + 1] = s2; +} +void i_string_3d(const char** v) { + static const char empty[] = ""; + static const char s0[] = "48"; + static const char s1[] = "49"; + static const char s2[] = "50"; + static const char s3[] = "51"; + for (int i = 0; i < 4 * 3 * 2; ++i) v[i] = empty; + v[(0 * 3 + 0) * 2 + 0] = s0; + v[(1 * 3 + 0) * 2 + 0] = s1; + v[(2 * 3 + 0) * 2 + 0] = s2; + v[(3 * 3 + 0) * 2 + 0] = s3; +} + +void i_bit7_0d(svBitVecVal* v) { set_0d(v, 7); } +void i_bit7_1d(svBitVecVal* v) { set_1d(v, 7); } +void i_bit7_2d(svBitVecVal* v) { set_2d(v, 7); } +void i_bit7_3d(svBitVecVal* v) { set_3d(v, 7); } + +void i_bit121_0d(svBitVecVal* v) { set_0d(v, 121); } +void i_bit121_1d(svBitVecVal* v) { set_1d(v, 121); } +void i_bit121_2d(svBitVecVal* v) { set_2d(v, 121); } +void i_bit121_3d(svBitVecVal* v) { set_3d(v, 121); } + +void i_logic7_0d(svLogicVecVal* v) { set_0d(v, 7); } +void i_logic7_1d(svLogicVecVal* v) { set_1d(v, 7); } +void i_logic7_2d(svLogicVecVal* v) { set_2d(v, 7); } +void i_logic7_3d(svLogicVecVal* v) { set_3d(v, 7); } + +void i_logic121_0d(svLogicVecVal* v) { set_0d(v, 121); } +void i_logic121_1d(svLogicVecVal* v) { set_1d(v, 121); } +void i_logic121_2d(svLogicVecVal* v) { set_2d(v, 121); } +void i_logic121_3d(svLogicVecVal* v) { set_3d(v, 121); } + +void i_pack_struct_0d(svLogicVecVal* v) { set_0d(v, 7); } +void i_pack_struct_1d(svLogicVecVal* v) { set_1d(v, 7); } +void i_pack_struct_2d(svLogicVecVal* v) { set_2d(v, 7); } +void i_pack_struct_3d(svLogicVecVal* v) { set_3d(v, 7); } + +#ifndef NO_UNPACK_STRUCT +void i_unpack_struct_0d(unpack_struct_t* v) { set_uint(v->val, 42, 121); } +void i_unpack_struct_1d(unpack_struct_t* v) { + set_uint(v[0].val, 43, 121); + set_uint(v[1].val, 44, 121); +} +void i_unpack_struct_2d(unpack_struct_t* v) { + set_uint(v[0 * 2 + 1].val, 45, 121); + set_uint(v[1 * 2 + 1].val, 46, 121); + set_uint(v[2 * 2 + 1].val, 47, 121); +} +void i_unpack_struct_3d(unpack_struct_t* v) { + set_uint(v[(0 * 3 + 0) * 2 + 0].val, 48, 121); + set_uint(v[(1 * 3 + 0) * 2 + 0].val, 49, 121); + set_uint(v[(2 * 3 + 0) * 2 + 0].val, 50, 121); + set_uint(v[(3 * 3 + 0) * 2 + 0].val, 51, 121); +} +#endif + +void check_exports() { + { + char byte_array[4][3][2]; + e_byte_0d(&byte_array[3][2][1]); + if (!check_0d(byte_array[3][2][1])) stop(); + e_byte_1d(&byte_array[2][1][0]); + if (!check_1d(byte_array[2][1])) stop(); + e_byte_2d(&byte_array[1][0][0]); + if (!check_2d(byte_array[1])) stop(); + e_byte_3d(&byte_array[0][0][0]); + if (!check_3d(byte_array)) stop(); + } + { + unsigned char byte_unsigned_array[4][3][2]; + e_byte_unsigned_0d(&byte_unsigned_array[3][2][1]); + if (!check_0d(byte_unsigned_array[3][2][1])) stop(); + e_byte_unsigned_1d(&byte_unsigned_array[2][1][0]); + if (!check_1d(byte_unsigned_array[2][1])) stop(); + e_byte_unsigned_2d(&byte_unsigned_array[1][0][0]); + if (!check_2d(byte_unsigned_array[1])) stop(); + e_byte_unsigned_3d(&byte_unsigned_array[0][0][0]); + if (!check_3d(byte_unsigned_array)) stop(); + } + { + short shortint_array[4][3][2]; + e_shortint_0d(&shortint_array[3][2][1]); + if (!check_0d(shortint_array[3][2][1])) stop(); + e_shortint_1d(&shortint_array[2][1][0]); + if (!check_1d(shortint_array[2][1])) stop(); + e_shortint_2d(&shortint_array[1][0][0]); + if (!check_2d(shortint_array[1])) stop(); + e_shortint_3d(&shortint_array[0][0][0]); + if (!check_3d(shortint_array)) stop(); + } + { + unsigned short shortint_unsigned_array[4][3][2]; + e_shortint_unsigned_0d(&shortint_unsigned_array[3][2][1]); + if (!check_0d(shortint_unsigned_array[3][2][1])) stop(); + e_shortint_unsigned_1d(&shortint_unsigned_array[2][1][0]); + if (!check_1d(shortint_unsigned_array[2][1])) stop(); + e_shortint_unsigned_2d(&shortint_unsigned_array[1][0][0]); + if (!check_2d(shortint_unsigned_array[1])) stop(); + e_shortint_unsigned_3d(&shortint_unsigned_array[0][0][0]); + if (!check_3d(shortint_unsigned_array)) stop(); + } + + { + int int_array[4][3][2]; + e_int_0d(&int_array[3][2][1]); + if (!check_0d(int_array[3][2][1])) stop(); + e_int_1d(&int_array[2][1][0]); + if (!check_1d(int_array[2][1])) stop(); + e_int_2d(&int_array[1][0][0]); + if (!check_2d(int_array[1])) stop(); + e_int_3d(&int_array[0][0][0]); + if (!check_3d(int_array)) stop(); + } + { + unsigned int int_unsigned_array[4][3][2]; + e_int_unsigned_0d(&int_unsigned_array[3][2][1]); + if (!check_0d(int_unsigned_array[3][2][1])) stop(); + e_int_unsigned_1d(&int_unsigned_array[2][1][0]); + if (!check_1d(int_unsigned_array[2][1])) stop(); + e_int_unsigned_2d(&int_unsigned_array[1][0][0]); + if (!check_2d(int_unsigned_array[1])) stop(); + e_int_unsigned_3d(&int_unsigned_array[0][0][0]); + if (!check_3d(int_unsigned_array)) stop(); + } + + { + sv_longint_t longint_array[4][3][2]; + e_longint_0d(&longint_array[3][2][1]); + if (!check_0d(longint_array[3][2][1])) stop(); + e_longint_1d(&longint_array[2][1][0]); + if (!check_1d(longint_array[2][1])) stop(); + e_longint_2d(&longint_array[1][0][0]); + if (!check_2d(longint_array[1])) stop(); + e_longint_3d(&longint_array[0][0][0]); + if (!check_3d(longint_array)) stop(); + } + { + sv_longint_unsigned_t longint_unsigned_array[4][3][2]; + e_longint_unsigned_0d(&longint_unsigned_array[3][2][1]); + if (!check_0d(longint_unsigned_array[3][2][1])) stop(); + e_longint_unsigned_1d(&longint_unsigned_array[2][1][0]); + if (!check_1d(longint_unsigned_array[2][1])) stop(); + e_longint_unsigned_2d(&longint_unsigned_array[1][0][0]); + if (!check_2d(longint_unsigned_array[1])) stop(); + e_longint_unsigned_3d(&longint_unsigned_array[0][0][0]); + if (!check_3d(longint_unsigned_array)) stop(); + } + +#ifndef NO_TIME + { + svLogicVecVal time_array[4][3][2][2]; + e_time_0d(time_array[3][2][1]); + if (!check_0d(time_array[3][2][1], 64)) stop(); + e_time_1d(time_array[2][1][0]); + if (!check_1d(time_array[2][1], 64)) stop(); + e_time_2d(time_array[1][0][0]); + if (!check_2d(time_array[1], 64)) stop(); + e_time_3d(time_array[0][0][0]); + if (!check_3d(time_array, 64)) stop(); + } +#endif + +#ifndef NO_INTEGER + { + svLogicVecVal integer_array[4][3][2][1]; + e_integer_0d(integer_array[3][2][1]); + if (!check_0d(integer_array[3][2][1], 32)) stop(); + e_integer_1d(integer_array[2][1][0]); + if (!check_1d(integer_array[2][1], 32)) stop(); + e_integer_2d(integer_array[1][0][0]); + if (!check_2d(integer_array[1], 32)) stop(); + e_integer_3d(integer_array[0][0][0]); + if (!check_3d(integer_array, 32)) stop(); + } +#endif + + { + double real_array[4][3][2]; + e_real_0d(&real_array[3][2][1]); + if (!check_0d(real_array[3][2][1])) stop(); + e_real_1d(&real_array[2][1][0]); + if (!check_1d(real_array[2][1])) stop(); + e_real_2d(&real_array[1][0][0]); + if (!check_2d(real_array[1])) stop(); + e_real_3d(&real_array[0][0][0]); + if (!check_3d(real_array)) stop(); + } +#ifndef NO_SHORTREAL + { + float shortreal_array[4][3][2]; + e_shortreal_0d(&shortreal_array[3][2][1]); + if (!check_0d(shortreal_array[3][2][1])) stop(); + e_shortreal_1d(&shortreal_array[2][1][0]); + if (!check_1d(shortreal_array[2][1])) stop(); + e_shortreal_2d(&shortreal_array[1][0][0]); + if (!check_2d(shortreal_array[1])) stop(); + e_shortreal_3d(&shortreal_array[0][0][0]); + if (!check_3d(shortreal_array)) stop(); + } +#endif + + { + void* chandle_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) chandle_array[i][j][k] = NULL; + e_chandle_0d(&chandle_array[3][2][1]); + if (!chandle_array[3][2][1]) stop(); + e_chandle_1d(&chandle_array[2][1][0]); + if (!chandle_array[2][1][0]) stop(); + if (!chandle_array[2][1][1]) stop(); + e_chandle_2d(&chandle_array[1][0][0]); + if (!chandle_array[1][0][1]) stop(); + if (!chandle_array[1][1][1]) stop(); + if (!chandle_array[1][2][1]) stop(); + e_chandle_3d(&chandle_array[0][0][0]); + if (!chandle_array[0][0][0]) stop(); + if (!chandle_array[1][0][0]) stop(); + if (!chandle_array[2][0][0]) stop(); + if (!chandle_array[3][0][0]) stop(); + } + + { + const char* string_array[4][3][2]; + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) string_array[i][j][k] = NULL; + e_string_0d(&string_array[3][2][1]); + if (!compare(string_array[3][2][1], "42")) stop(); + e_string_1d(&string_array[2][1][0]); + if (!compare(string_array[2][1][0], "43")) stop(); + if (!compare(string_array[2][1][1], "44")) stop(); + e_string_2d(&string_array[1][0][0]); + if (!compare(string_array[1][0][1], "45")) stop(); + if (!compare(string_array[1][1][1], "46")) stop(); + if (!compare(string_array[1][2][1], "47")) stop(); + e_string_3d(&string_array[0][0][0]); + if (!compare(string_array[0][0][0], "48")) stop(); + if (!compare(string_array[1][0][0], "49")) stop(); + if (!compare(string_array[2][0][0], "50")) stop(); + if (!compare(string_array[3][0][0], "51")) stop(); + } + + { + svBitVecVal bit7_array[4][3][2][1]; + e_bit7_0d(bit7_array[3][2][1]); + if (!check_0d(bit7_array[3][2][1], 7)) stop(); + e_bit7_1d(bit7_array[2][1][0]); + if (!check_1d(bit7_array[2][1], 7)) stop(); + e_bit7_2d(bit7_array[1][0][0]); + if (!check_2d(bit7_array[1], 7)) stop(); + e_bit7_3d(bit7_array[0][0][0]); + if (!check_3d(bit7_array, 7)) stop(); + } + + { + svBitVecVal bit121_array[4][3][2][4]; + e_bit121_0d(bit121_array[3][2][1]); + if (!check_0d(bit121_array[3][2][1], 121)) stop(); + e_bit121_1d(bit121_array[2][1][0]); + if (!check_1d(bit121_array[2][1], 121)) stop(); + e_bit121_2d(bit121_array[1][0][0]); + if (!check_2d(bit121_array[1], 121)) stop(); + e_bit121_3d(bit121_array[0][0][0]); + if (!check_3d(bit121_array, 121)) stop(); + } + { + svLogicVecVal logic7_array[4][3][2][1]; + e_logic7_0d(logic7_array[3][2][1]); + if (!check_0d(logic7_array[3][2][1], 7)) stop(); + e_logic7_1d(logic7_array[2][1][0]); + if (!check_1d(logic7_array[2][1], 7)) stop(); + e_logic7_2d(logic7_array[1][0][0]); + if (!check_2d(logic7_array[1], 7)) stop(); + e_logic7_3d(logic7_array[0][0][0]); + if (!check_3d(logic7_array, 7)) stop(); + } + + { + svLogicVecVal logic121_array[4][3][2][4]; + e_logic121_0d(logic121_array[3][2][1]); + if (!check_0d(logic121_array[3][2][1], 121)) stop(); + e_logic121_1d(logic121_array[2][1][0]); + if (!check_1d(logic121_array[2][1], 121)) stop(); + e_logic121_2d(logic121_array[1][0][0]); + if (!check_2d(logic121_array[1], 121)) stop(); + e_logic121_3d(logic121_array[0][0][0]); + if (!check_3d(logic121_array, 121)) stop(); + } + + { + svLogicVecVal pack_struct_array[4][3][2][1]; + e_pack_struct_0d(pack_struct_array[3][2][1]); + if (!check_0d(pack_struct_array[3][2][1], 7)) stop(); + e_pack_struct_1d(pack_struct_array[2][1][0]); + if (!check_1d(pack_struct_array[2][1], 7)) stop(); + e_pack_struct_2d(pack_struct_array[1][0][0]); + if (!check_2d(pack_struct_array[1], 7)) stop(); + e_pack_struct_3d(pack_struct_array[0][0][0]); + if (!check_3d(pack_struct_array, 7)) stop(); + } + +#ifndef NO_UNPACK_STRUCT + { + unpack_struct_t unpack_struct_array[4][3][2]; + e_unpack_struct_0d(&unpack_struct_array[3][2][1]); + if (!compare(unpack_struct_array[3][2][1].val, 42, 121)) stop(); + e_unpack_struct_1d(&unpack_struct_array[2][1][0]); + if (!compare(unpack_struct_array[2][1][0].val, 43, 121)) stop(); + if (!compare(unpack_struct_array[2][1][1].val, 44, 121)) stop(); + e_unpack_struct_2d(&unpack_struct_array[1][0][0]); + if (!compare(unpack_struct_array[1][0][1].val, 45, 121)) stop(); + if (!compare(unpack_struct_array[1][1][1].val, 46, 121)) stop(); + if (!compare(unpack_struct_array[1][2][1].val, 47, 121)) stop(); + e_unpack_struct_3d(&unpack_struct_array[0][0][0]); + if (!compare(unpack_struct_array[0][0][0].val, 48, 121)) stop(); + if (!compare(unpack_struct_array[1][0][0].val, 49, 121)) stop(); + if (!compare(unpack_struct_array[2][0][0].val, 50, 121)) stop(); + if (!compare(unpack_struct_array[3][0][0].val, 51, 121)) stop(); + } +#endif +} diff --git a/test_regress/t/t_dpi_arg_output_unpack.pl b/test_regress/t/t_dpi_arg_output_unpack.pl new file mode 100755 index 000000000..4a2f325ab --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_unpack.pl @@ -0,0 +1,44 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2020 by Geza Lore. This program is free software; you can +# redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +if ($Self->{nc}) { + # For NC, compile twice, first just to generate DPI headers + compile( + nc_flags2 => ["+ncdpiheader+$Self->{obj_dir}/dpi-exp.h", + "+ncdpiimpheader+$Self->{obj_dir}/dpi-imp.h"] + ); +} + +compile( + v_flags2 => ["t/t_dpi_arg_output_unpack.cpp"], + verilator_flags2 => ["-Wall -Wno-DECLFILENAME"], + # NC: Gdd the obj_dir to the C include path + nc_flags2 => ["+ncscargs+-I$Self->{obj_dir}"], + # ModelSim: Generate DPI header, add obj_dir to the C include path + ms_flags2 => ["-dpiheader $Self->{obj_dir}/dpi.h", + "-ccflags -I$Self->{obj_dir}"], + ); + +if ($Self->{vlt_all}) { + files_identical( + "$Self->{obj_dir}/Vt_dpi_arg_output_unpack__Dpi.h", + "t/t_dpi_arg_output_unpack__Dpi.out" + ); +} + +execute( + check_finished => 1, + ms_pli => 0 + ); + +ok(1); +1; diff --git a/test_regress/t/t_dpi_arg_output_unpack.v b/test_regress/t/t_dpi_arg_output_unpack.v new file mode 100644 index 000000000..f2fbcd7ee --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_unpack.v @@ -0,0 +1,761 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Yutetsu TAKATSUKASA. This program is free software; you can +// redistribute it and/or modify it under the terms of either the GNU +// Lesser General Public License Version 3 or the Perl Artistic License +// Version 2.0. +// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +`ifdef VCS + `define NO_TIME +`endif + +`ifdef NC + `define NO_TIME + `define NO_INTEGER + `define NO_SHORTREAL +`endif + +`ifdef MS +`endif + +`ifdef VERILATOR + `define NO_SHORTREAL + `define NO_UNPACK_STRUCT + `define NULL 64'd0 +`else + `define NULL null +`endif + +`define CHECK_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":", (act), " as expected"); \ + end else begin \ + $display("Mismatch %s expected:%d actual:%d at %d", `"act`", \ + int'(exp), \ + int'(act), `__LINE__); \ + $stop; \ + end + +`define CHECK_0D(val) `CHECK_VAL((val), 42) +`define CHECK_1D(val) `CHECK_VAL(val[0], 43); \ +`CHECK_VAL(val[1], 44) +`define CHECK_2D(val) `CHECK_VAL(val[0][1], 45); \ +`CHECK_VAL(val[1][1], 46); \ +`CHECK_VAL(val[2][1], 47) +`define CHECK_3D(val) `CHECK_VAL(val[0][0][0], 48); \ +`CHECK_VAL(val[1][0][0], 49); \ +`CHECK_VAL(val[2][0][0], 50); \ +`CHECK_VAL(val[3][0][0], 51) + +`define CHECK_CHANDLE_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":non-null as expected"); \ + end else begin \ + $display("Mismatch %s expected:%s but %s at %d", `"act`", \ + (exp) ? "null" : "non-null", (act) ? "null" : "non-null", `__LINE__); \ + $stop; \ + end + +`define CHECK_STRING_VAL(act, exp) if ((act) == (exp)) begin \ + if (ENABLE_VERBOSE_MESSAGE)$display(`"act`", ":", (act), " as expected"); \ + end else begin \ + $display("Mismatch %s expected:%s actual:%s at %d", \ + `"act`", (exp), (act), `__LINE__); \ + $stop; \ + end + +`define SET_VALUES(val) \ +val[3][2][1] = 42; \ +val[2][1][0] = 43; val[2][1][1] = 44; \ +val[1][0][1] = 45; val[1][1][1] = 46; val[1][2][1] = 47; \ +val[0][0][0] = 48; val[1][0][0] = 49; val[2][0][0] = 50; val[3][0][0] = 51 + +module t; + + localparam ENABLE_VERBOSE_MESSAGE = 0; + + // Legal output argument types for DPI functions + + //====================================================================== + // Type definitions + //====================================================================== + + typedef byte byte_array_t[4][3][2]; + typedef byte unsigned byte_unsigned_array_t[4][3][2]; + typedef shortint shortint_array_t[4][3][2]; + typedef shortint unsigned shortint_unsigned_array_t[4][3][2]; + typedef int int_array_t[4][3][2]; + typedef int unsigned int_unsigned_array_t[4][3][2]; + typedef longint longint_array_t[4][3][2]; + typedef longint unsigned longint_unsigned_array_t[4][3][2]; +`ifndef NO_TIME + typedef time time_array_t[4][3][2]; +`endif +`ifndef NO_INTEGER + typedef integer integer_array_t[4][3][2]; +`endif + typedef real real_array_t[4][3][2]; +`ifndef NO_SHORTREAL + typedef shortreal shortreal_array_t[4][3][2]; +`endif + typedef chandle chandle_array_t[4][3][2]; + typedef string string_array_t[4][3][2]; + typedef bit [6:0] bit7_array_t[4][3][2]; + typedef bit [120:0] bit121_array_t[4][3][2]; + typedef logic [6:0] logic7_array_t[4][3][2]; + typedef logic [120:0] logic121_array_t[4][3][2]; + + typedef struct packed { + logic [6:0] val; + } pack_struct_t; + typedef pack_struct_t pack_struct_array_t[4][3][2]; +`ifndef NO_UNPACK_STRUCT + typedef struct { + logic [120:0] val; + } unpack_struct_t; + typedef unpack_struct_t unpack_struct_array_t[4][3][2]; +`endif + + //====================================================================== + // Imports + //====================================================================== + + // Returns non-null pointer + import "DPI-C" function chandle get_non_null(); + + import "DPI-C" function void i_byte_0d(output byte val); + import "DPI-C" function void i_byte_1d(output byte val[2]); + import "DPI-C" function void i_byte_2d(output byte val[3][2]); + import "DPI-C" function void i_byte_3d(output byte_array_t val); + + import "DPI-C" function void i_byte_unsigned_0d(output byte unsigned val); + import "DPI-C" function void i_byte_unsigned_1d(output byte unsigned val[2]); + import "DPI-C" function void i_byte_unsigned_2d(output byte unsigned val[3][2]); + import "DPI-C" function void i_byte_unsigned_3d(output byte_unsigned_array_t val); + + import "DPI-C" function void i_shortint_0d(output shortint val); + import "DPI-C" function void i_shortint_1d(output shortint val[2]); + import "DPI-C" function void i_shortint_2d(output shortint val[3][2]); + import "DPI-C" function void i_shortint_3d(output shortint_array_t val); + + import "DPI-C" function void i_shortint_unsigned_0d(output shortint unsigned val); + import "DPI-C" function void i_shortint_unsigned_1d(output shortint unsigned val[2]); + import "DPI-C" function void i_shortint_unsigned_2d(output shortint unsigned val[3][2]); + import "DPI-C" function void i_shortint_unsigned_3d(output shortint_unsigned_array_t val); + + import "DPI-C" function void i_int_0d(output int val); + import "DPI-C" function void i_int_1d(output int val[2]); + import "DPI-C" function void i_int_2d(output int val[3][2]); + import "DPI-C" function void i_int_3d(output int_array_t val); + + import "DPI-C" function void i_int_unsigned_0d(output int unsigned val); + import "DPI-C" function void i_int_unsigned_1d(output int unsigned val[2]); + import "DPI-C" function void i_int_unsigned_2d(output int unsigned val[3][2]); + import "DPI-C" function void i_int_unsigned_3d(output int_unsigned_array_t val); + + import "DPI-C" function void i_longint_0d(output longint val); + import "DPI-C" function void i_longint_1d(output longint val[2]); + import "DPI-C" function void i_longint_2d(output longint val[3][2]); + import "DPI-C" function void i_longint_3d(output longint_array_t val); + + import "DPI-C" function void i_longint_unsigned_0d(output longint unsigned val); + import "DPI-C" function void i_longint_unsigned_1d(output longint unsigned val[2]); + import "DPI-C" function void i_longint_unsigned_2d(output longint unsigned val[3][2]); + import "DPI-C" function void i_longint_unsigned_3d(output longint_unsigned_array_t val); + +`ifndef NO_TIME + import "DPI-C" function void i_time_0d(output time val); + import "DPI-C" function void i_time_1d(output time val[2]); + import "DPI-C" function void i_time_2d(output time val[3][2]); + import "DPI-C" function void i_time_3d(output time_array_t val); +`endif + +`ifndef NO_INTEGER + import "DPI-C" function void i_integer_0d(output integer val); + import "DPI-C" function void i_integer_1d(output integer val[2]); + import "DPI-C" function void i_integer_2d(output integer val[3][2]); + import "DPI-C" function void i_integer_3d(output integer_array_t val); +`endif + + import "DPI-C" function void i_real_0d(output real val); + import "DPI-C" function void i_real_1d(output real val[2]); + import "DPI-C" function void i_real_2d(output real val[3][2]); + import "DPI-C" function void i_real_3d(output real_array_t val); + +`ifndef NO_SHORTREAL + import "DPI-C" function void i_shortreal_0d(output shortreal val); + import "DPI-C" function void i_shortreal_1d(output shortreal val[2]); + import "DPI-C" function void i_shortreal_2d(output shortreal val[3][2]); + import "DPI-C" function void i_shortreal_3d(output shortreal_array_t val); +`endif + + import "DPI-C" function void i_chandle_0d(output chandle val); + import "DPI-C" function void i_chandle_1d(output chandle val[2]); + import "DPI-C" function void i_chandle_2d(output chandle val[3][2]); + import "DPI-C" function void i_chandle_3d(output chandle_array_t val); + + import "DPI-C" function void i_string_0d(output string val); + import "DPI-C" function void i_string_1d(output string val[2]); + import "DPI-C" function void i_string_2d(output string val[3][2]); + import "DPI-C" function void i_string_3d(output string_array_t val); + + import "DPI-C" function void i_bit7_0d(output bit[6:0] val); + import "DPI-C" function void i_bit7_1d(output bit[6:0] val[2]); + import "DPI-C" function void i_bit7_2d(output bit[6:0] val[3][2]); + import "DPI-C" function void i_bit7_3d(output bit7_array_t val); + + import "DPI-C" function void i_bit121_0d(output bit[120:0] val); + import "DPI-C" function void i_bit121_1d(output bit[120:0] val[2]); + import "DPI-C" function void i_bit121_2d(output bit[120:0] val[3][2]); + import "DPI-C" function void i_bit121_3d(output bit121_array_t val); + + import "DPI-C" function void i_logic7_0d(output logic[6:0] val); + import "DPI-C" function void i_logic7_1d(output logic[6:0] val[2]); + import "DPI-C" function void i_logic7_2d(output logic[6:0] val[3][2]); + import "DPI-C" function void i_logic7_3d(output logic7_array_t val); + + import "DPI-C" function void i_logic121_0d(output logic[120:0] val); + import "DPI-C" function void i_logic121_1d(output logic[120:0] val[2]); + import "DPI-C" function void i_logic121_2d(output logic[120:0] val[3][2]); + import "DPI-C" function void i_logic121_3d(output logic121_array_t val); + + import "DPI-C" function void i_pack_struct_0d(output pack_struct_t val); + import "DPI-C" function void i_pack_struct_1d(output pack_struct_t val[2]); + import "DPI-C" function void i_pack_struct_2d(output pack_struct_t val[3][2]); + import "DPI-C" function void i_pack_struct_3d(output pack_struct_array_t val); + +`ifndef NO_UNPACK_STRUCT + import "DPI-C" function void i_unpack_struct_0d(output unpack_struct_t val); + import "DPI-C" function void i_unpack_struct_1d(output unpack_struct_t val[2]); + import "DPI-C" function void i_unpack_struct_2d(output unpack_struct_t val[3][2]); + import "DPI-C" function void i_unpack_struct_3d(output unpack_struct_array_t val); +`endif + + //====================================================================== + // Exports + //====================================================================== + export "DPI-C" function e_byte_0d; + export "DPI-C" function e_byte_1d; + export "DPI-C" function e_byte_2d; + export "DPI-C" function e_byte_3d; + + export "DPI-C" function e_byte_unsigned_0d; + export "DPI-C" function e_byte_unsigned_1d; + export "DPI-C" function e_byte_unsigned_2d; + export "DPI-C" function e_byte_unsigned_3d; + + export "DPI-C" function e_shortint_0d; + export "DPI-C" function e_shortint_1d; + export "DPI-C" function e_shortint_2d; + export "DPI-C" function e_shortint_3d; + + export "DPI-C" function e_shortint_unsigned_0d; + export "DPI-C" function e_shortint_unsigned_1d; + export "DPI-C" function e_shortint_unsigned_2d; + export "DPI-C" function e_shortint_unsigned_3d; + + export "DPI-C" function e_int_0d; + export "DPI-C" function e_int_1d; + export "DPI-C" function e_int_2d; + export "DPI-C" function e_int_3d; + + export "DPI-C" function e_int_unsigned_0d; + export "DPI-C" function e_int_unsigned_1d; + export "DPI-C" function e_int_unsigned_2d; + export "DPI-C" function e_int_unsigned_3d; + + export "DPI-C" function e_longint_0d; + export "DPI-C" function e_longint_1d; + export "DPI-C" function e_longint_2d; + export "DPI-C" function e_longint_3d; + + export "DPI-C" function e_longint_unsigned_0d; + export "DPI-C" function e_longint_unsigned_1d; + export "DPI-C" function e_longint_unsigned_2d; + export "DPI-C" function e_longint_unsigned_3d; + +`ifndef NO_TIME + export "DPI-C" function e_time_0d; + export "DPI-C" function e_time_1d; + export "DPI-C" function e_time_2d; + export "DPI-C" function e_time_3d; +`endif + +`ifndef NO_INTEGER + export "DPI-C" function e_integer_0d; + export "DPI-C" function e_integer_1d; + export "DPI-C" function e_integer_2d; + export "DPI-C" function e_integer_3d; +`endif + + export "DPI-C" function e_real_0d; + export "DPI-C" function e_real_1d; + export "DPI-C" function e_real_2d; + export "DPI-C" function e_real_3d; + +`ifndef NO_SHORTREAL + export "DPI-C" function e_shortreal_0d; + export "DPI-C" function e_shortreal_1d; + export "DPI-C" function e_shortreal_2d; + export "DPI-C" function e_shortreal_3d; +`endif + + export "DPI-C" function e_chandle_0d; + export "DPI-C" function e_chandle_1d; + export "DPI-C" function e_chandle_2d; + export "DPI-C" function e_chandle_3d; + + export "DPI-C" function e_string_0d; + export "DPI-C" function e_string_1d; + export "DPI-C" function e_string_2d; + export "DPI-C" function e_string_3d; + + export "DPI-C" function e_bit7_0d; + export "DPI-C" function e_bit7_1d; + export "DPI-C" function e_bit7_2d; + export "DPI-C" function e_bit7_3d; + + export "DPI-C" function e_bit121_0d; + export "DPI-C" function e_bit121_1d; + export "DPI-C" function e_bit121_2d; + export "DPI-C" function e_bit121_3d; + + export "DPI-C" function e_logic7_0d; + export "DPI-C" function e_logic7_1d; + export "DPI-C" function e_logic7_2d; + export "DPI-C" function e_logic7_3d; + + export "DPI-C" function e_logic121_0d; + export "DPI-C" function e_logic121_1d; + export "DPI-C" function e_logic121_2d; + export "DPI-C" function e_logic121_3d; + + export "DPI-C" function e_pack_struct_0d; + export "DPI-C" function e_pack_struct_1d; + export "DPI-C" function e_pack_struct_2d; + export "DPI-C" function e_pack_struct_3d; + +`ifndef NO_UNPACK_STRUCT + export "DPI-C" function e_unpack_struct_0d; + export "DPI-C" function e_unpack_struct_1d; + export "DPI-C" function e_unpack_struct_2d; + export "DPI-C" function e_unpack_struct_3d; +`endif + //====================================================================== + // Definitions of exported functions + //====================================================================== +`define SET_0D(val) val = 42 +`define SET_1D(val) val[0] = 43; val[1] = 44 +`define SET_2D(val) val[0][1] = 45; val[1][1] = 46; val[2][1] = 47 +`define SET_3D(val) val[0][0][0] = 48; val[1][0][0] = 49; val[2][0][0] = 50; val[3][0][0] = 51 + + function void e_byte_0d(output byte val); `SET_0D(val); endfunction + function void e_byte_1d(output byte val[2]); `SET_1D(val); endfunction + function void e_byte_2d(output byte val[3][2]); `SET_2D(val); endfunction + function void e_byte_3d(output byte_array_t val); `SET_3D(val); endfunction + + function void e_byte_unsigned_0d(output byte unsigned val); `SET_0D(val); endfunction + function void e_byte_unsigned_1d(output byte unsigned val[2]); `SET_1D(val); endfunction + function void e_byte_unsigned_2d(output byte unsigned val[3][2]); `SET_2D(val); endfunction + function void e_byte_unsigned_3d(output byte_unsigned_array_t val); `SET_3D(val); endfunction + + function void e_shortint_0d(output shortint val); `SET_0D(val); endfunction + function void e_shortint_1d(output shortint val[2]); `SET_1D(val); endfunction + function void e_shortint_2d(output shortint val[3][2]); `SET_2D(val); endfunction + function void e_shortint_3d(output shortint_array_t val); `SET_3D(val); endfunction + + function void e_shortint_unsigned_0d(output shortint unsigned val); `SET_0D(val); endfunction + function void e_shortint_unsigned_1d(output shortint unsigned val[2]); `SET_1D(val); endfunction + function void e_shortint_unsigned_2d(output shortint unsigned val[3][2]); `SET_2D(val); endfunction + function void e_shortint_unsigned_3d(output shortint_unsigned_array_t val); `SET_3D(val); endfunction + + function void e_int_0d(output int val); `SET_0D(val); endfunction + function void e_int_1d(output int val[2]); `SET_1D(val); endfunction + function void e_int_2d(output int val[3][2]); `SET_2D(val); endfunction + function void e_int_3d(output int_array_t val); `SET_3D(val); endfunction + + function void e_int_unsigned_0d(output int unsigned val); `SET_0D(val); endfunction + function void e_int_unsigned_1d(output int unsigned val[2]); `SET_1D(val); endfunction + function void e_int_unsigned_2d(output int unsigned val[3][2]); `SET_2D(val); endfunction + function void e_int_unsigned_3d(output int_unsigned_array_t val); `SET_3D(val); endfunction + + function void e_longint_0d(output longint val); `SET_0D(val); endfunction + function void e_longint_1d(output longint val[2]); `SET_1D(val); endfunction + function void e_longint_2d(output longint val[3][2]); `SET_2D(val); endfunction + function void e_longint_3d(output longint_array_t val); `SET_3D(val); endfunction + + function void e_longint_unsigned_0d(output longint unsigned val); `SET_0D(val); endfunction + function void e_longint_unsigned_1d(output longint unsigned val[2]); `SET_1D(val); endfunction + function void e_longint_unsigned_2d(output longint unsigned val[3][2]); `SET_2D(val); endfunction + function void e_longint_unsigned_3d(output longint_unsigned_array_t val); `SET_3D(val); endfunction + +`ifndef NO_TIME + function void e_time_0d(output time val); `SET_0D(val); endfunction + function void e_time_1d(output time val[2]); `SET_1D(val); endfunction + function void e_time_2d(output time val[3][2]); `SET_2D(val); endfunction + function void e_time_3d(output time_array_t val); `SET_3D(val); endfunction +`endif + +`ifndef NO_INTEGER + function void e_integer_0d(output integer val); `SET_0D(val); endfunction + function void e_integer_1d(output integer val[2]); `SET_1D(val); endfunction + function void e_integer_2d(output integer val[3][2]); `SET_2D(val); endfunction + function void e_integer_3d(output integer_array_t val); `SET_3D(val); endfunction +`endif + + function void e_real_0d(output real val); `SET_0D(val); endfunction + function void e_real_1d(output real val[2]); `SET_1D(val); endfunction + function void e_real_2d(output real val[3][2]); `SET_2D(val); endfunction + function void e_real_3d(output real_array_t val); `SET_3D(val); endfunction + +`ifndef NO_SHORTREAL + function void e_shortreal_0d(output shortreal val); `SET_0D(val); endfunction + function void e_shortreal_1d(output shortreal val[2]); `SET_1D(val); endfunction + function void e_shortreal_2d(output shortreal val[3][2]); `SET_2D(val); endfunction + function void e_shortreal_3d(output shortreal_array_t val); `SET_3D(val); endfunction +`endif + + function void e_chandle_0d(output chandle val); + val = get_non_null(); + endfunction + function void e_chandle_1d(output chandle val[2]); + val[0] = get_non_null(); + val[1] = get_non_null(); + endfunction + function void e_chandle_2d(output chandle val[3][2]); + val[0][1] = get_non_null(); + val[1][1] = get_non_null(); + val[2][1] = get_non_null(); + endfunction + function void e_chandle_3d(output chandle_array_t val); + val[0][0][0] = get_non_null(); + val[1][0][0] = get_non_null(); + val[2][0][0] = get_non_null(); + val[3][0][0] = get_non_null(); + endfunction + + function void e_string_0d(output string val); + val = "42"; + endfunction + function void e_string_1d(output string val[2]); + val[0] = "43"; + val[1] = "44"; + endfunction + function void e_string_2d(output string val[3][2]); + val[0][1] = "45"; + val[1][1] = "46"; + val[2][1] = "47"; + endfunction + function void e_string_3d(output string_array_t val); + val[0][0][0] = "48"; + val[1][0][0] = "49"; + val[2][0][0] = "50"; + val[3][0][0] = "51"; + endfunction + + function void e_bit7_0d(output bit[6:0] val); `SET_0D(val); endfunction + function void e_bit7_1d(output bit[6:0] val[2]); `SET_1D(val); endfunction + function void e_bit7_2d(output bit[6:0] val[3][2]); `SET_2D(val); endfunction + function void e_bit7_3d(output bit7_array_t val); `SET_3D(val); endfunction + + function void e_bit121_0d(output bit[120:0] val); `SET_0D(val); endfunction + function void e_bit121_1d(output bit[120:0] val[2]); `SET_1D(val); endfunction + function void e_bit121_2d(output bit[120:0] val[3][2]); `SET_2D(val); endfunction + function void e_bit121_3d(output bit121_array_t val); `SET_3D(val); endfunction + + function void e_logic7_0d(output logic[6:0] val); `SET_0D(val); endfunction + function void e_logic7_1d(output logic[6:0] val[2]); `SET_1D(val); endfunction + function void e_logic7_2d(output logic[6:0] val[3][2]); `SET_2D(val); endfunction + function void e_logic7_3d(output logic7_array_t val); `SET_3D(val); endfunction + + function void e_logic121_0d(output logic[120:0] val); `SET_0D(val); endfunction + function void e_logic121_1d(output logic[120:0] val[2]); `SET_1D(val); endfunction + function void e_logic121_2d(output logic[120:0] val[3][2]); `SET_2D(val); endfunction + function void e_logic121_3d(output logic121_array_t val); `SET_3D(val); endfunction + + function void e_pack_struct_0d(output pack_struct_t val); `SET_0D(val); endfunction + function void e_pack_struct_1d(output pack_struct_t val[2]); `SET_1D(val); endfunction + function void e_pack_struct_2d(output pack_struct_t val[3][2]); `SET_2D(val); endfunction + function void e_pack_struct_3d(output pack_struct_array_t val); `SET_3D(val); endfunction + +`ifndef NO_UNPACK_STRUCT + function void e_unpack_struct_0d(output unpack_struct_t val); + val.val = 42; + endfunction + function void e_unpack_struct_1d(output unpack_struct_t val[2]); + val[0].val = 43; + val[1].val = 44; + endfunction + function void e_unpack_struct_2d(output unpack_struct_t val[3][2]); + val[0][1].val = 45; + val[1][1].val = 46; + val[2][1].val = 47; + endfunction + function void e_unpack_struct_3d(output unpack_struct_array_t val); + val[0][0][0].val = 48; + val[1][0][0].val = 49; + val[2][0][0].val = 50; + val[3][0][0].val = 51; + endfunction +`endif + + //====================================================================== + // Invoke all imported functions + //====================================================================== + + import "DPI-C" context function void check_exports(); + + initial begin + byte_array_t byte_array; + byte_unsigned_array_t byte_unsigned_array; + shortint_array_t shortint_array; + shortint_unsigned_array_t shortint_unsigned_array; + int_array_t int_array; + int_unsigned_array_t int_unsigned_array; + longint_array_t longint_array; + longint_unsigned_array_t longint_unsigned_array; +`ifndef NO_TIME + time_array_t time_array; +`endif +`ifndef NO_INTEGER + integer_array_t integer_array; +`endif + real_array_t real_array; +`ifndef NO_SHORTREAL + shortreal_array_t shortreal_array; +`endif + chandle_array_t chandle_array; + string_array_t string_array; + bit7_array_t bit7_array; + bit121_array_t bit121_array; + logic7_array_t logic7_array; + logic121_array_t logic121_array; + pack_struct_array_t pack_struct_array; +`ifndef NO_UNPACK_STRUCT + unpack_struct_array_t unpack_struct_array; +`endif + + i_byte_0d(byte_array[3][2][1]); + `CHECK_0D(byte_array[3][2][1]); + i_byte_1d(byte_array[2][1]); + `CHECK_1D(byte_array[2][1]); + i_byte_2d(byte_array[1]); + `CHECK_2D(byte_array[1]); + i_byte_3d(byte_array); + `CHECK_3D(byte_array); + + i_byte_unsigned_0d(byte_unsigned_array[3][2][1]); + `CHECK_0D(byte_unsigned_array[3][2][1]); + i_byte_unsigned_1d(byte_unsigned_array[2][1]); + `CHECK_1D(byte_unsigned_array[2][1]); + i_byte_unsigned_2d(byte_unsigned_array[1]); + `CHECK_2D(byte_unsigned_array[1]); + i_byte_unsigned_3d(byte_unsigned_array); + `CHECK_3D(byte_unsigned_array); + + i_shortint_0d(shortint_array[3][2][1]); + `CHECK_0D(shortint_array[3][2][1]); + i_shortint_1d(shortint_array[2][1]); + `CHECK_1D(shortint_array[2][1]); + i_shortint_2d(shortint_array[1]); + `CHECK_2D(shortint_array[1]); + i_shortint_3d(shortint_array); + `CHECK_3D(shortint_array); + + i_shortint_unsigned_0d(shortint_unsigned_array[3][2][1]); + `CHECK_0D(shortint_unsigned_array[3][2][1]); + i_shortint_unsigned_1d(shortint_unsigned_array[2][1]); + `CHECK_1D(shortint_unsigned_array[2][1]); + i_shortint_unsigned_2d(shortint_unsigned_array[1]); + `CHECK_2D(shortint_unsigned_array[1]); + i_shortint_unsigned_3d(shortint_unsigned_array); + `CHECK_3D(shortint_unsigned_array); + + i_int_0d(int_array[3][2][1]); + `CHECK_0D(int_array[3][2][1]); + i_int_1d(int_array[2][1]); + `CHECK_1D(int_array[2][1]); + i_int_2d(int_array[1]); + `CHECK_2D(int_array[1]); + i_int_3d(int_array); + `CHECK_3D(int_array); + + i_int_unsigned_0d(int_unsigned_array[3][2][1]); + `CHECK_0D(int_unsigned_array[3][2][1]); + i_int_unsigned_1d(int_unsigned_array[2][1]); + `CHECK_1D(int_unsigned_array[2][1]); + i_int_unsigned_2d(int_unsigned_array[1]); + `CHECK_2D(int_unsigned_array[1]); + i_int_unsigned_3d(int_unsigned_array); + `CHECK_3D(int_unsigned_array); + + i_longint_0d(longint_array[3][2][1]); + `CHECK_0D(longint_array[3][2][1]); + i_longint_1d(longint_array[2][1]); + `CHECK_1D(longint_array[2][1]); + i_longint_2d(longint_array[1]); + `CHECK_2D(longint_array[1]); + i_longint_3d(longint_array); + `CHECK_3D(longint_array); + + i_longint_unsigned_0d(longint_unsigned_array[3][2][1]); + `CHECK_0D(longint_unsigned_array[3][2][1]); + i_longint_unsigned_1d(longint_unsigned_array[2][1]); + `CHECK_1D(longint_unsigned_array[2][1]); + i_longint_unsigned_2d(longint_unsigned_array[1]); + `CHECK_2D(longint_unsigned_array[1]); + i_longint_unsigned_3d(longint_unsigned_array); + `CHECK_3D(longint_unsigned_array); + +`ifndef NO_TIME + i_time_0d(time_array[3][2][1]); + `CHECK_0D(time_array[3][2][1]); + i_time_1d(time_array[2][1]); + `CHECK_1D(time_array[2][1]); + i_time_2d(time_array[1]); + `CHECK_2D(time_array[1]); + i_time_3d(time_array); + `CHECK_3D(time_array); +`endif + +`ifndef NO_INTEGER + i_integer_0d(integer_array[3][2][1]); + `CHECK_0D(integer_array[3][2][1]); + i_integer_1d(integer_array[2][1]); + `CHECK_1D(integer_array[2][1]); + i_integer_2d(integer_array[1]); + `CHECK_2D(integer_array[1]); + i_integer_3d(integer_array); + `CHECK_3D(integer_array); +`endif + + i_real_0d(real_array[3][2][1]); + `CHECK_0D(real_array[3][2][1]); + i_real_1d(real_array[2][1]); + `CHECK_1D(real_array[2][1]); + i_real_2d(real_array[1]); + `CHECK_2D(real_array[1]); + i_real_3d(real_array); + `CHECK_3D(real_array); + +`ifndef NO_SHORTREAL + i_shortreal_0d(shortreal_array[3][2][1]); + `CHECK_0D(shortreal_array[3][2][1]); + i_shortreal_1d(shortreal_array[2][1]); + `CHECK_1D(shortreal_array[2][1]); + i_shortreal_2d(shortreal_array[1]); + `CHECK_2D(shortreal_array[1]); + i_shortreal_3d(shortreal_array); + `CHECK_3D(shortreal_array); +`endif + + for (int i = 0; i < 4; ++i) + for (int j = 0; j < 3; ++j) + for (int k = 0; k < 2; ++k) + chandle_array[i][j][k] = null; + i_chandle_0d(chandle_array[3][2][1]); + `CHECK_CHANDLE_VAL(chandle_array[3][2][1], get_non_null()); + i_chandle_1d(chandle_array[2][1]); + `CHECK_CHANDLE_VAL(chandle_array[2][1][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[2][1][1], get_non_null()); + i_chandle_2d(chandle_array[1]); + `CHECK_CHANDLE_VAL(chandle_array[1][0][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][1][1], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][2][1], get_non_null()); + i_chandle_3d(chandle_array); + `CHECK_CHANDLE_VAL(chandle_array[0][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[1][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[2][0][0], get_non_null()); + `CHECK_CHANDLE_VAL(chandle_array[3][0][0], get_non_null()); + + i_string_0d(string_array[3][2][1]); + `CHECK_STRING_VAL(string_array[3][2][1], "42"); + i_string_1d(string_array[2][1]); + `CHECK_STRING_VAL(string_array[2][1][0], "43"); + `CHECK_STRING_VAL(string_array[2][1][1], "44"); + i_string_2d(string_array[1]); + `CHECK_STRING_VAL(string_array[1][0][1], "45"); + `CHECK_STRING_VAL(string_array[1][1][1], "46"); + `CHECK_STRING_VAL(string_array[1][2][1], "47"); + i_string_3d(string_array); + `CHECK_STRING_VAL(string_array[0][0][0], "48"); + `CHECK_STRING_VAL(string_array[1][0][0], "49"); + `CHECK_STRING_VAL(string_array[2][0][0], "50"); + `CHECK_STRING_VAL(string_array[3][0][0], "51"); + + i_bit7_0d(bit7_array[3][2][1]); + `CHECK_0D(bit7_array[3][2][1]); + i_bit7_1d(bit7_array[2][1]); + `CHECK_1D(bit7_array[2][1]); + i_bit7_2d(bit7_array[1]); + `CHECK_2D(bit7_array[1]); + i_bit7_3d(bit7_array); + `CHECK_3D(bit7_array); + + i_bit121_0d(bit121_array[3][2][1]); + `CHECK_0D(bit121_array[3][2][1]); + i_bit121_1d(bit121_array[2][1]); + `CHECK_1D(bit121_array[2][1]); + i_bit121_2d(bit121_array[1]); + `CHECK_2D(bit121_array[1]); + i_bit121_3d(bit121_array); + `CHECK_3D(bit121_array); + + i_logic7_0d(logic7_array[3][2][1]); + `CHECK_0D(logic7_array[3][2][1]); + i_logic7_1d(logic7_array[2][1]); + `CHECK_1D(logic7_array[2][1]); + i_logic7_2d(logic7_array[1]); + `CHECK_2D(logic7_array[1]); + i_logic7_3d(logic7_array); + `CHECK_3D(logic7_array); + + i_logic121_0d(logic121_array[3][2][1]); + `CHECK_0D(logic121_array[3][2][1]); + i_logic121_1d(logic121_array[2][1]); + `CHECK_1D(logic121_array[2][1]); + i_logic121_2d(logic121_array[1]); + `CHECK_2D(logic121_array[1]); + i_logic121_3d(logic121_array); + `CHECK_3D(logic121_array); + + i_pack_struct_0d(pack_struct_array[3][2][1]); + `CHECK_0D(pack_struct_array[3][2][1]); + i_pack_struct_1d(pack_struct_array[2][1]); + `CHECK_1D(pack_struct_array[2][1]); + i_pack_struct_2d(pack_struct_array[1]); + `CHECK_2D(pack_struct_array[1]); + i_pack_struct_3d(pack_struct_array); + `CHECK_3D(pack_struct_array); + + `SET_VALUES(pack_struct_array); + i_pack_struct_0d(pack_struct_array[3][2][1]); + i_pack_struct_1d(pack_struct_array[2][1]); + i_pack_struct_2d(pack_struct_array[1]); + i_pack_struct_3d(pack_struct_array); + +`ifndef NO_UNPACK_STRUCT + i_unpack_struct_0d(unpack_struct_array[3][2][1]); + `CHECK_VAL(unpack_struct_array[3][2][1].val, 42); + + i_unpack_struct_1d(unpack_struct_array[2][1]); + `CHECK_VAL(unpack_struct_array[2][1][0].val, 43); + `CHECK_VAL(unpack_struct_array[2][1][1].val, 44); + + i_unpack_struct_2d(unpack_struct_array[1]); + `CHECK_VAL(unpack_struct_array[1][0][1].val, 45); + `CHECK_VAL(unpack_struct_array[1][1][1].val, 46); + `CHECK_VAL(unpack_struct_array[1][2][1].val, 47); + + i_unpack_struct_3d(unpack_struct_array); + `CHECK_VAL(unpack_struct_array[0][0][0].val, 48); + `CHECK_VAL(unpack_struct_array[1][0][0].val, 49); + `CHECK_VAL(unpack_struct_array[2][0][0].val, 50); + `CHECK_VAL(unpack_struct_array[3][0][0].val, 51); +`endif + + check_exports(); + $write("*-* All Finished *-*\n"); + $finish; + end + +endmodule diff --git a/test_regress/t/t_dpi_arg_output_unpack__Dpi.out b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out new file mode 100644 index 000000000..0c038cb14 --- /dev/null +++ b/test_regress/t/t_dpi_arg_output_unpack__Dpi.out @@ -0,0 +1,313 @@ +// Verilated -*- C++ -*- +// DESCRIPTION: Verilator output: Prototypes for DPI import and export functions. +// +// Verilator includes this file in all generated .cpp files that use DPI functions. +// Manually include this file where DPI .c import functions are declared to ensure +// the C functions match the expectations of the DPI imports. + +#include "svdpi.h" + +#ifdef __cplusplus +extern "C" { +#endif + + + // DPI EXPORTS + // DPI export at t/t_dpi_arg_output_unpack.v:460:18 + extern void e_bit121_0d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:461:18 + extern void e_bit121_1d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:462:18 + extern void e_bit121_2d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:463:18 + extern void e_bit121_3d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:455:18 + extern void e_bit7_0d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:456:18 + extern void e_bit7_1d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:457:18 + extern void e_bit7_2d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:458:18 + extern void e_bit7_3d(svBitVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:351:18 + extern void e_byte_0d(char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:352:18 + extern void e_byte_1d(char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:353:18 + extern void e_byte_2d(char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:354:18 + extern void e_byte_3d(char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:356:18 + extern void e_byte_unsigned_0d(unsigned char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:357:18 + extern void e_byte_unsigned_1d(unsigned char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:358:18 + extern void e_byte_unsigned_2d(unsigned char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:359:18 + extern void e_byte_unsigned_3d(unsigned char* val); + // DPI export at t/t_dpi_arg_output_unpack.v:417:18 + extern void e_chandle_0d(void** val); + // DPI export at t/t_dpi_arg_output_unpack.v:420:18 + extern void e_chandle_1d(void** val); + // DPI export at t/t_dpi_arg_output_unpack.v:424:18 + extern void e_chandle_2d(void** val); + // DPI export at t/t_dpi_arg_output_unpack.v:429:18 + extern void e_chandle_3d(void** val); + // DPI export at t/t_dpi_arg_output_unpack.v:371:18 + extern void e_int_0d(int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:372:18 + extern void e_int_1d(int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:373:18 + extern void e_int_2d(int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:374:18 + extern void e_int_3d(int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:376:18 + extern void e_int_unsigned_0d(unsigned int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:377:18 + extern void e_int_unsigned_1d(unsigned int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:378:18 + extern void e_int_unsigned_2d(unsigned int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:379:18 + extern void e_int_unsigned_3d(unsigned int* val); + // DPI export at t/t_dpi_arg_output_unpack.v:399:18 + extern void e_integer_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:400:18 + extern void e_integer_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:401:18 + extern void e_integer_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:402:18 + extern void e_integer_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:470:18 + extern void e_logic121_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:471:18 + extern void e_logic121_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:472:18 + extern void e_logic121_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:473:18 + extern void e_logic121_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:465:18 + extern void e_logic7_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:466:18 + extern void e_logic7_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:467:18 + extern void e_logic7_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:468:18 + extern void e_logic7_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:381:18 + extern void e_longint_0d(long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:382:18 + extern void e_longint_1d(long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:383:18 + extern void e_longint_2d(long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:384:18 + extern void e_longint_3d(long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:386:18 + extern void e_longint_unsigned_0d(unsigned long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:387:18 + extern void e_longint_unsigned_1d(unsigned long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:388:18 + extern void e_longint_unsigned_2d(unsigned long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:389:18 + extern void e_longint_unsigned_3d(unsigned long long* val); + // DPI export at t/t_dpi_arg_output_unpack.v:475:18 + extern void e_pack_struct_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:476:18 + extern void e_pack_struct_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:477:18 + extern void e_pack_struct_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:478:18 + extern void e_pack_struct_3d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:405:18 + extern void e_real_0d(double* val); + // DPI export at t/t_dpi_arg_output_unpack.v:406:18 + extern void e_real_1d(double* val); + // DPI export at t/t_dpi_arg_output_unpack.v:407:18 + extern void e_real_2d(double* val); + // DPI export at t/t_dpi_arg_output_unpack.v:408:18 + extern void e_real_3d(double* val); + // DPI export at t/t_dpi_arg_output_unpack.v:361:18 + extern void e_shortint_0d(short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:362:18 + extern void e_shortint_1d(short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:363:18 + extern void e_shortint_2d(short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:364:18 + extern void e_shortint_3d(short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:366:18 + extern void e_shortint_unsigned_0d(unsigned short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:367:18 + extern void e_shortint_unsigned_1d(unsigned short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:368:18 + extern void e_shortint_unsigned_2d(unsigned short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:369:18 + extern void e_shortint_unsigned_3d(unsigned short* val); + // DPI export at t/t_dpi_arg_output_unpack.v:436:18 + extern void e_string_0d(const char** val); + // DPI export at t/t_dpi_arg_output_unpack.v:439:18 + extern void e_string_1d(const char** val); + // DPI export at t/t_dpi_arg_output_unpack.v:443:18 + extern void e_string_2d(const char** val); + // DPI export at t/t_dpi_arg_output_unpack.v:448:18 + extern void e_string_3d(const char** val); + // DPI export at t/t_dpi_arg_output_unpack.v:392:18 + extern void e_time_0d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:393:18 + extern void e_time_1d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:394:18 + extern void e_time_2d(svLogicVecVal* val); + // DPI export at t/t_dpi_arg_output_unpack.v:395:18 + extern void e_time_3d(svLogicVecVal* val); + + // DPI IMPORTS + // DPI import at t/t_dpi_arg_output_unpack.v:505:41 + extern void check_exports(); + // DPI import at t/t_dpi_arg_output_unpack.v:123:36 + extern void* get_non_null(); + // DPI import at t/t_dpi_arg_output_unpack.v:206:33 + extern void i_bit121_0d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:207:33 + extern void i_bit121_1d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:208:33 + extern void i_bit121_2d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:209:33 + extern void i_bit121_3d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:201:33 + extern void i_bit7_0d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:202:33 + extern void i_bit7_1d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:203:33 + extern void i_bit7_2d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:204:33 + extern void i_bit7_3d(svBitVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:125:33 + extern void i_byte_0d(char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:126:33 + extern void i_byte_1d(char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:127:33 + extern void i_byte_2d(char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:128:33 + extern void i_byte_3d(char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:130:33 + extern void i_byte_unsigned_0d(unsigned char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:131:33 + extern void i_byte_unsigned_1d(unsigned char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:132:33 + extern void i_byte_unsigned_2d(unsigned char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:133:33 + extern void i_byte_unsigned_3d(unsigned char* val); + // DPI import at t/t_dpi_arg_output_unpack.v:191:33 + extern void i_chandle_0d(void** val); + // DPI import at t/t_dpi_arg_output_unpack.v:192:33 + extern void i_chandle_1d(void** val); + // DPI import at t/t_dpi_arg_output_unpack.v:193:33 + extern void i_chandle_2d(void** val); + // DPI import at t/t_dpi_arg_output_unpack.v:194:33 + extern void i_chandle_3d(void** val); + // DPI import at t/t_dpi_arg_output_unpack.v:145:33 + extern void i_int_0d(int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:146:33 + extern void i_int_1d(int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:147:33 + extern void i_int_2d(int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:148:33 + extern void i_int_3d(int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:150:33 + extern void i_int_unsigned_0d(unsigned int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:151:33 + extern void i_int_unsigned_1d(unsigned int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:152:33 + extern void i_int_unsigned_2d(unsigned int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:153:33 + extern void i_int_unsigned_3d(unsigned int* val); + // DPI import at t/t_dpi_arg_output_unpack.v:173:33 + extern void i_integer_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:174:33 + extern void i_integer_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:175:33 + extern void i_integer_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:176:33 + extern void i_integer_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:216:33 + extern void i_logic121_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:217:33 + extern void i_logic121_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:218:33 + extern void i_logic121_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:219:33 + extern void i_logic121_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:211:33 + extern void i_logic7_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:212:33 + extern void i_logic7_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:213:33 + extern void i_logic7_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:214:33 + extern void i_logic7_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:155:33 + extern void i_longint_0d(long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:156:33 + extern void i_longint_1d(long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:157:33 + extern void i_longint_2d(long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:158:33 + extern void i_longint_3d(long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:160:33 + extern void i_longint_unsigned_0d(unsigned long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:161:33 + extern void i_longint_unsigned_1d(unsigned long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:162:33 + extern void i_longint_unsigned_2d(unsigned long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:163:33 + extern void i_longint_unsigned_3d(unsigned long long* val); + // DPI import at t/t_dpi_arg_output_unpack.v:221:33 + extern void i_pack_struct_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:222:33 + extern void i_pack_struct_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:223:33 + extern void i_pack_struct_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:224:33 + extern void i_pack_struct_3d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:179:33 + extern void i_real_0d(double* val); + // DPI import at t/t_dpi_arg_output_unpack.v:180:33 + extern void i_real_1d(double* val); + // DPI import at t/t_dpi_arg_output_unpack.v:181:33 + extern void i_real_2d(double* val); + // DPI import at t/t_dpi_arg_output_unpack.v:182:33 + extern void i_real_3d(double* val); + // DPI import at t/t_dpi_arg_output_unpack.v:135:33 + extern void i_shortint_0d(short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:136:33 + extern void i_shortint_1d(short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:137:33 + extern void i_shortint_2d(short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:138:33 + extern void i_shortint_3d(short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:140:33 + extern void i_shortint_unsigned_0d(unsigned short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:141:33 + extern void i_shortint_unsigned_1d(unsigned short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:142:33 + extern void i_shortint_unsigned_2d(unsigned short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:143:33 + extern void i_shortint_unsigned_3d(unsigned short* val); + // DPI import at t/t_dpi_arg_output_unpack.v:196:33 + extern void i_string_0d(const char** val); + // DPI import at t/t_dpi_arg_output_unpack.v:197:33 + extern void i_string_1d(const char** val); + // DPI import at t/t_dpi_arg_output_unpack.v:198:33 + extern void i_string_2d(const char** val); + // DPI import at t/t_dpi_arg_output_unpack.v:199:33 + extern void i_string_3d(const char** val); + // DPI import at t/t_dpi_arg_output_unpack.v:166:33 + extern void i_time_0d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:167:33 + extern void i_time_1d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:168:33 + extern void i_time_2d(svLogicVecVal* val); + // DPI import at t/t_dpi_arg_output_unpack.v:169:33 + extern void i_time_3d(svLogicVecVal* val); + +#ifdef __cplusplus +} +#endif diff --git a/test_regress/t/t_dpi_export_context2_bad.cpp b/test_regress/t/t_dpi_export_context2_bad.cpp index 77ce4668c..ec2b10216 100644 --- a/test_regress/t/t_dpi_export_context2_bad.cpp +++ b/test_regress/t/t_dpi_export_context2_bad.cpp @@ -27,6 +27,7 @@ int main(int argc, char* argv[]) { Verilated::debug(0); topp->eval(); + VL_DO_DANGLING(delete topp, topp); return 1; } int dpii_task() { diff --git a/test_regress/t/t_dpi_export_context_bad.cpp b/test_regress/t/t_dpi_export_context_bad.cpp index a42ceff51..407c8b5b4 100644 --- a/test_regress/t/t_dpi_export_context_bad.cpp +++ b/test_regress/t/t_dpi_export_context_bad.cpp @@ -44,5 +44,8 @@ int main(int argc, char* argv[]) { topp->eval(); dpix_task(); // Missing svSetScope + + topp->final(); + VL_DO_DANGLING(delete topp, topp); return 1; } diff --git a/test_regress/t/t_dpi_unpack_bad.out b/test_regress/t/t_dpi_unpack_bad.out new file mode 100644 index 000000000..735465cf0 --- /dev/null +++ b/test_regress/t/t_dpi_unpack_bad.out @@ -0,0 +1,30 @@ +%Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:21:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]' v.s. 'logic[3:0]') + : ... In instance t + 21 | import_func0(sig0); + | ^~~~ +%Warning-WIDTH: t/t_dpi_unpack_bad.v:21:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's VARREF 'sig0' generates 3 bits. + : ... In instance t + 21 | import_func0(sig0); + | ^~~~~~~~~~~~ + ... Use "/* verilator lint_off WIDTH */" and lint_on around source to disable this message. +%Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:23:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]$[0:2][0:1]' v.s. 'logic[2:0]$[0:2]') + : ... In instance t + 23 | import_func1(sig1); + | ^~~~ +%Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:25:20: Shape of the argument does not match the shape of the parameter ('logic[2:0]$[0:2][0:1]' v.s. 'logic[2:0]$[0:2][0:2]') + : ... In instance t + 25 | import_func2(sig1); + | ^~~~ +%Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:27:20: Shape of the argument does not match the shape of the parameter ('bit[2:0]' v.s. 'logic[2:0]') + : ... In instance t + 27 | import_func2(sig2); + | ^~~~ +%Error-UNSUPPORTED: t/t_dpi_unpack_bad.v:29:24: Argument is not an unpacked array while parameter 'in' is + : ... In instance t + 29 | import_func0(sig0[1]); + | ^ +%Warning-WIDTH: t/t_dpi_unpack_bad.v:29:7: Operator TASKREF 'import_func0' expects 4 bits on the Function Argument, but Function Argument's ARRAYSEL generates 3 bits. + : ... In instance t + 29 | import_func0(sig0[1]); + | ^~~~~~~~~~~~ +%Error: Exiting due to diff --git a/test_regress/t/t_dpi_unpack_bad.pl b/test_regress/t/t_dpi_unpack_bad.pl new file mode 100755 index 000000000..1720150ad --- /dev/null +++ b/test_regress/t/t_dpi_unpack_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_dpi_unpack_bad.v b/test_regress/t/t_dpi_unpack_bad.v new file mode 100644 index 000000000..381fbe675 --- /dev/null +++ b/test_regress/t/t_dpi_unpack_bad.v @@ -0,0 +1,31 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// Copyright 2020 by Yutetsu TAKATSUKASA. 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 + +module t; + + logic [2:0] sig0[3]; + logic [2:0] sig1[3][2]; + bit [2:0] sig2[3][3]; + + import "DPI-C" function void import_func0(input logic [3:0] in [0:2]); + import "DPI-C" function void import_func1(input logic [2:0] in [0:2]); + import "DPI-C" function void import_func2(input logic [2:0] in [0:2][0:2]); + + initial begin + // packed width differs + import_func0(sig0); + // dimension differs + import_func1(sig1); + // unpacked extent differs + import_func2(sig1); + // bit v.s. logic mismatch + import_func2(sig2); + // packed var for unpacked port + import_func0(sig0[1]); + end +endmodule diff --git a/test_regress/t/t_dpi_vams.cpp b/test_regress/t/t_dpi_vams.cpp index 4722f8636..264eb18cd 100644 --- a/test_regress/t/t_dpi_vams.cpp +++ b/test_regress/t/t_dpi_vams.cpp @@ -51,5 +51,8 @@ int main(int argc, char* argv[]) { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results\n"); } + + topp->final(); + VL_DO_DANGLING(delete topp, topp); return 0; } diff --git a/test_regress/t/t_dynarray_method.v b/test_regress/t/t_dynarray_method.v index 21a778dc5..3142782b5 100644 --- a/test_regress/t/t_dynarray_method.v +++ b/test_regress/t/t_dynarray_method.v @@ -100,6 +100,9 @@ module t (/*AUTOARG*/); qi = d.find_last_index with (item == 20); `checkh(qi.size, 0); + qi = d.find_index with (item.index == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qv = d.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = d.max; diff --git a/test_regress/t/t_enum_public.cpp b/test_regress/t/t_enum_public.cpp index 598275ffc..328140331 100644 --- a/test_regress/t/t_enum_public.cpp +++ b/test_regress/t/t_enum_public.cpp @@ -24,4 +24,7 @@ int main(int argc, char* argv[]) { for (int i = 0; i < 10; i++) { // topp->eval(); } + + topp->final(); + VL_DO_DANGLING(delete topp, topp); } diff --git a/test_regress/t/t_flag_fi.cpp b/test_regress/t/t_flag_fi.cpp index 4c0a89ed1..c977decf8 100644 --- a/test_regress/t/t_flag_fi.cpp +++ b/test_regress/t/t_flag_fi.cpp @@ -29,6 +29,7 @@ int main(int argc, char* argv[]) { if (!gotit) { vl_fatal(__FILE__, __LINE__, "dut", "Never got call to myfunction"); } topp->final(); + VL_DO_DANGLING(delete topp, topp); return 0; } diff --git a/test_regress/t/t_flag_hier1_bad.out b/test_regress/t/t_flag_hier1_bad.out new file mode 100644 index 000000000..90f0cb247 --- /dev/null +++ b/test_regress/t/t_flag_hier1_bad.out @@ -0,0 +1,3 @@ +%Error: --hierarchical must not be set with --hierarchical-child or --hierarchical-block +%Error: --hierarchical-block must be set when --hierarchical-child is set +%Error: Exiting due to diff --git a/test_regress/t/t_flag_hier1_bad.pl b/test_regress/t/t_flag_hier1_bad.pl new file mode 100755 index 000000000..f41278e68 --- /dev/null +++ b/test_regress/t/t_flag_hier1_bad.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 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); +top_filename("t/t_hier_block.v"); + +lint( + fails => 1, + verilator_flags2 => ['--hierarchical', + '--hierarchical-child', + 'modName', + ], + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_flag_mmd.pl b/test_regress/t/t_flag_mmd.pl new file mode 100755 index 000000000..7f2955642 --- /dev/null +++ b/test_regress/t/t_flag_mmd.pl @@ -0,0 +1,20 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(vlt => 1); + +compile( + verilator_flags2 => ["-MMD -MP"], + ); + +file_grep("$Self->{obj_dir}/Vt_flag_mmd__ver.d", qr!t/t_flag_mmd.v!x); + +ok(1); +1; diff --git a/test_regress/t/t_flag_mmd.v b/test_regress/t/t_flag_mmd.v new file mode 100644 index 000000000..df8679e7d --- /dev/null +++ b/test_regress/t/t_flag_mmd.v @@ -0,0 +1,8 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2016 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; +endmodule diff --git a/test_regress/t/t_func_complex.pl b/test_regress/t/t_func_complex.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_func_complex.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_complex.v b/test_regress/t/t_func_complex.v new file mode 100644 index 000000000..142088d35 --- /dev/null +++ b/test_regress/t/t_func_complex.v @@ -0,0 +1,54 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed into the Public Domain, for any use, +// without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + typedef integer q_t[$]; + + function void queue_set(ref q_t q); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + q.push_back(42); + endfunction + + function void queue_check_nref(q_t q); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + q[0] = 11; + if (q[0] != 11) $stop; + endfunction + + function void queue_check_ref(const ref q_t q); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + if (q[0] != 42) $stop; + endfunction + + function q_t queue_ret(); +`ifdef TEST_NOINLINE + // verilator no_inline_task +`endif + queue_ret = '{101}; + endfunction + + initial begin + q_t iq; + queue_set(iq); + queue_check_ref(iq); + + iq[0] = 44; + queue_check_nref(iq); + if (iq[0] != 44) $stop; + + iq = queue_ret(); + if (iq[0] != 101) $stop; + + $write("*-* All Finished *-*\n"); + $finish; + end +endmodule diff --git a/test_regress/t/t_func_complex_noinl.pl b/test_regress/t/t_func_complex_noinl.pl new file mode 100755 index 000000000..e7a493593 --- /dev/null +++ b/test_regress/t/t_func_complex_noinl.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 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 + +top_filename("t/t_func_complex.v"); + +scenarios(simulator => 1); + +compile( + v_flags2 => ["+define+TEST_NOINLINE"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_rand.cpp b/test_regress/t/t_func_rand.cpp index f69fd7243..6a93db0ff 100644 --- a/test_regress/t/t_func_rand.cpp +++ b/test_regress/t/t_func_rand.cpp @@ -24,5 +24,7 @@ int main(int argc, char* argv[]) { if (topp->Rand != 0xfeed0fad) { vl_fatal(__FILE__, __LINE__, "top", "Unexpected value for Rand output\n"); } + topp->final(); + VL_DO_DANGLING(delete topp, topp); printf("*-* All Finished *-*\n"); } diff --git a/test_regress/t/t_func_refio_bad.out b/test_regress/t/t_func_refio_bad.out new file mode 100644 index 000000000..7d92bd42a --- /dev/null +++ b/test_regress/t/t_func_refio_bad.out @@ -0,0 +1,5 @@ +%Error: t/t_func_refio_bad.v:16:17: Ref argument requires matching types; port 'q' requires VAR 'q' but connection is CONST '?32?sh2a'. + : ... In instance t + 16 | queue_set(42); + | ^~ +%Error: Exiting due to diff --git a/test_regress/t/t_func_refio_bad.pl b/test_regress/t/t_func_refio_bad.pl new file mode 100755 index 000000000..59ba0d6c6 --- /dev/null +++ b/test_regress/t/t_func_refio_bad.pl @@ -0,0 +1,19 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(linter => 1); + +lint( + fails => $Self->{vlt_all}, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); +1; diff --git a/test_regress/t/t_func_refio_bad.v b/test_regress/t/t_func_refio_bad.v new file mode 100644 index 000000000..dc117ac4f --- /dev/null +++ b/test_regress/t/t_func_refio_bad.v @@ -0,0 +1,18 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(); + typedef integer q_t[$]; + + function void queue_set(ref q_t q); + q.push_back(42); + endfunction + + initial begin + q_t iq; + queue_set(42); // 42 is bad, meant iq + end +endmodule diff --git a/test_regress/t/t_gantt.pl b/test_regress/t/t_gantt.pl index e38cd63b7..77b8714a4 100755 --- a/test_regress/t/t_gantt.pl +++ b/test_regress/t/t_gantt.pl @@ -40,7 +40,7 @@ execute( run(cmd => ["$ENV{VERILATOR_ROOT}/bin/verilator_gantt", "$Self->{obj_dir}/profile_threads.dat", "--vcd $Self->{obj_dir}/profile_threads.vcd", - "> $Self->{obj_dir}/gantt.log"], + "| tee $Self->{obj_dir}/gantt.log"], verilator_run => 1, ); diff --git a/test_regress/t/t_hier_block.pl b/test_regress/t/t_hier_block.pl index e334fd536..e856d3cd8 100755 --- a/test_regress/t/t_hier_block.pl +++ b/test_regress/t/t_hier_block.pl @@ -12,7 +12,7 @@ clean_objs(); scenarios(vlt_all => 1); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. diff --git a/test_regress/t/t_hier_block_nohier.pl b/test_regress/t/t_hier_block_nohier.pl index ef6ebf31a..006c981b3 100755 --- a/test_regress/t/t_hier_block_nohier.pl +++ b/test_regress/t/t_hier_block_nohier.pl @@ -16,7 +16,7 @@ clean_objs(); scenarios(vlt_all => 1); top_filename("t/t_hier_block.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. compile( diff --git a/test_regress/t/t_hier_block_sc.pl b/test_regress/t/t_hier_block_sc.pl index 731aec401..7b85fedd8 100755 --- a/test_regress/t/t_hier_block_sc.pl +++ b/test_regress/t/t_hier_block_sc.pl @@ -12,7 +12,7 @@ clean_objs(); top_filename("t/t_hier_block.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. scenarios(vlt_all => 1); diff --git a/test_regress/t/t_hier_block_vlt.pl b/test_regress/t/t_hier_block_vlt.pl index fc4e7ccc9..f5231113b 100755 --- a/test_regress/t/t_hier_block_vlt.pl +++ b/test_regress/t/t_hier_block_vlt.pl @@ -13,7 +13,7 @@ clean_objs(); scenarios(vlt_all => 1); top_filename("t/t_hier_block.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. compile( diff --git a/test_regress/t/t_inst_array_bad.out b/test_regress/t/t_inst_array_bad.out index 312b0b4c3..b438a2a0d 100644 --- a/test_regress/t/t_inst_array_bad.out +++ b/test_regress/t/t_inst_array_bad.out @@ -1,4 +1,4 @@ -%Error: t/t_inst_array_bad.v:19:28: Input port connection 'onebit' as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits. +%Error: t/t_inst_array_bad.v:19:28: Input port connection 'onebit' as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits. (IEEE 1800-2017 23.3.3) : ... In instance t 19 | sub sub [7:0] (allbits, onebitbad, bitout); | ^~~~~~~~~ diff --git a/test_regress/t/t_interface2.v b/test_regress/t/t_interface2.v index caa6c1591..799e7ec13 100644 --- a/test_regress/t/t_interface2.v +++ b/test_regress/t/t_interface2.v @@ -104,6 +104,10 @@ module counter_nansi(clkm, c_data, i_value); endmodule : counter_nansi `endif +// Test uses Verilator --top-module, which means this isn't in the hierarchy +// Other simulators will see it, and is illegal to have unconnected interface +`ifdef VERILATOR module modunused (ifunused ifinunused); ifunused ifunused(); endmodule +`endif diff --git a/test_regress/t/t_leak.pl b/test_regress/t/t_leak.pl index 6e0507280..4ab37524e 100755 --- a/test_regress/t/t_leak.pl +++ b/test_regress/t/t_leak.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di if ($Self->{vltmt} && exists $ENV{TRAVIS_DIST} && $ENV{TRAVIS_DIST} eq "trusty") { - skip("Multithreaded test does not work under Travis w/ Ubuntu Trusty"); + skip("Multithreaded test does not work under CI w/ Ubuntu Trusty"); } scenarios(vlt_all => 1); diff --git a/test_regress/t/t_lint_syncasyncnet_bad.out b/test_regress/t/t_lint_syncasyncnet_bad.out index fd13ef2e0..dd4ca5627 100644 --- a/test_regress/t/t_lint_syncasyncnet_bad.out +++ b/test_regress/t/t_lint_syncasyncnet_bad.out @@ -1,9 +1,9 @@ -%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:16:25: Signal flopped as both synchronous and async: 'rst_both_l' - t/t_lint_syncasyncnet_bad.v:91:15: ... Location of async usage - 91 | q2 <= (~rst_both_l) ? 1'b0 : d; +%Warning-SYNCASYNCNET: t/t_lint_syncasyncnet_bad.v:14:10: Signal flopped as both synchronous and async: 'rst_both_l' + t/t_lint_syncasyncnet_bad.v:52:15: ... Location of async usage + 52 | q4 <= (~rst_both_l) ? 1'b0 : d; | ^~~~~~~~~~ - t/t_lint_syncasyncnet_bad.v:59:14: ... Location of sync usage - 59 | q2 <= (rst_both_l) ? d : 1'b0; + t/t_lint_syncasyncnet_bad.v:34:14: ... Location of sync usage + 34 | q2 <= (rst_both_l) ? d : 1'b0; | ^~~~~~~~~~ ... Use "/* verilator lint_off SYNCASYNCNET */" and lint_on around source to disable this message. %Error: Exiting due to diff --git a/test_regress/t/t_lint_syncasyncnet_bad.v b/test_regress/t/t_lint_syncasyncnet_bad.v index f941d0514..9db96f3fe 100644 --- a/test_regress/t/t_lint_syncasyncnet_bad.v +++ b/test_regress/t/t_lint_syncasyncnet_bad.v @@ -6,40 +6,15 @@ module t (/*AUTOARG*/ // Inputs - rst_sync_l, rst_both_l, rst_async_l, d, clk + clk, rst_both_l, rst_sync_l, rst_async_l, d ); /*AUTOINPUT*/ - // Beginning of automatic inputs (from unused autoinst inputs) - input clk; // To sub1 of sub1.v, ... - input d; // To sub1 of sub1.v, ... - input rst_async_l; // To sub2 of sub2.v - input rst_both_l; // To sub1 of sub1.v, ... - input rst_sync_l; // To sub1 of sub1.v - // End of automatics - - sub1 sub1 (/*AUTOINST*/ - // Inputs - .clk (clk), - .rst_both_l (rst_both_l), - .rst_sync_l (rst_sync_l), - .d (d)); - sub2 sub2 (/*AUTOINST*/ - // Inputs - .clk (clk), - .rst_both_l (rst_both_l), - .rst_async_l (rst_async_l), - .d (d)); -endmodule - -module sub1 (/*AUTOARG*/ - // Inputs - clk, rst_both_l, rst_sync_l, d - ); input clk; input rst_both_l; input rst_sync_l; - //input rst_async_l; + input rst_async_l; + input d; reg q1; reg q2; @@ -60,40 +35,27 @@ module sub1 (/*AUTOARG*/ if (0 && q1 && q2) ; end -endmodule - -module sub2 (/*AUTOARG*/ - // Inputs - clk, rst_both_l, rst_async_l, d - ); - - input clk; - input rst_both_l; - //input rst_sync_l; - input rst_async_l; - input d; - reg q1; - reg q2; reg q3; - always @(posedge clk or negedge rst_async_l) begin if (~rst_async_l) begin /*AUTORESET*/ // Beginning of autoreset for uninitialized flops - q1 <= 1'h0; + q3 <= 1'h0; // End of automatics end else begin - q1 <= d; + q3 <= d; end end + reg q4; always @(posedge clk or negedge rst_both_l) begin - q2 <= (~rst_both_l) ? 1'b0 : d; + q4 <= (~rst_both_l) ? 1'b0 : d; end // Make there be more async uses than sync uses + reg q5; always @(posedge clk or negedge rst_both_l) begin - q3 <= (~rst_both_l) ? 1'b0 : d; - if (0 && q1 && q2 && q3) ; + q5 <= (~rst_both_l) ? 1'b0 : d; + if (0 && q3 && q4 && q5) ; end endmodule diff --git a/test_regress/t/t_math_countbits.v b/test_regress/t/t_math_countbits.v index 8a1d9d4c5..547263faa 100644 --- a/test_regress/t/t_math_countbits.v +++ b/test_regress/t/t_math_countbits.v @@ -37,6 +37,18 @@ module t(/*AUTOARG*/ reg [5:0] result_59_3; reg [6:0] result_70_3; + initial begin + if ($countbits(32'b111100000000, '1) != 4) $stop; + if ($countbits(32'b111100000000, '0) != 28) $stop; + if ($countbits(32'b111100000000, '0, '1) != 32) $stop; + if ($countbits(4'bxxx0, 'x) != 3) $stop; + if ($countbits(4'bzzz0, 'z) != 3) $stop; + if ($countbits(4'b1zz0, 'z, '0) != 3) $stop; + if ($countbits(4'b1xx0, 'x, '0) != 3) $stop; + if ($countbits(4'b1xx0, 'x, '0, '1) != 4) $stop; + if ($countbits(4'bzzx0, 'x, 'z) != 3) $stop; + end + always @* begin result_16_1 = $countbits(in16, ctrl0); result_16_2 = $countbits(in16, ctrl0, ctrl1); @@ -73,13 +85,26 @@ module t(/*AUTOARG*/ if ($countbits(32'b1100x01z101, 'x, 'z) != 2) $stop; if ($countbits(32'b1100x01z101, 'x, 'z, '1) != 7) $stop; -`ifndef VERILATOR // Unsup if ($countbits(val, '1) != 7) $stop; if ($countones(val) != 7) $stop; if ($countbits(val, '0) != 25) $stop; if ($countbits(val, '0, '1) != 32) $stop; + // Optimization may depend on position of X, so need to walk it + if ($countbits(val, 'x) != 0) $stop; + if ($countbits(val, 'x, '1) != 7) $stop; + if ($countbits(val, '1, 'x) != 7) $stop; + if ($countbits(val, '1, '1, 'x) != 7) $stop; + if ($countbits(val, 'x, '0) != 25) $stop; + if ($countbits(val, 'x, '0, '1) != 32) $stop; + // Optimization may depend on position of Z, so need to walk it + if ($countbits(val, 'z) != 0) $stop; + if ($countbits(val, 'z, '1) != 7) $stop; + if ($countbits(val, '1, 'z) != 7) $stop; + if ($countbits(val, '1, '1, 'z) != 7) $stop; + if ($countbits(val, 'z, '0) != 25) $stop; + if ($countbits(val, 'z, '0, '1) != 32) $stop; + // if ($countbits(val, 'x, 'z) != 0) $stop; -`endif end else if (cyc == 1) begin in16 <= 16'h0AF0; diff --git a/test_regress/t/t_math_equal.v b/test_regress/t/t_math_equal.v index 7346c86c4..54968a263 100644 --- a/test_regress/t/t_math_equal.v +++ b/test_regress/t/t_math_equal.v @@ -45,13 +45,17 @@ module t (/*AUTOARG*/ // if (5'd10 != 5'b1010) $stop; if (5'd10 != 5'd10) $stop; + if (5'd10 != 5'd1_0) $stop; if (5'd10 != 5'ha) $stop; if (5'd10 != 5'o12) $stop; + if (5'd10 != 5'o1_2) $stop; if (5'd10 != 5'B 1010) $stop; + if (5'd10 != 5'B 10_10) $stop; if (5'd10 != 5'D10) $stop; if (5'd10 != 5'H a) $stop; if (5'd10 != 5 'O 12) $stop; if (24'h29cbb8 != 24'o12345670) $stop; + if (24'h29__cbb8 != 24'o123456__70) $stop; if (6'b111xxx !== 6'o7x) $stop; if (6'b111??? !== 6'o7?) $stop; if (6'b111zzz !== 6'o7z) $stop; diff --git a/test_regress/t/t_math_imm2.cpp b/test_regress/t/t_math_imm2.cpp index 999ef1157..163e797b7 100644 --- a/test_regress/t/t_math_imm2.cpp +++ b/test_regress/t/t_math_imm2.cpp @@ -44,6 +44,9 @@ int main(int argc, char* argv[]) { } } + sim->final(); + VL_DO_DANGLING(delete sim, sim); + if (errs) { vl_stop(__FILE__, __LINE__, "TOP-cpp"); exit(10); diff --git a/test_regress/t/t_mem_multi_io2.cpp b/test_regress/t/t_mem_multi_io2.cpp index 145b02ba3..7c18d04e3 100644 --- a/test_regress/t/t_mem_multi_io2.cpp +++ b/test_regress/t/t_mem_multi_io2.cpp @@ -78,6 +78,9 @@ int main() for (int j = 0; j < 5; j++) check("o345", READ(o345[i][j]), i * 8 + j); } + tb->final(); + VL_DO_DANGLING(delete tb, tb); + if (pass) { VL_PRINTF("*-* All Finished *-*\n"); } else { diff --git a/test_regress/t/t_mem_multi_io3.cpp b/test_regress/t/t_mem_multi_io3.cpp index 9068af3f9..9db98b288 100644 --- a/test_regress/t/t_mem_multi_io3.cpp +++ b/test_regress/t/t_mem_multi_io3.cpp @@ -20,6 +20,9 @@ int main() Verilated::debug(0); tb = new VM_PREFIX("tb"); + tb->final(); + VL_DO_DANGLING(delete tb, tb); + // Just a constructor test VL_PRINTF("*-* All Finished *-*\n"); return 0; diff --git a/test_regress/t/t_mem_slot.cpp b/test_regress/t/t_mem_slot.cpp index 86d3b984e..501c9113f 100644 --- a/test_regress/t/t_mem_slot.cpp +++ b/test_regress/t/t_mem_slot.cpp @@ -55,5 +55,8 @@ int main(int argc, char* argv[]) { for (i = 0; i < 100; i++) // StepSim(sim, random() % 3, random() % 2, random() % 2, random() % 3); + sim->final(); + VL_DO_DANGLING(delete sim, sim); + printf("*-* All Finished *-*\n"); } diff --git a/test_regress/t/t_mem_twoedge.v b/test_regress/t/t_mem_twoedge.v index 2a2af9faf..9c241853c 100644 --- a/test_regress/t/t_mem_twoedge.v +++ b/test_regress/t/t_mem_twoedge.v @@ -90,9 +90,9 @@ module Test (/*AUTOARG*/ input [7:0] d0; input [7:0] d1; output reg [31:0] out; + // verilator lint_off MULTIDRIVEN output reg [15:0] out2; - // verilator lint_off MULTIDRIVEN reg [7:0] mem [4]; // verilator lint_on MULTIDRIVEN diff --git a/test_regress/t/t_multitop_sig.cpp b/test_regress/t/t_multitop_sig.cpp index e548d25ad..e89b40853 100644 --- a/test_regress/t/t_multitop_sig.cpp +++ b/test_regress/t/t_multitop_sig.cpp @@ -39,5 +39,9 @@ int main(int argc, char* argv[]) { CHECK_RESULT(topp->b__02Eout, 1); CHECK_RESULT(topp->uniq_out, 0); } + + topp->final(); + VL_DO_DANGLING(delete topp, topp); + printf("*-* All Finished *-*\n"); } diff --git a/test_regress/t/t_order_multidriven.cpp b/test_regress/t/t_order_multidriven.cpp index 8679cdca3..5f6003e4b 100644 --- a/test_regress/t/t_order_multidriven.cpp +++ b/test_regress/t/t_order_multidriven.cpp @@ -56,5 +56,9 @@ int main() { } vcd->close(); + + vcore->final(); + VL_DO_DANGLING(delete vcore, vcore); + printf("*-* All Finished *-*\n"); } diff --git a/test_regress/t/t_order_quad.cpp b/test_regress/t/t_order_quad.cpp index 89773b790..9f6bd98d8 100644 --- a/test_regress/t/t_order_quad.cpp +++ b/test_regress/t/t_order_quad.cpp @@ -38,12 +38,13 @@ int main(int argc, char* argv[]) { topp->eval(); check(topp->y, 0x3c00000000ULL); - topp->final(); if (!fail) { VL_PRINTF("*-* All Finished *-*\n"); topp->final(); } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results\n"); } + + VL_DO_DANGLING(delete topp, topp); return 0; } diff --git a/test_regress/t/t_param_array6.pl b/test_regress/t/t_param_array6.pl new file mode 100755 index 000000000..b46d46042 --- /dev/null +++ b/test_regress/t/t_param_array6.pl @@ -0,0 +1,21 @@ +#!/usr/bin/env perl +if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; } +# DESCRIPTION: Verilator: Verilog Test driver/expect definition +# +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_param_array6.v b/test_regress/t/t_param_array6.v new file mode 100644 index 000000000..34766e731 --- /dev/null +++ b/test_regress/t/t_param_array6.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, 2020 by Anderson Ignacio da Silva. +// SPDX-License-Identifier: CC0-1.0 + +package test_pkg; + localparam [31:0] test_arr [4][4:0] + = '{ + '{'h0000, 'h1000, 'h2000, 'h3000, 'h4000}, + '{'h0FFF, 'h1FFF, 'h2FFF, 'h3FFF, 'h4FFF}, + '{ 'd0, 'd0, 'd0, 'd0, 'd0}, + '{ 'd0, 'd1, 'd2, 'd3, 'd4} + }; + + typedef struct packed{ + logic [7:0] val_1; + logic [7:0] val_2; + } test_ret_t; +endpackage + +module t import test_pkg::*; (clk); + input clk; + + function automatic test_ret_t test_f(logic [31:0] val); + test_ret_t temp; + + temp = test_ret_t'(0); + for (int i=0; i<5; i++) begin + if (val >= test_arr[0][i] && val <= test_arr[1][i]) begin + temp.val_1 = test_arr[2][i][7:0]; + temp.val_2 = test_arr[3][i][7:0]; + end + end + return temp; + endfunction + + test_ret_t temp; + logic [31:0] random; + + int cyc; + bit [63:0] sum; + + always @ (posedge clk) begin + cyc <= cyc + 1; + random <= {17'b0, cyc[3:0], 11'b0}; + temp <= test_f(random); +`ifdef TEST_VERBOSE + $display("rand: %h / Values -> val_1: %d / val_2: %d", random, temp.val_1, temp.val_2); +`endif + if (cyc > 10 && cyc < 90) begin + sum <= {48'h0, temp} ^ {sum[62:0],sum[63]^sum[2]^sum[0]}; + end + else if (cyc == 99) begin + $displayh(sum); + if (sum != 64'h74d34ea7a775f994) $stop; + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_param_public.cpp b/test_regress/t/t_param_public.cpp index 093d5acb6..f2e158a78 100644 --- a/test_regress/t/t_param_public.cpp +++ b/test_regress/t/t_param_public.cpp @@ -26,4 +26,7 @@ int main(int argc, char* argv[]) { for (int i = 0; i < 10; i++) { // topp->eval(); } + + topp->final(); + VL_DO_DANGLING(delete topp, topp); } diff --git a/test_regress/t/t_pp_recursedef_bad.out b/test_regress/t/t_pp_recursedef_bad.out new file mode 100644 index 000000000..06f2e03e9 --- /dev/null +++ b/test_regress/t/t_pp_recursedef_bad.out @@ -0,0 +1,2 @@ +%Error: t/t_pp_recursedef_bad.v:9:8012: Recursive `define substitution: `RECURSE +%Error: Exiting due to diff --git a/test_regress/t/t_with_bbox.pl b/test_regress/t/t_pp_recursedef_bad.pl similarity index 73% rename from test_regress/t/t_with_bbox.pl rename to test_regress/t/t_pp_recursedef_bad.pl index cc3646920..a5846c699 100755 --- a/test_regress/t/t_with_bbox.pl +++ b/test_regress/t/t_pp_recursedef_bad.pl @@ -2,19 +2,17 @@ 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 +# Copyright 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU # Lesser General Public License Version 3 or the Perl Artistic License # Version 2.0. # SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 scenarios(vlt => 1); -top_filename("t/t_with_unsup.v"); - lint( - verilator_flags => ["--bbox-unsup"], fails => 1, + expect_filename => $Self->{golden_filename}, ); ok(1); diff --git a/test_regress/t/t_pp_recursedef_bad.v b/test_regress/t/t_pp_recursedef_bad.v new file mode 100644 index 000000000..00a2aa78c --- /dev/null +++ b/test_regress/t/t_pp_recursedef_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, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t; +`define RECURSE `RECURSE + `RECURSE + + initial $stop; // Should have failed + +endmodule diff --git a/test_regress/t/t_queue_method.v b/test_regress/t/t_queue_method.v index d5429c88d..3e8dfbf1a 100644 --- a/test_regress/t/t_queue_method.v +++ b/test_regress/t/t_queue_method.v @@ -95,6 +95,11 @@ module t (/*AUTOARG*/); qi = q.find_last_index with (item == 20); `checkh(qi.size, 0); + qi = q.find_index with (item.index == 2); + v = $sformatf("%p", qi); `checks(v, "'{'h2} "); + qi = q.find_index with (item.index == item); + v = $sformatf("%p", qi); `checks(v, "'{'h2, 'h3, 'h4} "); + qv = q.min; v = $sformatf("%p", qv); `checks(v, "'{'h1} "); qv = q.max; diff --git a/test_regress/t/t_sc_names.cpp b/test_regress/t/t_sc_names.cpp index 163916db5..ba71d8c14 100644 --- a/test_regress/t/t_sc_names.cpp +++ b/test_regress/t/t_sc_names.cpp @@ -24,5 +24,6 @@ int sc_main(int argc, char* argv[]) { } else { vl_fatal(__FILE__, __LINE__, "tb", "Unexpected results\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_scope_map.cpp b/test_regress/t/t_scope_map.cpp index 39d28c3d0..020bee9d4 100644 --- a/test_regress/t/t_scope_map.cpp +++ b/test_regress/t/t_scope_map.cpp @@ -161,6 +161,8 @@ int main(int argc, char** argv, char** env) { tfp->close(); top->final(); + VL_DO_DANGLING(delete top, top); + VL_PRINTF("*-* All Finished *-*\n"); return 0; diff --git a/test_regress/t/t_split_var_0.pl b/test_regress/t/t_split_var_0.pl index ee21699a3..5f07afe64 100755 --- a/test_regress/t/t_split_var_0.pl +++ b/test_regress/t/t_split_var_0.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. compile( diff --git a/test_regress/t/t_split_var_2_trace.pl b/test_regress/t/t_split_var_2_trace.pl index 49fd37f82..c79ed778a 100755 --- a/test_regress/t/t_split_var_2_trace.pl +++ b/test_regress/t/t_split_var_2_trace.pl @@ -11,7 +11,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); top_filename("t/t_split_var_0.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # So use 6 threads here though it's not optimal in performace wise, but ok. compile( diff --git a/test_regress/t/t_sys_file_basic.out b/test_regress/t/t_sys_file_basic.out index 7de722707..848109f37 100644 --- a/test_regress/t/t_sys_file_basic.out +++ b/test_regress/t/t_sys_file_basic.out @@ -2,9 +2,9 @@ [0] Hello2 d: 12 12 -h: 00000000014 0000000c +h: 0000000c 0000000c -o: 0000000c 00000000014 +o: 00000000014 00000000014 b: 00000000000000000000000000001100 00000000000000000000000000001100 diff --git a/test_regress/t/t_sys_fmonitor.out b/test_regress/t/t_sys_fmonitor.out new file mode 100644 index 000000000..4d75640c2 --- /dev/null +++ b/test_regress/t/t_sys_fmonitor.out @@ -0,0 +1,15 @@ +[110] cyc=11 also +[120] cyc=12 also +[130] cyc=13 also +[140] cyc=14 also +[150] cyc=15 also +[160] cyc=16 also +[170] cyc=17 also +00000000000000000000000000010010b +00000013h +00000000024o +00000000025o +00000000026o +[230] cyc=23 new-monitor +[240] cyc=24 new-monitor +[270] cyc=27 new-monitor diff --git a/test_regress/t/t_vgen.pl b/test_regress/t/t_sys_fmonitor.pl similarity index 66% rename from test_regress/t/t_vgen.pl rename to test_regress/t/t_sys_fmonitor.pl index a488b5a3f..6bbedacab 100755 --- a/test_regress/t/t_vgen.pl +++ b/test_regress/t/t_sys_fmonitor.pl @@ -10,23 +10,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -if (eval "use Bit::Vector; return 2;" != 2) { - skip("Vgen test requires Bit::Vector"); -} else { - - top_filename("$Self->{obj_dir}/vgen.v"); - - run(cmd => ["./vgen.pl", - "-o $Self->{top_filename}", - #"--seed 0", - ]); - - compile( +compile( ); - execute( +execute( check_finished => 1, ); -} + +files_identical("$Self->{obj_dir}/open.log", $Self->{golden_filename}); + ok(1); + 1; diff --git a/test_regress/t/t_sys_fmonitor.v b/test_regress/t/t_sys_fmonitor.v new file mode 100644 index 000000000..dd7f1329f --- /dev/null +++ b/test_regress/t/t_sys_fmonitor.v @@ -0,0 +1,57 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + int fd; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 5) begin + fd = $fopen({`STRINGIFY(`TEST_OBJ_DIR),"/open.log"}, "w"); + end + else if (cyc == 10) begin + $fmonitor(fd, "[%0t] cyc=%0d", $time, cyc); + $fmonitor(fd, "[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $fmonitorb(fd, cyc, "b"); + end + else if (cyc == 18) begin + $fmonitorh(fd, cyc, "h"); + end + else if (cyc == 19) begin + $fmonitoro(fd, cyc, "o"); + end + else if (cyc == 22) begin + $fmonitor(fd, "[%0t] cyc=%0d new-monitor", $time, cyc); + end + else if (cyc == 24) begin + // IEEE suggests $monitoroff doesn't affect $fmonitor, but + // other simulators believe it does + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 27) begin + $fclose(fd); + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_fstrobe.out b/test_regress/t/t_sys_fstrobe.out new file mode 100644 index 000000000..7f9c034de --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.out @@ -0,0 +1,6 @@ +[110] cyc=11 +[110] cyc=11 also +00000000000000000000000000010010b +00000013h +00000000024o +[230] cyc=23 new-strobe diff --git a/test_regress/t/t_sys_fstrobe.pl b/test_regress/t/t_sys_fstrobe.pl new file mode 100755 index 000000000..6bbedacab --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.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 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, + ); + +files_identical("$Self->{obj_dir}/open.log", $Self->{golden_filename}); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_fstrobe.v b/test_regress/t/t_sys_fstrobe.v new file mode 100644 index 000000000..de5c664b1 --- /dev/null +++ b/test_regress/t/t_sys_fstrobe.v @@ -0,0 +1,55 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +`define STRINGIFY(x) `"x`" + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + int fd; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 5) begin + fd = $fopen({`STRINGIFY(`TEST_OBJ_DIR),"/open.log"}, "w"); + end + else if (cyc == 10) begin + $fstrobe(fd, "[%0t] cyc=%0d", $time, cyc); + $fstrobe(fd, "[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $fstrobeb(fd, cyc, "b"); + end + else if (cyc == 18) begin + $fstrobeh(fd, cyc, "h"); + end + else if (cyc == 19) begin + $fstrobeo(fd, cyc, "o"); + end + else if (cyc == 22) begin + $fstrobe(fd, "[%0t] cyc=%0d new-strobe", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 27) begin + $fclose(fd); + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_monitor.out b/test_regress/t/t_sys_monitor.out new file mode 100644 index 000000000..50f6f4d16 --- /dev/null +++ b/test_regress/t/t_sys_monitor.out @@ -0,0 +1,20 @@ +[110] cyc=11 +[120] cyc=12 +[130] cyc=13 +[140] cyc=14 +[150] cyc=15 +[160] cyc=16 +[170] cyc=17 +00000000000000000000000000010010b +00000013h +00000000024o +00000000025o +00000000026o +[230] cyc=23 new-monitor +[240] cyc=24 new-monitor +[270] cyc=27 new-monitor +[280] cyc=28 new-monitor +[290] cyc=29 new-monitor +[300] cyc=30 new-monitor +*-* All Finished *-* +[310] cyc=31 new-monitor diff --git a/test_regress/t/t_sys_monitor.pl b/test_regress/t/t_sys_monitor.pl new file mode 100755 index 000000000..88b7809fc --- /dev/null +++ b/test_regress/t/t_sys_monitor.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 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_monitor.v b/test_regress/t/t_sys_monitor.v new file mode 100644 index 000000000..21df4071f --- /dev/null +++ b/test_regress/t/t_sys_monitor.v @@ -0,0 +1,45 @@ +// 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 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + $monitor("[%0t] cyc=%0d", $time, cyc); + end + else if (cyc == 17) begin + $monitorb(cyc, "b"); + end + else if (cyc == 18) begin + $monitorh(cyc, "h"); + end + else if (cyc == 19) begin + $monitoro(cyc, "o"); + end + else if (cyc == 22) begin + $monitor("[%0t] cyc=%0d new-monitor", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_sys_rand_seed.out b/test_regress/t/t_sys_rand_seed.out deleted file mode 100644 index a9ae64425..000000000 --- a/test_regress/t/t_sys_rand_seed.out +++ /dev/null @@ -1,13 +0,0 @@ -%Error-UNSUPPORTED: t/t_sys_rand_seed.v:13:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag - 13 | valuea = $random(10); - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_sys_rand_seed.v:14:16: Unsupported: Seed on $random. Suggest use +verilator+seed+ runtime flag - 14 | valueb = $random(10); - | ^~~~~~~ -%Error-UNSUPPORTED: t/t_sys_rand_seed.v:16:16: Unsupported: Seed on $urandom. Suggest use +verilator+seed+ runtime flag - 16 | valuea = $urandom(10); - | ^~~~~~~~ -%Error-UNSUPPORTED: t/t_sys_rand_seed.v:17:16: Unsupported: Seed on $urandom. Suggest use +verilator+seed+ runtime flag - 17 | valueb = $urandom(10); - | ^~~~~~~~ -%Error: Exiting due to diff --git a/test_regress/t/t_sys_rand_seed.pl b/test_regress/t/t_sys_rand_seed.pl index 391ec23fd..b46d46042 100755 --- a/test_regress/t/t_sys_rand_seed.pl +++ b/test_regress/t/t_sys_rand_seed.pl @@ -11,12 +11,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); compile( - fails => $Self->{vlt_all}, - expect_filename => $Self->{golden_filename}, ); execute( - ) if !$Self->{vlt_all}; + check_finished => 1, + ); ok(1); 1; diff --git a/test_regress/t/t_sys_strobe.out b/test_regress/t/t_sys_strobe.out new file mode 100644 index 000000000..c38db0c3f --- /dev/null +++ b/test_regress/t/t_sys_strobe.out @@ -0,0 +1,7 @@ +[110] cyc=11 +[110] cyc=11 also +00000000000000000000000000010010b +00000013h +00000000024o +[230] cyc=23 new-strobe +*-* All Finished *-* diff --git a/test_regress/t/t_sys_strobe.pl b/test_regress/t/t_sys_strobe.pl new file mode 100755 index 000000000..88b7809fc --- /dev/null +++ b/test_regress/t/t_sys_strobe.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 2003 by Wilson Snyder. This program is free software; you +# can redistribute it and/or modify it under the terms of either the GNU +# Lesser General Public License Version 3 or the Perl Artistic License +# Version 2.0. +# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 + +scenarios(simulator => 1); + +compile( + ); + +execute( + check_finished => 1, + expect_filename => $Self->{golden_filename}, + ); + +ok(1); + +1; diff --git a/test_regress/t/t_sys_strobe.v b/test_regress/t/t_sys_strobe.v new file mode 100644 index 000000000..4365344d5 --- /dev/null +++ b/test_regress/t/t_sys_strobe.v @@ -0,0 +1,46 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 by Wilson Snyder. +// SPDX-License-Identifier: CC0-1.0 + +module t(/*AUTOARG*/ + // Inputs + clk + ); + + input clk; + + int cyc = 0; + + // Test loop + always @ (posedge clk) begin + cyc <= cyc + 1; + if (cyc == 10) begin + $strobe("[%0t] cyc=%0d", $time, cyc); + $strobe("[%0t] cyc=%0d also", $time, cyc); + end + else if (cyc == 17) begin + $strobeb(cyc, "b"); + end + else if (cyc == 18) begin + $strobeh(cyc, "h"); + end + else if (cyc == 19) begin + $strobeo(cyc, "o"); + end + else if (cyc == 22) begin + $strobe("[%0t] cyc=%0d new-strobe", $time, cyc); + end + else if (cyc == 24) begin + $monitoroff; + end + else if (cyc == 26) begin + $monitoron; + end + else if (cyc == 30) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end +endmodule diff --git a/test_regress/t/t_timescale.cpp b/test_regress/t/t_timescale.cpp index 1471cc2d3..f4a673912 100644 --- a/test_regress/t/t_timescale.cpp +++ b/test_regress/t/t_timescale.cpp @@ -50,6 +50,7 @@ int main(int argc, char** argv, char** env) { CHECK_RESULT(VL_TIME_STR_CONVERT(0), 0); top->final(); + VL_DO_DANGLING(delete top, top); printf("*-* All Finished *-*\n"); return 0; } diff --git a/test_regress/t/t_timescale_parse.cpp b/test_regress/t/t_timescale_parse.cpp index eb9fcc18a..c1464fe97 100644 --- a/test_regress/t/t_timescale_parse.cpp +++ b/test_regress/t/t_timescale_parse.cpp @@ -19,4 +19,5 @@ int main() { tb->eval(); tb->final(); + VL_DO_DANGLING(delete tb, tb); } diff --git a/test_regress/t/t_trace_cat.cpp b/test_regress/t/t_trace_cat.cpp index b4a9c6125..c0374121d 100644 --- a/test_regress/t/t_trace_cat.cpp +++ b/test_regress/t/t_trace_cat.cpp @@ -58,6 +58,7 @@ int main(int argc, char** argv, char** env) { } tfp->close(); top->final(); + VL_DO_DANGLING(delete top, top); printf("*-* All Finished *-*\n"); return 0; } diff --git a/test_regress/t/t_trace_complex.out b/test_regress/t/t_trace_complex.out index 1372dbc2c..e57a057af 100644 --- a/test_regress/t/t_trace_complex.out +++ b/test_regress/t/t_trace_complex.out @@ -1,53 +1,54 @@ $version Generated by VerilatedVcd $end -$date Tue Jan 21 18:15:27 2020 +$date Mon Nov 16 17:48:27 2020 $end $timescale 1ps $end $scope module top $end - $var wire 1 7" clk $end + $var wire 1 = clk $end $scope module $unit $end $var wire 1 # global_bit $end $upscope $end $scope module t $end - $var wire 1 7" clk $end - $var wire 32 + cyc [31:0] $end - $var wire 8 p" unpacked_array(-1) [7:0] $end - $var wire 8 o" unpacked_array(-2) [7:0] $end - $var wire 8 q" unpacked_array(0) [7:0] $end - $var real 64 E! v_arr_real(0) $end - $var real 64 G! v_arr_real(1) $end - $var wire 2 [ v_arrp [2:1] $end - $var wire 4 c v_arrp_arrp [3:0] $end - $var wire 4 k v_arrp_strp [3:0] $end - $var wire 1 ?" v_arru(1) $end - $var wire 1 @" v_arru(2) $end - $var wire 2 s v_arru_arrp(3) [2:1] $end - $var wire 2 t v_arru_arrp(4) [2:1] $end - $var wire 1 O" v_arru_arru(3)(1) $end - $var wire 1 W" v_arru_arru(3)(2) $end - $var wire 1 _" v_arru_arru(4)(1) $end - $var wire 1 g" v_arru_arru(4)(2) $end - $var wire 2 %! v_arru_strp(3) [1:0] $end - $var wire 2 -! v_arru_strp(4) [1:0] $end - $var wire 3 u! v_enumb [2:0] $end - $var wire 6 }! v_enumb2_str [5:0] $end - $var wire 32 e! v_enumed [31:0] $end - $var wire 32 m! v_enumed2 [31:0] $end - $var real 64 5! v_real $end - $var wire 64 3 v_str32x2 [63:0] $end - $var wire 2 C v_strp [1:0] $end - $var wire 4 K v_strp_strp [3:0] $end - $var wire 2 S v_unip_strp [1:0] $end + $var wire 1 G LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end + $var wire 1 = clk $end + $var wire 32 $ cyc [31:0] $end + $var wire 8 E unpacked_array(-1) [7:0] $end + $var wire 8 D unpacked_array(-2) [7:0] $end + $var wire 8 F unpacked_array(0) [7:0] $end + $var real 64 1 v_arr_real(0) $end + $var real 64 3 v_arr_real(1) $end + $var wire 2 ( v_arrp [2:1] $end + $var wire 4 ) v_arrp_arrp [3:0] $end + $var wire 4 * v_arrp_strp [3:0] $end + $var wire 1 > v_arru(1) $end + $var wire 1 ? v_arru(2) $end + $var wire 2 + v_arru_arrp(3) [2:1] $end + $var wire 2 , v_arru_arrp(4) [2:1] $end + $var wire 1 @ v_arru_arru(3)(1) $end + $var wire 1 A v_arru_arru(3)(2) $end + $var wire 1 B v_arru_arru(4)(1) $end + $var wire 1 C v_arru_arru(4)(2) $end + $var wire 2 - v_arru_strp(3) [1:0] $end + $var wire 2 . v_arru_strp(4) [1:0] $end + $var wire 3 9 v_enumb [2:0] $end + $var wire 6 : v_enumb2_str [5:0] $end + $var wire 32 7 v_enumed [31:0] $end + $var wire 32 8 v_enumed2 [31:0] $end + $var real 64 / v_real $end + $var wire 64 5 v_str32x2 [63:0] $end + $var wire 2 % v_strp [1:0] $end + $var wire 4 & v_strp_strp [3:0] $end + $var wire 2 ' v_unip_strp [1:0] $end $scope module p2 $end - $var wire 32 )# PARAM [31:0] $end + $var wire 32 H PARAM [31:0] $end $upscope $end $scope module p3 $end - $var wire 32 1# PARAM [31:0] $end + $var wire 32 I PARAM [31:0] $end $upscope $end $scope module unnamedblk1 $end - $var wire 32 '" b [31:0] $end + $var wire 32 ; b [31:0] $end $scope module unnamedblk2 $end - $var wire 32 /" a [31:0] $end + $var wire 32 < a [31:0] $end $upscope $end $upscope $end $upscope $end @@ -57,173 +58,174 @@ $enddefinitions $end #0 1# -b00000000000000000000000000000000 + -b0000000000000000000000000000000000000000000000000000000011111111 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0 5! -r0 E! -r0 G! -b00000000000000000000000000000000 e! -b00000000000000000000000000000000 m! -b000 u! -b000000 }! -b00000000000000000000000000000000 '" -b00000000000000000000000000000000 /" -07" -0?" -0@" -0O" -0W" -0_" -0g" -b00000000 o" -b00000000 p" -b00000000 q" -b00000000000000000000000000000010 )# -b00000000000000000000000000000011 1# +b00000000000000000000000000000000 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0 / +r0 1 +r0 3 +b0000000000000000000000000000000000000000000000000000000011111111 5 +b00000000000000000000000000000000 7 +b00000000000000000000000000000000 8 +b000 9 +b000000 : +b00000000000000000000000000000000 ; +b00000000000000000000000000000000 < +0= +0> +0? +0@ +0A +0B +0C +b00000000 D +b00000000 E +b00000000 F +0G +b00000000000000000000000000000010 H +b00000000000000000000000000000011 I #10 -b00000000000000000000000000000001 + -b0000000000000000000000000000000100000000000000000000000011111110 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.1 5! -r0.2 E! -r0.3 G! -b00000000000000000000000000000001 e! -b00000000000000000000000000000010 m! -b111 u! -b00000000000000000000000000000101 '" -b00000000000000000000000000000101 /" -17" +b00000000000000000000000000000001 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.1 / +r0.2 1 +r0.3 3 +b0000000000000000000000000000000100000000000000000000000011111110 5 +b00000000000000000000000000000001 7 +b00000000000000000000000000000010 8 +b111 9 +b00000000000000000000000000000101 ; +b00000000000000000000000000000101 < +1= #15 -07" +0= #20 -b00000000000000000000000000000010 + -b0000000000000000000000000000001000000000000000000000000011111101 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.2 5! -r0.4 E! -r0.6 G! -b00000000000000000000000000000010 e! -b00000000000000000000000000000100 m! -b110 u! -b111111 }! -17" +b00000000000000000000000000000010 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.2 / +r0.4 1 +r0.6 3 +b0000000000000000000000000000001000000000000000000000000011111101 5 +b00000000000000000000000000000010 7 +b00000000000000000000000000000100 8 +b110 9 +b111111 : +1= #25 -07" +0= #30 -b00000000000000000000000000000011 + -b0000000000000000000000000000001100000000000000000000000011111100 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.3 5! -r0.6000000000000001 E! -r0.8999999999999999 G! -b00000000000000000000000000000011 e! -b00000000000000000000000000000110 m! -b101 u! -b110110 }! -17" +b00000000000000000000000000000011 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.3 / +r0.6000000000000001 1 +r0.8999999999999999 3 +b0000000000000000000000000000001100000000000000000000000011111100 5 +b00000000000000000000000000000011 7 +b00000000000000000000000000000110 8 +b101 9 +b110110 : +1= #35 -07" +0= #40 -b00000000000000000000000000000100 + -b0000000000000000000000000000010000000000000000000000000011111011 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.4 5! -r0.8 E! -r1.2 G! -b00000000000000000000000000000100 e! -b00000000000000000000000000001000 m! -b100 u! -b101101 }! -17" +b00000000000000000000000000000100 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.4 / +r0.8 1 +r1.2 3 +b0000000000000000000000000000010000000000000000000000000011111011 5 +b00000000000000000000000000000100 7 +b00000000000000000000000000001000 8 +b100 9 +b101101 : +1= #45 -07" +0= #50 -b00000000000000000000000000000101 + -b0000000000000000000000000000010100000000000000000000000011111010 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.5 5! -r1 E! -r1.5 G! -b00000000000000000000000000000101 e! -b00000000000000000000000000001010 m! -b011 u! -b100100 }! -17" +b00000000000000000000000000000101 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.5 / +r1 1 +r1.5 3 +b0000000000000000000000000000010100000000000000000000000011111010 5 +b00000000000000000000000000000101 7 +b00000000000000000000000000001010 8 +b011 9 +b100100 : +1= #55 -07" +0= #60 -b00000000000000000000000000000110 + -b0000000000000000000000000000011000000000000000000000000011111001 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.6 5! -r1.2 E! -r1.8 G! -b00000000000000000000000000000110 e! -b00000000000000000000000000001100 m! -b010 u! -b011011 }! -17" +b00000000000000000000000000000110 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.6 / +r1.2 1 +r1.8 3 +b0000000000000000000000000000011000000000000000000000000011111001 5 +b00000000000000000000000000000110 7 +b00000000000000000000000000001100 8 +b010 9 +b011011 : +1= diff --git a/test_regress/t/t_trace_complex.v b/test_regress/t/t_trace_complex.v index 8f283e2e8..14489e9c5 100644 --- a/test_regress/t/t_trace_complex.v +++ b/test_regress/t/t_trace_complex.v @@ -8,21 +8,21 @@ bit global_bit; module t (clk); input clk; - integer cyc=0; + integer cyc=0; typedef struct packed { - bit b1; - bit b0; + bit b1; + bit b0; } strp_t; typedef struct packed { - strp_t x1; - strp_t x0; + strp_t x1; + strp_t x0; } strp_strp_t; typedef union packed { - strp_t x1; - strp_t x0; + strp_t x1; + strp_t x0; } unip_strp_t; typedef bit [2:1] arrp_t; @@ -35,20 +35,20 @@ module t (clk); typedef arrp_t arru_arrp_t [4:3]; typedef strp_t arru_strp_t [4:3]; - strp_t v_strp; - strp_strp_t v_strp_strp; - unip_strp_t v_unip_strp; - arrp_t v_arrp; - arrp_arrp_t v_arrp_arrp; - arrp_strp_t v_arrp_strp; - arru_t v_arru; - arru_arru_t v_arru_arru; - arru_arrp_t v_arru_arrp; - arru_strp_t v_arru_strp; + strp_t v_strp; + strp_strp_t v_strp_strp; + unip_strp_t v_unip_strp; + arrp_t v_arrp; + arrp_arrp_t v_arrp_arrp; + arrp_strp_t v_arrp_strp; + arru_t v_arru; + arru_arru_t v_arru_arru; + arru_arrp_t v_arru_arrp; + arru_strp_t v_arru_strp; real v_real; real v_arr_real [2]; - string v_string; + string v_string; string v_assoc[string]; initial v_assoc["key"] = "value"; @@ -73,6 +73,8 @@ module t (clk); logic [7:0] unpacked_array[-2:0]; + bit LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND; + p #(.PARAM(2)) p2 (); p #(.PARAM(3)) p3 (); @@ -93,18 +95,18 @@ module t (clk); v_enumb <= v_enumb - 1; v_enumb2_str <= {v_enumb, v_enumb}; for (integer b=3; b<=4; b++) begin - v_arru[b] <= ~v_arru[b]; - v_arru_strp[b] <= ~v_arru_strp[b]; - v_arru_arrp[b] <= ~v_arru_arrp[b]; - for (integer a=3; a<=4; a++) begin - v_arru_arru[a][b] = ~v_arru_arru[a][b]; - end + v_arru[b] <= ~v_arru[b]; + v_arru_strp[b] <= ~v_arru_strp[b]; + v_arru_arrp[b] <= ~v_arru_arrp[b]; + for (integer a=3; a<=4; a++) begin + v_arru_arru[a][b] = ~v_arru_arru[a][b]; + end end v_str32x2[0] <= v_str32x2[0] - 1; v_str32x2[1] <= v_str32x2[1] + 1; if (cyc == 5) begin - $write("*-* All Finished *-*\n"); - $finish; + $write("*-* All Finished *-*\n"); + $finish; end end endmodule diff --git a/test_regress/t/t_trace_complex_fst.out b/test_regress/t/t_trace_complex_fst.out index 8b05384c7..e4f264a8e 100644 --- a/test_regress/t/t_trace_complex_fst.out +++ b/test_regress/t/t_trace_complex_fst.out @@ -1,5 +1,5 @@ $date - Sun Apr 19 04:15:26 2020 + Mon Nov 16 17:51:08 2020 $end $version @@ -45,193 +45,197 @@ $var logic 6 : v_enumb2_str $end $var logic 8 ; unpacked_array(-2) $end $var logic 8 < unpacked_array(-1) $end $var logic 8 = unpacked_array(0) $end +$var bit 1 > LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end $scope module unnamedblk1 $end -$var integer 32 > b $end +$var integer 32 ? b $end $scope module unnamedblk2 $end -$var integer 32 ? a $end +$var integer 32 @ a $end $upscope $end $upscope $end $scope module p2 $end -$var parameter 32 @ PARAM $end +$var parameter 32 A PARAM $end $upscope $end $scope module p3 $end -$var parameter 32 A PARAM $end +$var parameter 32 B PARAM $end $upscope $end $upscope $end $scope module $unit $end -$var bit 1 B global_bit $end +$var bit 1 C global_bit $end $upscope $end $upscope $end $enddefinitions $end +#0 $dumpvars -0! -b00000000000000000000000000000000 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -0) -0* -0+ -0, -0- -0. -b00 / -b00 0 -b00 1 -b00 2 -r0 3 -r0 4 -r0 5 -b0000000000000000000000000000000000000000000000000000000011111111 6 -b00000000000000000000000000000000 7 -b00000000000000000000000000000000 8 -b000 9 -b000000 : -b00000000 ; -b00000000 < -b00000000 = -b00000000000000000000000000000000 > +1C +b00000000000000000000000000000011 B +b00000000000000000000000000000010 A +b00000000000000000000000000000000 @ b00000000000000000000000000000000 ? -b00000000000000000000000000000010 @ -b00000000000000000000000000000011 A -1B +0> +b00000000 = +b00000000 < +b00000000 ; +b000000 : +b000 9 +b00000000000000000000000000000000 8 +b00000000000000000000000000000000 7 +b0000000000000000000000000000000000000000000000000000000011111111 6 +r0 5 +r0 4 +r0 3 +b00 2 +b00 1 +b00 0 +b00 / +0. +0- +0, +0+ +0* +0) +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000000 " +0! +$end #10 -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > -b111 9 -b00000000000000000000000000000010 8 -b00000000000000000000000000000001 7 -b0000000000000000000000000000000100000000000000000000000011111110 6 -r0.3 5 -r0.2 4 -r0.1 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # -b00000000000000000000000000000001 " 1! +b00000000000000000000000000000001 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.1 3 +r0.2 4 +r0.3 5 +b0000000000000000000000000000000100000000000000000000000011111110 6 +b00000000000000000000000000000001 7 +b00000000000000000000000000000010 8 +b111 9 +b00000000000000000000000000000101 ? +b00000000000000000000000000000101 @ #15 0! #20 1! -b00000000000000000000000000000010 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.2 3 -r0.4 4 -r0.6 5 -b0000000000000000000000000000001000000000000000000000000011111101 6 -b00000000000000000000000000000010 7 -b00000000000000000000000000000100 8 b110 9 +b00000000000000000000000000000100 8 +b00000000000000000000000000000010 7 +b0000000000000000000000000000001000000000000000000000000011111101 6 +r0.6 5 +r0.4 4 +r0.2 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000010 " b111111 : #25 0! #30 1! b110110 : -b101 9 -b00000000000000000000000000000110 8 -b00000000000000000000000000000011 7 -b0000000000000000000000000000001100000000000000000000000011111100 6 -r0.8999999999999999 5 -r0.6000000000000001 4 -r0.3 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # b00000000000000000000000000000011 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.3 3 +r0.6000000000000001 4 +r0.8999999999999999 5 +b0000000000000000000000000000001100000000000000000000000011111100 6 +b00000000000000000000000000000011 7 +b00000000000000000000000000000110 8 +b101 9 #35 0! #40 1! -b00000000000000000000000000000100 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.4 3 -r0.8 4 -r1.2 5 -b0000000000000000000000000000010000000000000000000000000011111011 6 -b00000000000000000000000000000100 7 -b00000000000000000000000000001000 8 b100 9 +b00000000000000000000000000001000 8 +b00000000000000000000000000000100 7 +b0000000000000000000000000000010000000000000000000000000011111011 6 +r1.2 5 +r0.8 4 +r0.4 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000100 " b101101 : #45 0! #50 1! b100100 : -b011 9 -b00000000000000000000000000001010 8 -b00000000000000000000000000000101 7 -b0000000000000000000000000000010100000000000000000000000011111010 6 -r1.5 5 -r1 4 -r0.5 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # b00000000000000000000000000000101 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.5 3 +r1 4 +r1.5 5 +b0000000000000000000000000000010100000000000000000000000011111010 6 +b00000000000000000000000000000101 7 +b00000000000000000000000000001010 8 +b011 9 #55 0! #60 1! -b00000000000000000000000000000110 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.6 3 -r1.2 4 -r1.8 5 -b0000000000000000000000000000011000000000000000000000000011111001 6 -b00000000000000000000000000000110 7 -b00000000000000000000000000001100 8 b010 9 +b00000000000000000000000000001100 8 +b00000000000000000000000000000110 7 +b0000000000000000000000000000011000000000000000000000000011111001 6 +r1.8 5 +r1.2 4 +r0.6 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000110 " b011011 : diff --git a/test_regress/t/t_trace_complex_params.out b/test_regress/t/t_trace_complex_params.out index b328bd887..88690fd62 100644 --- a/test_regress/t/t_trace_complex_params.out +++ b/test_regress/t/t_trace_complex_params.out @@ -1,53 +1,54 @@ $version Generated by VerilatedVcd $end -$date Tue Jan 21 18:15:28 2020 +$date Mon Nov 16 17:51:08 2020 $end $timescale 1ps $end $scope module top $end - $var wire 1 7" clk $end + $var wire 1 = clk $end $scope module $unit $end $var wire 1 # global_bit $end $upscope $end $scope module t $end - $var wire 1 7" clk $end - $var wire 32 + cyc [31:0] $end - $var wire 8 p" unpacked_array(-1) [7:0] $end - $var wire 8 o" unpacked_array(-2) [7:0] $end - $var wire 8 q" unpacked_array(0) [7:0] $end - $var real 64 E! v_arr_real(0) $end - $var real 64 G! v_arr_real(1) $end - $var wire 2 [ v_arrp [2:1] $end - $var wire 4 c v_arrp_arrp [3:0] $end - $var wire 4 k v_arrp_strp [3:0] $end - $var wire 1 ?" v_arru(1) $end - $var wire 1 @" v_arru(2) $end - $var wire 2 s v_arru_arrp(3) [2:1] $end - $var wire 2 t v_arru_arrp(4) [2:1] $end - $var wire 1 O" v_arru_arru(3)(1) $end - $var wire 1 W" v_arru_arru(3)(2) $end - $var wire 1 _" v_arru_arru(4)(1) $end - $var wire 1 g" v_arru_arru(4)(2) $end - $var wire 2 %! v_arru_strp(3) [1:0] $end - $var wire 2 -! v_arru_strp(4) [1:0] $end - $var wire 3 u! v_enumb [2:0] $end - $var wire 6 }! v_enumb2_str [5:0] $end - $var wire 32 e! v_enumed [31:0] $end - $var wire 32 m! v_enumed2 [31:0] $end - $var real 64 5! v_real $end - $var wire 64 3 v_str32x2 [63:0] $end - $var wire 2 C v_strp [1:0] $end - $var wire 4 K v_strp_strp [3:0] $end - $var wire 2 S v_unip_strp [1:0] $end + $var wire 1 G LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end + $var wire 1 = clk $end + $var wire 32 $ cyc [31:0] $end + $var wire 8 E unpacked_array(-1) [7:0] $end + $var wire 8 D unpacked_array(-2) [7:0] $end + $var wire 8 F unpacked_array(0) [7:0] $end + $var real 64 1 v_arr_real(0) $end + $var real 64 3 v_arr_real(1) $end + $var wire 2 ( v_arrp [2:1] $end + $var wire 4 ) v_arrp_arrp [3:0] $end + $var wire 4 * v_arrp_strp [3:0] $end + $var wire 1 > v_arru(1) $end + $var wire 1 ? v_arru(2) $end + $var wire 2 + v_arru_arrp(3) [2:1] $end + $var wire 2 , v_arru_arrp(4) [2:1] $end + $var wire 1 @ v_arru_arru(3)(1) $end + $var wire 1 A v_arru_arru(3)(2) $end + $var wire 1 B v_arru_arru(4)(1) $end + $var wire 1 C v_arru_arru(4)(2) $end + $var wire 2 - v_arru_strp(3) [1:0] $end + $var wire 2 . v_arru_strp(4) [1:0] $end + $var wire 3 9 v_enumb [2:0] $end + $var wire 6 : v_enumb2_str [5:0] $end + $var wire 32 7 v_enumed [31:0] $end + $var wire 32 8 v_enumed2 [31:0] $end + $var real 64 / v_real $end + $var wire 64 5 v_str32x2 [63:0] $end + $var wire 2 % v_strp [1:0] $end + $var wire 4 & v_strp_strp [3:0] $end + $var wire 2 ' v_unip_strp [1:0] $end $scope module p2 $end - $var wire 32 )# PARAM [31:0] $end + $var wire 32 H PARAM [31:0] $end $upscope $end $scope module p3 $end - $var wire 32 1# PARAM [31:0] $end + $var wire 32 I PARAM [31:0] $end $upscope $end $scope module unnamedblk1 $end - $var wire 32 '" b [31:0] $end + $var wire 32 ; b [31:0] $end $scope module unnamedblk2 $end - $var wire 32 /" a [31:0] $end + $var wire 32 < a [31:0] $end $upscope $end $upscope $end $upscope $end @@ -57,173 +58,174 @@ $enddefinitions $end #0 1# -b00000000000000000000000000000000 + -b0000000000000000000000000000000000000000000000000000000011111111 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0 5! -r0 E! -r0 G! -b00000000000000000000000000000000 e! -b00000000000000000000000000000000 m! -b000 u! -b000000 }! -b00000000000000000000000000000000 '" -b00000000000000000000000000000000 /" -07" -0?" -0@" -0O" -0W" -0_" -0g" -b00000000 o" -b00000000 p" -b00000000 q" -b00000000000000000000000000000010 )# -b00000000000000000000000000000011 1# +b00000000000000000000000000000000 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0 / +r0 1 +r0 3 +b0000000000000000000000000000000000000000000000000000000011111111 5 +b00000000000000000000000000000000 7 +b00000000000000000000000000000000 8 +b000 9 +b000000 : +b00000000000000000000000000000000 ; +b00000000000000000000000000000000 < +0= +0> +0? +0@ +0A +0B +0C +b00000000 D +b00000000 E +b00000000 F +0G +b00000000000000000000000000000010 H +b00000000000000000000000000000011 I #10 -b00000000000000000000000000000001 + -b0000000000000000000000000000000100000000000000000000000011111110 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.1 5! -r0.2 E! -r0.3 G! -b00000000000000000000000000000001 e! -b00000000000000000000000000000010 m! -b111 u! -b00000000000000000000000000000101 '" -b00000000000000000000000000000101 /" -17" +b00000000000000000000000000000001 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.1 / +r0.2 1 +r0.3 3 +b0000000000000000000000000000000100000000000000000000000011111110 5 +b00000000000000000000000000000001 7 +b00000000000000000000000000000010 8 +b111 9 +b00000000000000000000000000000101 ; +b00000000000000000000000000000101 < +1= #15 -07" +0= #20 -b00000000000000000000000000000010 + -b0000000000000000000000000000001000000000000000000000000011111101 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.2 5! -r0.4 E! -r0.6 G! -b00000000000000000000000000000010 e! -b00000000000000000000000000000100 m! -b110 u! -b111111 }! -17" +b00000000000000000000000000000010 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.2 / +r0.4 1 +r0.6 3 +b0000000000000000000000000000001000000000000000000000000011111101 5 +b00000000000000000000000000000010 7 +b00000000000000000000000000000100 8 +b110 9 +b111111 : +1= #25 -07" +0= #30 -b00000000000000000000000000000011 + -b0000000000000000000000000000001100000000000000000000000011111100 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.3 5! -r0.6000000000000001 E! -r0.8999999999999999 G! -b00000000000000000000000000000011 e! -b00000000000000000000000000000110 m! -b101 u! -b110110 }! -17" +b00000000000000000000000000000011 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.3 / +r0.6000000000000001 1 +r0.8999999999999999 3 +b0000000000000000000000000000001100000000000000000000000011111100 5 +b00000000000000000000000000000011 7 +b00000000000000000000000000000110 8 +b101 9 +b110110 : +1= #35 -07" +0= #40 -b00000000000000000000000000000100 + -b0000000000000000000000000000010000000000000000000000000011111011 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.4 5! -r0.8 E! -r1.2 G! -b00000000000000000000000000000100 e! -b00000000000000000000000000001000 m! -b100 u! -b101101 }! -17" +b00000000000000000000000000000100 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.4 / +r0.8 1 +r1.2 3 +b0000000000000000000000000000010000000000000000000000000011111011 5 +b00000000000000000000000000000100 7 +b00000000000000000000000000001000 8 +b100 9 +b101101 : +1= #45 -07" +0= #50 -b00000000000000000000000000000101 + -b0000000000000000000000000000010100000000000000000000000011111010 3 -b11 C -b1111 K -b11 S -b11 [ -b1111 c -b1111 k -b11 s -b11 t -b11 %! -b11 -! -r0.5 5! -r1 E! -r1.5 G! -b00000000000000000000000000000101 e! -b00000000000000000000000000001010 m! -b011 u! -b100100 }! -17" +b00000000000000000000000000000101 $ +b11 % +b1111 & +b11 ' +b11 ( +b1111 ) +b1111 * +b11 + +b11 , +b11 - +b11 . +r0.5 / +r1 1 +r1.5 3 +b0000000000000000000000000000010100000000000000000000000011111010 5 +b00000000000000000000000000000101 7 +b00000000000000000000000000001010 8 +b011 9 +b100100 : +1= #55 -07" +0= #60 -b00000000000000000000000000000110 + -b0000000000000000000000000000011000000000000000000000000011111001 3 -b00 C -b0000 K -b00 S -b00 [ -b0000 c -b0000 k -b00 s -b00 t -b00 %! -b00 -! -r0.6 5! -r1.2 E! -r1.8 G! -b00000000000000000000000000000110 e! -b00000000000000000000000000001100 m! -b010 u! -b011011 }! -17" +b00000000000000000000000000000110 $ +b00 % +b0000 & +b00 ' +b00 ( +b0000 ) +b0000 * +b00 + +b00 , +b00 - +b00 . +r0.6 / +r1.2 1 +r1.8 3 +b0000000000000000000000000000011000000000000000000000000011111001 5 +b00000000000000000000000000000110 7 +b00000000000000000000000000001100 8 +b010 9 +b011011 : +1= diff --git a/test_regress/t/t_trace_complex_params_fst.out b/test_regress/t/t_trace_complex_params_fst.out index c94200384..e4f264a8e 100644 --- a/test_regress/t/t_trace_complex_params_fst.out +++ b/test_regress/t/t_trace_complex_params_fst.out @@ -1,5 +1,5 @@ $date - Sun Apr 19 04:15:31 2020 + Mon Nov 16 17:51:08 2020 $end $version @@ -45,193 +45,197 @@ $var logic 6 : v_enumb2_str $end $var logic 8 ; unpacked_array(-2) $end $var logic 8 < unpacked_array(-1) $end $var logic 8 = unpacked_array(0) $end +$var bit 1 > LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end $scope module unnamedblk1 $end -$var integer 32 > b $end +$var integer 32 ? b $end $scope module unnamedblk2 $end -$var integer 32 ? a $end +$var integer 32 @ a $end $upscope $end $upscope $end $scope module p2 $end -$var parameter 32 @ PARAM $end +$var parameter 32 A PARAM $end $upscope $end $scope module p3 $end -$var parameter 32 A PARAM $end +$var parameter 32 B PARAM $end $upscope $end $upscope $end $scope module $unit $end -$var bit 1 B global_bit $end +$var bit 1 C global_bit $end $upscope $end $upscope $end $enddefinitions $end +#0 $dumpvars -0! -b00000000000000000000000000000000 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -0) -0* -0+ -0, -0- -0. -b00 / -b00 0 -b00 1 -b00 2 -r0 3 -r0 4 -r0 5 -b0000000000000000000000000000000000000000000000000000000011111111 6 -b00000000000000000000000000000000 7 -b00000000000000000000000000000000 8 -b000 9 -b000000 : -b00000000 ; -b00000000 < -b00000000 = -b00000000000000000000000000000000 > +1C +b00000000000000000000000000000011 B +b00000000000000000000000000000010 A +b00000000000000000000000000000000 @ b00000000000000000000000000000000 ? -b00000000000000000000000000000010 @ -b00000000000000000000000000000011 A -1B +0> +b00000000 = +b00000000 < +b00000000 ; +b000000 : +b000 9 +b00000000000000000000000000000000 8 +b00000000000000000000000000000000 7 +b0000000000000000000000000000000000000000000000000000000011111111 6 +r0 5 +r0 4 +r0 3 +b00 2 +b00 1 +b00 0 +b00 / +0. +0- +0, +0+ +0* +0) +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000000 " +0! +$end #10 -b00000000000000000000000000000101 ? -b00000000000000000000000000000101 > -b111 9 -b00000000000000000000000000000010 8 -b00000000000000000000000000000001 7 -b0000000000000000000000000000000100000000000000000000000011111110 6 -r0.3 5 -r0.2 4 -r0.1 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # -b00000000000000000000000000000001 " 1! +b00000000000000000000000000000001 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.1 3 +r0.2 4 +r0.3 5 +b0000000000000000000000000000000100000000000000000000000011111110 6 +b00000000000000000000000000000001 7 +b00000000000000000000000000000010 8 +b111 9 +b00000000000000000000000000000101 ? +b00000000000000000000000000000101 @ #15 0! #20 1! -b00000000000000000000000000000010 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.2 3 -r0.4 4 -r0.6 5 -b0000000000000000000000000000001000000000000000000000000011111101 6 -b00000000000000000000000000000010 7 -b00000000000000000000000000000100 8 b110 9 +b00000000000000000000000000000100 8 +b00000000000000000000000000000010 7 +b0000000000000000000000000000001000000000000000000000000011111101 6 +r0.6 5 +r0.4 4 +r0.2 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000010 " b111111 : #25 0! #30 1! b110110 : -b101 9 -b00000000000000000000000000000110 8 -b00000000000000000000000000000011 7 -b0000000000000000000000000000001100000000000000000000000011111100 6 -r0.8999999999999999 5 -r0.6000000000000001 4 -r0.3 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # b00000000000000000000000000000011 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.3 3 +r0.6000000000000001 4 +r0.8999999999999999 5 +b0000000000000000000000000000001100000000000000000000000011111100 6 +b00000000000000000000000000000011 7 +b00000000000000000000000000000110 8 +b101 9 #35 0! #40 1! -b00000000000000000000000000000100 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.4 3 -r0.8 4 -r1.2 5 -b0000000000000000000000000000010000000000000000000000000011111011 6 -b00000000000000000000000000000100 7 -b00000000000000000000000000001000 8 b100 9 +b00000000000000000000000000001000 8 +b00000000000000000000000000000100 7 +b0000000000000000000000000000010000000000000000000000000011111011 6 +r1.2 5 +r0.8 4 +r0.4 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000100 " b101101 : #45 0! #50 1! b100100 : -b011 9 -b00000000000000000000000000001010 8 -b00000000000000000000000000000101 7 -b0000000000000000000000000000010100000000000000000000000011111010 6 -r1.5 5 -r1 4 -r0.5 3 -b11 2 -b11 1 -b11 0 -b11 / -b1111 ( -b1111 ' -b11 & -b11 % -b1111 $ -b11 # b00000000000000000000000000000101 " +b11 # +b1111 $ +b11 % +b11 & +b1111 ' +b1111 ( +b11 / +b11 0 +b11 1 +b11 2 +r0.5 3 +r1 4 +r1.5 5 +b0000000000000000000000000000010100000000000000000000000011111010 6 +b00000000000000000000000000000101 7 +b00000000000000000000000000001010 8 +b011 9 #55 0! #60 1! -b00000000000000000000000000000110 " -b00 # -b0000 $ -b00 % -b00 & -b0000 ' -b0000 ( -b00 / -b00 0 -b00 1 -b00 2 -r0.6 3 -r1.2 4 -r1.8 5 -b0000000000000000000000000000011000000000000000000000000011111001 6 -b00000000000000000000000000000110 7 -b00000000000000000000000000001100 8 b010 9 +b00000000000000000000000000001100 8 +b00000000000000000000000000000110 7 +b0000000000000000000000000000011000000000000000000000000011111001 6 +r1.8 5 +r1.2 4 +r0.6 3 +b00 2 +b00 1 +b00 0 +b00 / +b0000 ( +b0000 ' +b00 & +b00 % +b0000 $ +b00 # +b00000000000000000000000000000110 " b011011 : diff --git a/test_regress/t/t_trace_complex_structs.out b/test_regress/t/t_trace_complex_structs.out index f22f6d3be..dad2d3736 100644 --- a/test_regress/t/t_trace_complex_structs.out +++ b/test_regress/t/t_trace_complex_structs.out @@ -1,90 +1,91 @@ $version Generated by VerilatedVcd $end -$date Tue Jan 21 18:55:13 2020 +$date Mon Nov 16 17:51:09 2020 $end $timescale 1ps $end $scope module top $end - $var wire 1 9# clk $end + $var wire 1 I clk $end $scope module $unit $end $var wire 1 # global_bit $end $upscope $end $scope module t $end - $var wire 1 9# clk $end - $var wire 32 + cyc [31:0] $end - $var wire 8 r# unpacked_array(-1) [7:0] $end - $var wire 8 q# unpacked_array(-2) [7:0] $end - $var wire 8 s# unpacked_array(0) [7:0] $end - $var real 64 ?" v_arr_real(0) $end - $var real 64 A" v_arr_real(1) $end - $var wire 2 %! v_arrp [2:1] $end - $var wire 2 -! v_arrp_arrp(3) [2:1] $end - $var wire 2 5! v_arrp_arrp(4) [2:1] $end - $var wire 1 A# v_arru(1) $end - $var wire 1 B# v_arru(2) $end - $var wire 2 ]! v_arru_arrp(3) [2:1] $end - $var wire 2 ^! v_arru_arrp(4) [2:1] $end - $var wire 1 Q# v_arru_arru(3)(1) $end - $var wire 1 Y# v_arru_arru(3)(2) $end - $var wire 1 a# v_arru_arru(4)(1) $end - $var wire 1 i# v_arru_arru(4)(2) $end - $var wire 3 o" v_enumb [2:0] $end - $var wire 32 _" v_enumed [31:0] $end - $var wire 32 g" v_enumed2 [31:0] $end - $var real 64 /" v_real $end + $var wire 1 S LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end + $var wire 1 I clk $end + $var wire 32 $ cyc [31:0] $end + $var wire 8 Q unpacked_array(-1) [7:0] $end + $var wire 8 P unpacked_array(-2) [7:0] $end + $var wire 8 R unpacked_array(0) [7:0] $end + $var real 64 < v_arr_real(0) $end + $var real 64 > v_arr_real(1) $end + $var wire 2 - v_arrp [2:1] $end + $var wire 2 . v_arrp_arrp(3) [2:1] $end + $var wire 2 / v_arrp_arrp(4) [2:1] $end + $var wire 1 J v_arru(1) $end + $var wire 1 K v_arru(2) $end + $var wire 2 4 v_arru_arrp(3) [2:1] $end + $var wire 2 5 v_arru_arrp(4) [2:1] $end + $var wire 1 L v_arru_arru(3)(1) $end + $var wire 1 M v_arru_arru(3)(2) $end + $var wire 1 N v_arru_arru(4)(1) $end + $var wire 1 O v_arru_arru(4)(2) $end + $var wire 3 D v_enumb [2:0] $end + $var wire 32 B v_enumed [31:0] $end + $var wire 32 C v_enumed2 [31:0] $end + $var real 64 : v_real $end $scope module unnamedblk1 $end - $var wire 32 )# b [31:0] $end + $var wire 32 G b [31:0] $end $scope module unnamedblk2 $end - $var wire 32 1# a [31:0] $end + $var wire 32 H a [31:0] $end $upscope $end $upscope $end $scope module v_arrp_strp(3) $end - $var wire 1 E! b0 $end - $var wire 1 =! b1 $end + $var wire 1 1 b0 $end + $var wire 1 0 b1 $end $upscope $end $scope module v_arrp_strp(4) $end - $var wire 1 U! b0 $end - $var wire 1 M! b1 $end + $var wire 1 3 b0 $end + $var wire 1 2 b1 $end $upscope $end $scope module v_arru_strp(3) $end - $var wire 1 u! b0 $end - $var wire 1 m! b1 $end + $var wire 1 7 b0 $end + $var wire 1 6 b1 $end $upscope $end $scope module v_arru_strp(4) $end - $var wire 1 '" b0 $end - $var wire 1 }! b1 $end + $var wire 1 9 b0 $end + $var wire 1 8 b1 $end $upscope $end $scope module v_enumb2_str $end - $var wire 3 w" a [2:0] $end - $var wire 3 !# b [2:0] $end + $var wire 3 E a [2:0] $end + $var wire 3 F b [2:0] $end $upscope $end $scope module v_str32x2(0) $end - $var wire 32 3 data [31:0] $end + $var wire 32 @ data [31:0] $end $upscope $end $scope module v_str32x2(1) $end - $var wire 32 ; data [31:0] $end + $var wire 32 A data [31:0] $end $upscope $end $scope module v_strp $end - $var wire 1 K b0 $end - $var wire 1 C b1 $end + $var wire 1 & b0 $end + $var wire 1 % b1 $end $upscope $end $scope module v_strp_strp $end $scope module x0 $end - $var wire 1 k b0 $end - $var wire 1 c b1 $end + $var wire 1 * b0 $end + $var wire 1 ) b1 $end $upscope $end $scope module x1 $end - $var wire 1 [ b0 $end - $var wire 1 S b1 $end + $var wire 1 ( b0 $end + $var wire 1 ' b1 $end $upscope $end $upscope $end $scope module v_unip_strp $end $scope module x0 $end - $var wire 1 { b0 $end - $var wire 1 s b1 $end + $var wire 1 , b0 $end + $var wire 1 + b1 $end $upscope $end $scope module x1 $end - $var wire 1 { b0 $end - $var wire 1 s b1 $end + $var wire 1 , b0 $end + $var wire 1 + b1 $end $upscope $end $upscope $end $upscope $end @@ -94,261 +95,262 @@ $enddefinitions $end #0 1# -b00000000000000000000000000000000 + -b00000000000000000000000011111111 3 -b00000000000000000000000000000000 ; -0C +b00000000000000000000000000000000 $ +0% +0& +0' +0( +0) +0* +0+ +0, +b00 - +b00 . +b00 / +00 +01 +02 +03 +b00 4 +b00 5 +06 +07 +08 +09 +r0 : +r0 < +r0 > +b00000000000000000000000011111111 @ +b00000000000000000000000000000000 A +b00000000000000000000000000000000 B +b00000000000000000000000000000000 C +b000 D +b000 E +b000 F +b00000000000000000000000000000000 G +b00000000000000000000000000000000 H +0I +0J 0K +0L +0M +0N +0O +b00000000 P +b00000000 Q +b00000000 R 0S -0[ -0c -0k -0s -0{ -b00 %! -b00 -! -b00 5! -0=! -0E! -0M! -0U! -b00 ]! -b00 ^! -0m! -0u! -0}! -0'" -r0 /" -r0 ?" -r0 A" -b00000000000000000000000000000000 _" -b00000000000000000000000000000000 g" -b000 o" -b000 w" -b000 !# -b00000000000000000000000000000000 )# -b00000000000000000000000000000000 1# -09# -0A# -0B# -0Q# -0Y# -0a# -0i# -b00000000 q# -b00000000 r# -b00000000 s# #10 -b00000000000000000000000000000001 + -b00000000000000000000000011111110 3 -b00000000000000000000000000000001 ; -1C -1K -1S -1[ -1c -1k -1s -1{ -b11 %! -b11 -! -b11 5! -1=! -1E! -1M! -1U! -b11 ]! -b11 ^! -1m! -1u! -1}! -1'" -r0.1 /" -r0.2 ?" -r0.3 A" -b00000000000000000000000000000001 _" -b00000000000000000000000000000010 g" -b111 o" -b00000000000000000000000000000101 )# -b00000000000000000000000000000101 1# -19# +b00000000000000000000000000000001 $ +1% +1& +1' +1( +1) +1* +1+ +1, +b11 - +b11 . +b11 / +10 +11 +12 +13 +b11 4 +b11 5 +16 +17 +18 +19 +r0.1 : +r0.2 < +r0.3 > +b00000000000000000000000011111110 @ +b00000000000000000000000000000001 A +b00000000000000000000000000000001 B +b00000000000000000000000000000010 C +b111 D +b00000000000000000000000000000101 G +b00000000000000000000000000000101 H +1I #15 -09# +0I #20 -b00000000000000000000000000000010 + -b00000000000000000000000011111101 3 -b00000000000000000000000000000010 ; -0C -0K -0S -0[ -0c -0k -0s -0{ -b00 %! -b00 -! -b00 5! -0=! -0E! -0M! -0U! -b00 ]! -b00 ^! -0m! -0u! -0}! -0'" -r0.2 /" -r0.4 ?" -r0.6 A" -b00000000000000000000000000000010 _" -b00000000000000000000000000000100 g" -b110 o" -b111 w" -b111 !# -19# +b00000000000000000000000000000010 $ +0% +0& +0' +0( +0) +0* +0+ +0, +b00 - +b00 . +b00 / +00 +01 +02 +03 +b00 4 +b00 5 +06 +07 +08 +09 +r0.2 : +r0.4 < +r0.6 > +b00000000000000000000000011111101 @ +b00000000000000000000000000000010 A +b00000000000000000000000000000010 B +b00000000000000000000000000000100 C +b110 D +b111 E +b111 F +1I #25 -09# +0I #30 -b00000000000000000000000000000011 + -b00000000000000000000000011111100 3 -b00000000000000000000000000000011 ; -1C -1K -1S -1[ -1c -1k -1s -1{ -b11 %! -b11 -! -b11 5! -1=! -1E! -1M! -1U! -b11 ]! -b11 ^! -1m! -1u! -1}! -1'" -r0.3 /" -r0.6000000000000001 ?" -r0.8999999999999999 A" -b00000000000000000000000000000011 _" -b00000000000000000000000000000110 g" -b101 o" -b110 w" -b110 !# -19# +b00000000000000000000000000000011 $ +1% +1& +1' +1( +1) +1* +1+ +1, +b11 - +b11 . +b11 / +10 +11 +12 +13 +b11 4 +b11 5 +16 +17 +18 +19 +r0.3 : +r0.6000000000000001 < +r0.8999999999999999 > +b00000000000000000000000011111100 @ +b00000000000000000000000000000011 A +b00000000000000000000000000000011 B +b00000000000000000000000000000110 C +b101 D +b110 E +b110 F +1I #35 -09# +0I #40 -b00000000000000000000000000000100 + -b00000000000000000000000011111011 3 -b00000000000000000000000000000100 ; -0C -0K -0S -0[ -0c -0k -0s -0{ -b00 %! -b00 -! -b00 5! -0=! -0E! -0M! -0U! -b00 ]! -b00 ^! -0m! -0u! -0}! -0'" -r0.4 /" -r0.8 ?" -r1.2 A" -b00000000000000000000000000000100 _" -b00000000000000000000000000001000 g" -b100 o" -b101 w" -b101 !# -19# +b00000000000000000000000000000100 $ +0% +0& +0' +0( +0) +0* +0+ +0, +b00 - +b00 . +b00 / +00 +01 +02 +03 +b00 4 +b00 5 +06 +07 +08 +09 +r0.4 : +r0.8 < +r1.2 > +b00000000000000000000000011111011 @ +b00000000000000000000000000000100 A +b00000000000000000000000000000100 B +b00000000000000000000000000001000 C +b100 D +b101 E +b101 F +1I #45 -09# +0I #50 -b00000000000000000000000000000101 + -b00000000000000000000000011111010 3 -b00000000000000000000000000000101 ; -1C -1K -1S -1[ -1c -1k -1s -1{ -b11 %! -b11 -! -b11 5! -1=! -1E! -1M! -1U! -b11 ]! -b11 ^! -1m! -1u! -1}! -1'" -r0.5 /" -r1 ?" -r1.5 A" -b00000000000000000000000000000101 _" -b00000000000000000000000000001010 g" -b011 o" -b100 w" -b100 !# -19# +b00000000000000000000000000000101 $ +1% +1& +1' +1( +1) +1* +1+ +1, +b11 - +b11 . +b11 / +10 +11 +12 +13 +b11 4 +b11 5 +16 +17 +18 +19 +r0.5 : +r1 < +r1.5 > +b00000000000000000000000011111010 @ +b00000000000000000000000000000101 A +b00000000000000000000000000000101 B +b00000000000000000000000000001010 C +b011 D +b100 E +b100 F +1I #55 -09# +0I #60 -b00000000000000000000000000000110 + -b00000000000000000000000011111001 3 -b00000000000000000000000000000110 ; -0C -0K -0S -0[ -0c -0k -0s -0{ -b00 %! -b00 -! -b00 5! -0=! -0E! -0M! -0U! -b00 ]! -b00 ^! -0m! -0u! -0}! -0'" -r0.6 /" -r1.2 ?" -r1.8 A" -b00000000000000000000000000000110 _" -b00000000000000000000000000001100 g" -b010 o" -b011 w" -b011 !# -19# +b00000000000000000000000000000110 $ +0% +0& +0' +0( +0) +0* +0+ +0, +b00 - +b00 . +b00 / +00 +01 +02 +03 +b00 4 +b00 5 +06 +07 +08 +09 +r0.6 : +r1.2 < +r1.8 > +b00000000000000000000000011111001 @ +b00000000000000000000000000000110 A +b00000000000000000000000000000110 B +b00000000000000000000000000001100 C +b010 D +b011 E +b011 F +1I diff --git a/test_regress/t/t_trace_complex_structs_fst.out b/test_regress/t/t_trace_complex_structs_fst.out index 1cde8a16c..3e0bcd6f8 100644 --- a/test_regress/t/t_trace_complex_structs_fst.out +++ b/test_regress/t/t_trace_complex_structs_fst.out @@ -1,5 +1,5 @@ $date - Sun Apr 19 04:15:33 2020 + Mon Nov 16 17:51:13 2020 $end $version @@ -90,275 +90,279 @@ $upscope $end $var logic 8 H unpacked_array(-2) $end $var logic 8 I unpacked_array(-1) $end $var logic 8 J unpacked_array(0) $end +$var bit 1 K LONGSTART_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_a_very_long_name_which_will_get_hashed_LONGEND $end $scope module unnamedblk1 $end -$var integer 32 K b $end +$var integer 32 L b $end $scope module unnamedblk2 $end -$var integer 32 L a $end +$var integer 32 M a $end $upscope $end $upscope $end $upscope $end $scope module $unit $end -$var bit 1 M global_bit $end +$var bit 1 N global_bit $end $upscope $end $upscope $end $enddefinitions $end +#0 $dumpvars -0! -b00000000000000000000000000000000 " -0# -0$ -0% -0& -0' -0( -0) -0* -b00 + -b00 , -b00 - -0. -0/ -00 -01 -02 -03 -04 -05 -06 -07 -b00 8 -b00 9 -0: -0; -0< -0= -r0 > -r0 ? -r0 @ -b00000000000000000000000011111111 A -b00000000000000000000000000000000 B -b00000000000000000000000000000000 C -b00000000000000000000000000000000 D -b000 E -b000 F -b000 G -b00000000 H -b00000000 I -b00000000 J -b00000000000000000000000000000000 K +1N +b00000000000000000000000000000000 M b00000000000000000000000000000000 L -1M +0K +b00000000 J +b00000000 I +b00000000 H +b000 G +b000 F +b000 E +b00000000000000000000000000000000 D +b00000000000000000000000000000000 C +b00000000000000000000000000000000 B +b00000000000000000000000011111111 A +r0 @ +r0 ? +r0 > +0= +0< +0; +0: +b00 9 +b00 8 +07 +06 +05 +04 +03 +02 +01 +00 +0/ +0. +b00 - +b00 , +b00 + +0* +0) +0( +0' +0& +0% +0$ +0# +b00000000000000000000000000000000 " +0! +$end #10 -b00000000000000000000000000000101 L -b00000000000000000000000000000101 K -b111 E -b00000000000000000000000000000010 D -b00000000000000000000000000000001 C -b00000000000000000000000000000001 B -b00000000000000000000000011111110 A -r0.3 @ -r0.2 ? -r0.1 > -1= -1< -1; -1: -b11 9 -b11 8 -11 -10 -1/ -1. -b11 - -b11 , -b11 + -1* -1) -1( -1' -1& -1% -1$ -1# -b00000000000000000000000000000001 " 1! +b00000000000000000000000000000001 " +1# +1$ +1% +1& +1' +1( +1) +1* +b11 + +b11 , +b11 - +1. +1/ +10 +11 +b11 8 +b11 9 +1: +1; +1< +1= +r0.1 > +r0.2 ? +r0.3 @ +b00000000000000000000000011111110 A +b00000000000000000000000000000001 B +b00000000000000000000000000000001 C +b00000000000000000000000000000010 D +b111 E +b00000000000000000000000000000101 L +b00000000000000000000000000000101 M #15 0! #20 1! -b00000000000000000000000000000010 " -0# -0$ -0% -0& -0' -0( -0) -0* -b00 + -b00 , -b00 - -0. -0/ -00 -01 -b00 8 -b00 9 -0: -0; -0< -0= -r0.2 > -r0.4 ? -r0.6 @ -b00000000000000000000000011111101 A -b00000000000000000000000000000010 B -b00000000000000000000000000000010 C -b00000000000000000000000000000100 D b110 E -b111 G +b00000000000000000000000000000100 D +b00000000000000000000000000000010 C +b00000000000000000000000000000010 B +b00000000000000000000000011111101 A +r0.6 @ +r0.4 ? +r0.2 > +0= +0< +0; +0: +b00 9 +b00 8 +01 +00 +0/ +0. +b00 - +b00 , +b00 + +0* +0) +0( +0' +0& +0% +0$ +0# +b00000000000000000000000000000010 " b111 F +b111 G #25 0! #30 1! -b110 F b110 G -b101 E -b00000000000000000000000000000110 D -b00000000000000000000000000000011 C -b00000000000000000000000000000011 B -b00000000000000000000000011111100 A -r0.8999999999999999 @ -r0.6000000000000001 ? -r0.3 > -1= -1< -1; -1: -b11 9 -b11 8 -11 -10 -1/ -1. -b11 - -b11 , -b11 + -1* -1) -1( -1' -1& -1% -1$ -1# +b110 F b00000000000000000000000000000011 " +1# +1$ +1% +1& +1' +1( +1) +1* +b11 + +b11 , +b11 - +1. +1/ +10 +11 +b11 8 +b11 9 +1: +1; +1< +1= +r0.3 > +r0.6000000000000001 ? +r0.8999999999999999 @ +b00000000000000000000000011111100 A +b00000000000000000000000000000011 B +b00000000000000000000000000000011 C +b00000000000000000000000000000110 D +b101 E #35 0! #40 1! -b00000000000000000000000000000100 " -0# -0$ -0% -0& -0' -0( -0) -0* -b00 + -b00 , -b00 - -0. -0/ -00 -01 -b00 8 -b00 9 -0: -0; -0< -0= -r0.4 > -r0.8 ? -r1.2 @ -b00000000000000000000000011111011 A -b00000000000000000000000000000100 B -b00000000000000000000000000000100 C -b00000000000000000000000000001000 D b100 E -b101 G +b00000000000000000000000000001000 D +b00000000000000000000000000000100 C +b00000000000000000000000000000100 B +b00000000000000000000000011111011 A +r1.2 @ +r0.8 ? +r0.4 > +0= +0< +0; +0: +b00 9 +b00 8 +01 +00 +0/ +0. +b00 - +b00 , +b00 + +0* +0) +0( +0' +0& +0% +0$ +0# +b00000000000000000000000000000100 " b101 F +b101 G #45 0! #50 1! -b100 F b100 G -b011 E -b00000000000000000000000000001010 D -b00000000000000000000000000000101 C -b00000000000000000000000000000101 B -b00000000000000000000000011111010 A -r1.5 @ -r1 ? -r0.5 > -1= -1< -1; -1: -b11 9 -b11 8 -11 -10 -1/ -1. -b11 - -b11 , -b11 + -1* -1) -1( -1' -1& -1% -1$ -1# +b100 F b00000000000000000000000000000101 " +1# +1$ +1% +1& +1' +1( +1) +1* +b11 + +b11 , +b11 - +1. +1/ +10 +11 +b11 8 +b11 9 +1: +1; +1< +1= +r0.5 > +r1 ? +r1.5 @ +b00000000000000000000000011111010 A +b00000000000000000000000000000101 B +b00000000000000000000000000000101 C +b00000000000000000000000000001010 D +b011 E #55 0! #60 1! -b00000000000000000000000000000110 " -0# -0$ -0% -0& -0' -0( -0) -0* -b00 + -b00 , -b00 - -0. -0/ -00 -01 -b00 8 -b00 9 -0: -0; -0< -0= -r0.6 > -r1.2 ? -r1.8 @ -b00000000000000000000000011111001 A -b00000000000000000000000000000110 B -b00000000000000000000000000000110 C -b00000000000000000000000000001100 D b010 E -b011 G +b00000000000000000000000000001100 D +b00000000000000000000000000000110 C +b00000000000000000000000000000110 B +b00000000000000000000000011111001 A +r1.8 @ +r1.2 ? +r0.6 > +0= +0< +0; +0: +b00 9 +b00 8 +01 +00 +0/ +0. +b00 - +b00 , +b00 + +0* +0) +0( +0' +0& +0% +0$ +0# +b00000000000000000000000000000110 " b011 F +b011 G diff --git a/test_regress/t/t_trace_litendian.pl b/test_regress/t/t_trace_litendian.pl index 6ed5efd1c..91cc2e48f 100755 --- a/test_regress/t/t_trace_litendian.pl +++ b/test_regress/t/t_trace_litendian.pl @@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di scenarios(simulator => 1); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # Strangely, asking for more threads makes it go away. compile( diff --git a/test_regress/t/t_trace_litendian_fst.pl b/test_regress/t/t_trace_litendian_fst.pl index f13aa0c0d..4918c10bf 100755 --- a/test_regress/t/t_trace_litendian_fst.pl +++ b/test_regress/t/t_trace_litendian_fst.pl @@ -12,7 +12,7 @@ scenarios(simulator => 1); top_filename("t/t_trace_litendian.v"); -# Travis environment offers 2 VCPUs, 2 thread setting causes the following warning. +# CI environment offers 2 VCPUs, 2 thread setting causes the following warning. # %Warning-UNOPTTHREADS: Thread scheduler is unable to provide requested parallelism; consider asking for fewer threads. # Strangely, asking for more threads makes it go away. compile( diff --git a/test_regress/t/t_trace_public_func.cpp b/test_regress/t/t_trace_public_func.cpp index c43a13dbc..b77045813 100644 --- a/test_regress/t/t_trace_public_func.cpp +++ b/test_regress/t/t_trace_public_func.cpp @@ -46,6 +46,7 @@ int main(int argc, char** argv, char** env) { } tfp->close(); top->final(); + VL_DO_DANGLING(delete top, top); printf("*-* All Finished *-*\n"); return 0; } diff --git a/test_regress/t/t_trace_public_sig.cpp b/test_regress/t/t_trace_public_sig.cpp index 2c996203f..c77db8584 100644 --- a/test_regress/t/t_trace_public_sig.cpp +++ b/test_regress/t/t_trace_public_sig.cpp @@ -46,6 +46,7 @@ int main(int argc, char** argv, char** env) { } tfp->close(); top->final(); + VL_DO_DANGLING(delete top, top); printf("*-* All Finished *-*\n"); return 0; } diff --git a/test_regress/t/t_tri_gate.cpp b/test_regress/t/t_tri_gate.cpp index 6b1c881a6..89810bce7 100644 --- a/test_regress/t/t_tri_gate.cpp +++ b/test_regress/t/t_tri_gate.cpp @@ -54,5 +54,6 @@ int main() { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from tristate test\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_tri_inout.cpp b/test_regress/t/t_tri_inout.cpp index bd0cb1426..6156bfdbf 100644 --- a/test_regress/t/t_tri_inout.cpp +++ b/test_regress/t/t_tri_inout.cpp @@ -54,5 +54,6 @@ int main() { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from inout test\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_tri_inz.cpp b/test_regress/t/t_tri_inz.cpp index 0e47c3b8d..c9393b5f3 100644 --- a/test_regress/t/t_tri_inz.cpp +++ b/test_regress/t/t_tri_inz.cpp @@ -44,5 +44,6 @@ int main() { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from t_tri_inz\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_tri_pullup.cpp b/test_regress/t/t_tri_pullup.cpp index 7885093fd..a85093968 100644 --- a/test_regress/t/t_tri_pullup.cpp +++ b/test_regress/t/t_tri_pullup.cpp @@ -63,5 +63,6 @@ int main() { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from pullup test\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_tri_select.cpp b/test_regress/t/t_tri_select.cpp index d034b85f9..b2efad8fa 100644 --- a/test_regress/t/t_tri_select.cpp +++ b/test_regress/t/t_tri_select.cpp @@ -66,5 +66,6 @@ int main() { } else { vl_fatal(__FILE__, __LINE__, "top", "Unexpected results from t_tri_select\n"); } + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_type.v b/test_regress/t/t_type.v index bb8bd852a..ce40dee79 100644 --- a/test_regress/t/t_type.v +++ b/test_regress/t/t_type.v @@ -15,6 +15,8 @@ module t(/*AUTOARG*/); y = 2.3; z = x + y; if (z != (1.2+2.3)) $stop; + z = type(z)'(22); + if (z != 22.0) $stop; $write("*-* All Finished *-*\n"); $finish; end diff --git a/test_regress/t/t_unopt_combo.vlt b/test_regress/t/t_unopt_combo.vlt index f07f4d9f5..ffec0fb7a 100644 --- a/test_regress/t/t_unopt_combo.vlt +++ b/test_regress/t/t_unopt_combo.vlt @@ -1,3 +1,3 @@ `verilator_config -lint_off -rule UNOPTFLAT -file "*t_unopt_combo.v" -match "Signal unoptimizable: Feedback to clock or circular logic: 't.c'" +lint_off -rule UNOPTFLAT -file "*t_unopt_combo.v" -match "Signal unoptimizable: Feedback to clock or circular logic: *" diff --git a/test_regress/t/t_unopt_combo_waive.out b/test_regress/t/t_unopt_combo_waive.out deleted file mode 100644 index e69de29bb..000000000 diff --git a/test_regress/t/t_unopt_combo_waive.pl b/test_regress/t/t_unopt_combo_waive.pl index e9505bfa5..99f3041e4 100755 --- a/test_regress/t/t_unopt_combo_waive.pl +++ b/test_regress/t/t_unopt_combo_waive.pl @@ -14,7 +14,7 @@ top_filename("t/t_unopt_combo.v"); compile( v_flags2 => ['+define+ATTRIBUTES', "t/t_unopt_combo.vlt"], - expect_filename => $Self->{golden_filename}, # Expect no output, as we waived + # Passes, as we waived ); ok(1); diff --git a/test_regress/t/t_urandom.v b/test_regress/t/t_urandom.v index 3a894c6ae..f20529134 100644 --- a/test_regress/t/t_urandom.v +++ b/test_regress/t/t_urandom.v @@ -42,7 +42,6 @@ module t(/*AUTOARG*/); if (v1 != 0 && v1 != 1) $stop; end -`ifndef VERILATOR // Seed stability // Note UVM doesn't use $urandom seeding v1 = $urandom(1); @@ -50,7 +49,6 @@ module t(/*AUTOARG*/); if (v1 != v2) $stop; v2 = $urandom(1); if (v1 != v2) $stop; -`endif `ifdef PROC // Seed stability via process.srandom diff --git a/test_regress/t/t_var_pinsizes.cpp b/test_regress/t/t_var_pinsizes.cpp index 32624893c..a5c75e363 100644 --- a/test_regress/t/t_var_pinsizes.cpp +++ b/test_regress/t/t_var_pinsizes.cpp @@ -15,6 +15,7 @@ int main() { VL_PRINTF("*-* All Finished *-*\n"); tb->final(); + VL_DO_DANGLING(delete tb, tb); return 0; } @@ -23,5 +24,6 @@ int sc_main(int argc, char* argv[]) { VL_PRINTF("*-* All Finished *-*\n"); tb->final(); + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_vpi_cb_iter.cpp b/test_regress/t/t_vpi_cb_iter.cpp new file mode 100644 index 000000000..f9dd322d4 --- /dev/null +++ b/test_regress/t/t_vpi_cb_iter.cpp @@ -0,0 +1,202 @@ +// -*- mode: C++; c-file-style: "cc-mode" -*- +//************************************************************************* +// +// Copyright 2020 by Wilson Snyder and Marlon James. 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 "Vt_vpi_cb_iter.h" +#include "verilated.h" +#include "verilated_vpi.h" + +#include +#include +#include +#include +#include + +#include "TestSimulator.h" +#include "TestVpi.h" + +#include "vpi_user.h" + +bool got_error = false; + +vpiHandle vh_value_cb = 0; +vpiHandle vh_rw_cb = 0; + +unsigned int last_value_cb_time = 0; +unsigned int last_rw_cb_time = 0; + +unsigned int main_time = 0; + +#ifdef TEST_VERBOSE +bool verbose = true; +#else +bool verbose = false; +#endif + +#define CHECK_RESULT_NZ(got) \ + if (!(got)) { \ + printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", __FILE__, __LINE__); \ + got_error = true; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT_NE(got, exp) \ + if ((got) == (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = !" << (exp) << std::endl; \ + got_error = true; \ + } + +// Use cout to avoid issues with %d/%lx etc +#define CHECK_RESULT(got, exp) \ + if ((got) != (exp)) { \ + std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ + << " EXP = " << (exp) << std::endl; \ + got_error = true; \ + } +static void reregister_value_cb(); +static void reregister_rw_cb(); + +static int the_value_callback(p_cb_data cb_data) { + reregister_value_cb(); + return 0; +} + +static int the_rw_callback(p_cb_data cb_data) { + reregister_rw_cb(); + return 0; +} + +static void reregister_value_cb() { + if (vh_value_cb) { + if (verbose) { vpi_printf(const_cast("- Removing cbValueChange callback\n")); } + int ret = vpi_remove_cb(vh_value_cb); + CHECK_RESULT(ret, 1); + + if (verbose) { + vpi_printf(const_cast("- last_value_cb_time %d , main_time %d\n"), + last_value_cb_time, main_time); + } + CHECK_RESULT_NE(main_time, last_value_cb_time); + last_value_cb_time = main_time; + } + if (verbose) { vpi_printf(const_cast("- Registering cbValueChange callback\n")); } + t_cb_data cb_data_testcase; + bzero(&cb_data_testcase, sizeof(cb_data_testcase)); + cb_data_testcase.cb_rtn = the_value_callback; + cb_data_testcase.reason = cbValueChange; + + vpiHandle vh1 = VPI_HANDLE("count"); + CHECK_RESULT_NZ(vh1); + + s_vpi_value v; + v.format = vpiSuppressVal; + + cb_data_testcase.obj = vh1; + cb_data_testcase.value = &v; + + vh_value_cb = vpi_register_cb(&cb_data_testcase); + CHECK_RESULT_NZ(vh_value_cb); +} + +static void reregister_rw_cb() { + if (vh_rw_cb) { + if (verbose) { vpi_printf(const_cast("- Removing cbReadWriteSynch callback\n")); } + int ret = vpi_remove_cb(vh_rw_cb); + CHECK_RESULT(ret, 1); + + if (verbose) { + vpi_printf(const_cast("- last_rw_cb_time %d , main_time %d\n"), last_rw_cb_time, + main_time); + } + CHECK_RESULT_NE(main_time, last_rw_cb_time); + last_rw_cb_time = main_time; + } + if (verbose) { vpi_printf(const_cast("- Registering cbReadWriteSynch callback\n")); } + t_cb_data cb_data_testcase; + bzero(&cb_data_testcase, sizeof(cb_data_testcase)); + cb_data_testcase.cb_rtn = the_rw_callback; + cb_data_testcase.reason = cbReadWriteSynch; + + vh_rw_cb = vpi_register_cb(&cb_data_testcase); + CHECK_RESULT_NZ(vh_rw_cb); +} + +static int the_filler_callback(p_cb_data cb_data) { return 0; } + +static void register_filler_cb() { + if (verbose) { + vpi_printf(const_cast("- Registering filler cbReadWriteSynch callback\n")); + } + t_cb_data cb_data_1; + bzero(&cb_data_1, sizeof(cb_data_1)); + cb_data_1.cb_rtn = the_filler_callback; + cb_data_1.reason = cbReadWriteSynch; + + vpiHandle vh1 = vpi_register_cb(&cb_data_1); + CHECK_RESULT_NZ(vh1); + + if (verbose) { + vpi_printf(const_cast("- Registering filler cbValueChange callback\n")); + } + t_cb_data cb_data_2; + bzero(&cb_data_2, sizeof(cb_data_2)); + cb_data_2.cb_rtn = the_filler_callback; + cb_data_2.reason = cbValueChange; + + vpiHandle vh2 = VPI_HANDLE("count"); + CHECK_RESULT_NZ(vh2); + + s_vpi_value v; + v.format = vpiSuppressVal; + + cb_data_2.obj = vh2; + cb_data_2.value = &v; + + vpiHandle vh3 = vpi_register_cb(&cb_data_2); + CHECK_RESULT_NZ(vh3); +} + +double sc_time_stamp() { return main_time; } + +int main(int argc, char** argv, char** env) { + double sim_time = 100; + Verilated::commandArgs(argc, argv); + Verilated::debug(0); + + VM_PREFIX* topp = new VM_PREFIX(""); // Note null name - we're flattening it out + + reregister_value_cb(); + CHECK_RESULT_NZ(vh_value_cb); + reregister_rw_cb(); + CHECK_RESULT_NZ(vh_rw_cb); + register_filler_cb(); + + topp->eval(); + topp->clk = 0; + + while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) { + main_time += 1; + if (verbose) { VL_PRINTF("Sim Time %d got_error %d\n", main_time, got_error); } + topp->clk = !topp->clk; + topp->eval(); + VerilatedVpi::callValueCbs(); + VerilatedVpi::callCbs(cbReadWriteSynch); + if (got_error) { vl_stop(__FILE__, __LINE__, "TOP-cpp"); } + } + + if (!Verilated::gotFinish()) { + vl_fatal(__FILE__, __LINE__, "main", "%Error: Timeout; never got a $finish"); + } + topp->final(); + + VL_DO_DANGLING(delete topp, topp); + exit(0L); +} diff --git a/test_regress/t/t_vpi_cb_iter.pl b/test_regress/t/t_vpi_cb_iter.pl new file mode 100755 index 000000000..0d8f23641 --- /dev/null +++ b/test_regress/t/t_vpi_cb_iter.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 2020 by Wilson Snyder and Marlon James. 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( + make_top_shell => 0, + make_main => 0, + verilator_flags2 => ["--exe --vpi $Self->{t_dir}/$Self->{name}.cpp"], + ); + +execute( + check_finished => 1, + ); + +ok(1); +1; diff --git a/test_regress/t/t_vpi_cb_iter.v b/test_regress/t/t_vpi_cb_iter.v new file mode 100644 index 000000000..9c4d0fa91 --- /dev/null +++ b/test_regress/t/t_vpi_cb_iter.v @@ -0,0 +1,29 @@ +// DESCRIPTION: Verilator: Verilog Test module +// +// This file ONLY is placed under the Creative Commons Public Domain, for +// any use, without warranty, 2020 Wilson Snyder and Marlon James. +// SPDX-License-Identifier: CC0-1.0 + + +module t (/*AUTOARG*/ + // Inputs + input clk + ); + + reg [31:0] count /*verilator public_flat_rd */; + + // Test loop + initial begin + count = 0; + end + + always @(posedge clk) begin + count <= count + 2; + + if (count == 10) begin + $write("*-* All Finished *-*\n"); + $finish; + end + end + +endmodule : t diff --git a/test_regress/t/t_vpi_cbs_called.cpp b/test_regress/t/t_vpi_cbs_called.cpp index c63b95b7a..c5ac031b6 100644 --- a/test_regress/t/t_vpi_cbs_called.cpp +++ b/test_regress/t/t_vpi_cbs_called.cpp @@ -45,6 +45,7 @@ std::vector::const_iterator state_iter; vpiHandle vh_test_cb = 0; unsigned int main_time = 0; +bool got_error = false; #ifdef TEST_VERBOSE bool verbose = true; @@ -55,6 +56,7 @@ bool verbose = false; #define CHECK_RESULT_NZ(got) \ if (!(got)) { \ printf("%%Error: %s:%d: GOT = NULL EXP = !NULL\n", __FILE__, __LINE__); \ + got_error = true; \ return __LINE__; \ } @@ -63,6 +65,7 @@ bool verbose = false; if ((got) != (exp)) { \ std::cout << std::dec << "%Error: " << __FILE__ << ":" << __LINE__ << ": GOT = " << (got) \ << " EXP = " << (exp) << std::endl; \ + got_error = true; \ return __LINE__; \ } @@ -188,6 +191,7 @@ static int test_callbacks(p_cb_data cb_data) { } int ret = register_cb(next_state); + if (ret) { return ret; } // Update iterators for next loop ++state_iter; @@ -218,7 +222,7 @@ static int test_callbacks(p_cb_data cb_data) { return ret; } -void register_test_callback() { +static int register_test_callback() { t_cb_data cb_data; bzero(&cb_data, sizeof(cb_data)); s_vpi_time t1; @@ -231,10 +235,13 @@ void register_test_callback() { t1.low = 1; cb_data.time = &t1; cb_data.cb_rtn = test_callbacks; - vpi_register_cb(&cb_data); + vh_test_cb = vpi_register_cb(&cb_data); + CHECK_RESULT_NZ(vh_test_cb); cb_iter = cbs_to_test.cbegin(); state_iter = cb_states.cbegin(); + + return 0; } double sc_time_stamp() { return main_time; } @@ -279,10 +286,14 @@ int main(int argc, char** argv, char** env) { VerilatedVpi::callTimedCbs(); main_time = VerilatedVpi::cbNextDeadline(); - if (main_time == -1) { + if (main_time == -1 && !Verilated::gotFinish()) { if (verbose) { VL_PRINTF("-- { Sim Time %d , No more testcases } --\n", main_time); } - VL_PRINTF("*-* All Finished *-*\n"); - Verilated::gotFinish(true); + if (got_error) { + vl_stop(__FILE__, __LINE__, "TOP-cpp"); + } else { + VL_PRINTF("*-* All Finished *-*\n"); + Verilated::gotFinish(true); + } } // Count updates on rising edge, so cycle through falling edge as well diff --git a/test_regress/t/t_vpi_sc.cpp b/test_regress/t/t_vpi_sc.cpp index 6cdf5adf9..85c7b9078 100644 --- a/test_regress/t/t_vpi_sc.cpp +++ b/test_regress/t/t_vpi_sc.cpp @@ -12,5 +12,6 @@ int sc_main(int argc, char* argv[]) { VL_PRINTF("*-* All Finished *-*\n"); tb->final(); + VL_DO_DANGLING(delete tb, tb); return 0; } diff --git a/test_regress/t/t_with.v b/test_regress/t/t_with.v index 015cdc295..3a3da8ff2 100644 --- a/test_regress/t/t_with.v +++ b/test_regress/t/t_with.v @@ -26,6 +26,12 @@ module t (/*AUTOARG*/); found = aliases.find with (item == i); aliases.find with (item == i); +`ifdef VERILATOR + // No expression (e.g. x.randomize() with {}) + // Hack until randomize() supported + found = aliases.sort() with {}; +`endif + // Unique (array method) id = 4; found = aliases.find with (id); diff --git a/test_regress/t/t_x_assign.cpp b/test_regress/t/t_x_assign.cpp index 760b6f7ec..502301c7c 100644 --- a/test_regress/t/t_x_assign.cpp +++ b/test_regress/t/t_x_assign.cpp @@ -48,6 +48,7 @@ int main(int argc, const char** argv) { exit(1); } + VL_DO_DANGLING(delete top, top); std::cout << "*-* All Finished *-*" << std::endl; return 0; } diff --git a/test_regress/vgen.pl b/test_regress/vgen.pl deleted file mode 100755 index 112e083ba..000000000 --- a/test_regress/vgen.pl +++ /dev/null @@ -1,1068 +0,0 @@ -#!/usr/bin/env perl -# See copyright, etc in below POD section. -###################################################################### - -require 5.006_001; -use warnings; - -use Getopt::Long; -use IO::File; -use Pod::Usage; -use Data::Dumper; $Data::Dumper::Indent = 1; -use Bit::Vector; -use strict; -use vars qw($Debug); - -our @Orig_ARGV = @ARGV; -our $Rerun_Args = $0." ".join(' ',@Orig_ARGV); -$Rerun_Args =~ s/\s+$//; - -use vars qw(@Blocks - %Vars - %VarAttrs - %VarsBlock - %Tree - @Commit - $Depth - %IdWidth - %Ops); - -#====================================================================== - -# width=> Number of bits the output size is, 0=you tell me. -# func=> What to put in output file -# signed=> 0=unsigned output, 1=signed output, '%1'=signed if op1 signed -# lsb=> LSB for variable declarations -# em=> How to calculate emulated return value -# %w Width of this output op ($treeref->{width}) -# %v Output value ($treeref->{val}) -# %1r First operand ($treeref->{op1}) -# %1v First operand value ($treeref->{op1}{val}) -# %1w First operand width ($treeref->{op1}{width}) - -our $Raise_Weight_Max = 50; -%Ops = -( - 'VCONST'=> {weight=>1&&20, width=>0, sc=>1, terminal=>1, v=>'%v', }, - 'VIDNEW'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'%i', }, - 'VIDOLD'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', }, - 'VIDSAME'=> {weight=>1&&20, width=>0, sc=>1, terminal=>0, v=>'%i', }, - 'VRANGE'=> {weight=>1&&30, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2:%3]', }, - 'VBITSEL'=> {weight=>1&&10, width=>1, signed=>0,sc=>0, terminal=>0, v=>'%i[%2]', }, - 'VBITSELP'=> {weight=>1&&10, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2+:%3]', }, - 'VBITSELM'=> {weight=>1&&10, width=>0, signed=>0,sc=>0, terminal=>0, v=>'%i[%2-:%3]', }, - # Unary - 'VEXTEND'=> {weight=>1&&3, width=>-2, signed=>0,sc=>0, terminal=>0, v=>'{%xd\'h0,%1}', }, - 'VLOGNOT'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(! %1)', }, - 'VREDAND'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(& %1)', }, - 'VREDOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(| %1)', }, - 'VREDNAND'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(~& %1)', }, - 'VREDNOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(~| %1)', }, - 'VREDXNOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^~ %1)', }, - 'VREDXOR'=> {weight=>1&&1, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(^ %1)', }, - 'VNOT'=> {weight=>1&&3, width=>0, sc=>1, terminal=>0, v=>'(~ %1)', }, - 'VNEGATE'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(- %1)', }, - 'VCOUNTONES'=> {weight=>0&&2, width=>32, signed=>0, sc=>0, terminal=>0, v=>'\$countones(%1)', }, # No ncv support - 'VONEHOT'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot(%1)', }, # No ncv support - 'VONEHOT0'=> {weight=>0&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'\$onehot0(%1)', }, # No ncv support - # Binary - 'VAND'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(%1 & %2)', }, - 'VOR'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(%1 | %2)', }, - 'VNAND'=> {weight=>1&&0, width=>0, sc=>0, terminal=>0, v=>'(%1 ~& %2)', }, #FIX vcs bug! - 'VNOR'=> {weight=>1&&0, width=>0, sc=>0, terminal=>0, v=>'(%1 ~| %2)', }, #FIX vcs bug! - 'VXOR'=> {weight=>1&&2, width=>0, sc=>1, terminal=>0, v=>'(%1 ^ %2)', }, - 'VXNOR'=> {weight=>1&&0, width=>0, sc=>0, terminal=>0, v=>'(%1 ^~ %2)', }, #FIX vcs bug! - 'VEQ'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 == %2)', }, - 'VNEQ'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 != %2)', }, - 'VGT'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 > %2)', }, - 'VGTE'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 >= %2)', }, - 'VLT'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 < %2)', }, - 'VLTE'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 <= %2)', }, - 'VEQCASE'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 === %2)', }, # FIX just a = for now - 'VNEQCASE'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 !== %2)', }, # FIX just a != for now - 'VLOGOR'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 || %2)', }, - 'VLOGAND'=> {weight=>1&&2, width=>1, signed=>0, sc=>0, terminal=>0, v=>'(%1 && %2)', }, - 'VADD'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'(%1 + %2)', }, - 'VSUB'=> {weight=>1&&10, width=>0, sc=>1, terminal=>0, v=>'(%1 - %2)', }, - 'VMUL'=> {weight=>1&&15,width=>0, sc=>1, terminal=>0, v=>'(%1 * %2)', }, # High % as rarely applyable - # Unspecified behavior with == (a-signed / b) -- see t_math_signed5.v test - 'VDIV'=> {weight=>1&&8, width=>0, signed=>0, sc=>1, terminal=>0, v=>'((%2)==%xw\'h0 ? %xw\'%xsh0:(%1 / %2))', }, - 'VMODDIV'=> {weight=>1&&8, width=>0, signed=>0, sc=>1, terminal=>0, v=>'((%2)==%xw\'h0 ? %xw\'%xsh0:(%1 %% %2))', }, - #'VPOW'=> {weight=>2&&0,width=>-64, sc=>0, terminal=>0, v=>'(%1 ** %2)', }, - 'VSHIFTL'=> {weight=>1&&8, width=>0, signed=>0, sc=>0, terminal=>0, v=>'(%1 << %2)', }, - 'VSHIFTLS'=> {weight=>1&&8, width=>0, signed=>1, sc=>0, terminal=>0, v=>'(%1 <<< %2)', }, - 'VSHIFTR'=> {weight=>1&&8, width=>0, signed=>0, sc=>0, terminal=>0, v=>'(%1 >> %2)', }, - 'VSHIFTRS'=> {weight=>1&&15,width=>0, signed=>1, sc=>0, terminal=>0, v=>'(%1 >>> %2)', }, # ShiftR seems to sign extend differently for <=32 and >32 bits - 'VCONCAT'=> {weight=>1&&4, width=>-2,signed=>0, sc=>0, terminal=>0, v=>'{%1,%2}', }, - 'VREPLIC'=> {weight=>1&&2, width=>0, signed=>0, sc=>0, terminal=>0, v=>'{%1{%2}}', }, - 'VREPLIC1W'=> {weight=>1&&2, width=>0, signed=>0, sc=>0, terminal=>0, v=>'{%1{%2}}', }, - 'VSIGNED'=> {weight=>1&&2, width=>0, signed=>1, sc=>0, terminal=>0, v=>'\$signed(%1)', }, - 'VUNSIGNED'=> {weight=>1&&2, width=>0, signed=>0, sc=>0, terminal=>0, v=>'\$unsigned(%1)', }, - # Triops - 'VCOND'=> {weight=>1&&4, width=>0, sc=>0, terminal=>0, v=>'(%1 ? %2 : %3)', }, - # Control flow - #VIF - #VFOR - #VCASE - #VCASEX - #VCASEZ - ); - -my %ops2 = -( - 'VCONST'=> {pl=>'', rnd=>'rnd_const(%tr);'}, - 'VIDNEW'=> {pl=>'%tv=$Vars{%i}{val};', - rnd=>'%i=next_id(%tw);' - .' $Vars{%i}=gen_leaf(width=>%tw,trunc=>1,signed=>%tg);' - .' $VarAttrs{%i}{lsb} = rnd_lsb();' - .' id_commit(%tr,"%i");1;',}, - 'VIDOLD'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_old(%tr);', ok_id_width=>1,}, - 'VIDSAME'=> {pl=>'%tv=$Vars{%i}{val};', rnd=>'%i=id_same(%tr);', ok_id_width=>1,}, - # These create IDs they then extract from - 'VRANGE'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', - rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' - .' my $lsb=rnd(128-%tw); my $msb=$lsb+%tw-1;' - .' %2r=val_leaf($msb); %3r=val_leaf($lsb);' - .' $Vars{%i}=gen_leaf(width=>($msb+1));'}, - 'VBITSEL'=> {pl=>'VRANGE(%tr,$Vars{%i}{val},%2v,%2v,$VarAttrs{%i}{lsb});', - rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' - .' my $wid=min(128,rnd_width()|3);' - .' %2r=gen_leaf(width=>(log2($wid)-1),signed=>0);' - .' $Vars{%i}=gen_leaf(width=>$wid);'}, - 'VBITSELP'=> {pl=>'VBITSELP(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', - rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' - .' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-%tw; %2r=(($maxval<4)?val_leaf($maxval):gen_leaf(width=>(log2($maxval)-1),signed=>0));' - .' $Vars{%i}=gen_leaf(width=>$wid);'}, - 'VBITSELM'=> {pl=>'VBITSELM(%tr,$Vars{%i}{val},%2v,%3v,$VarAttrs{%i}{lsb});', - rnd=>'%i=next_id(%tw); $VarAttrs{%i}{lsb} = 0&&rnd_lsb();' - .' my $wid=min(128,(%tw+rnd_width()|3)); %3r=val_leaf(%tw); my $maxval = $wid-1; my $minval=%tw-1; %2r=val_leaf(rnd($maxval-$minval)+$minval);' - .' $Vars{%i}=gen_leaf(width=>$wid);'}, # No easy way to make expr with specified minimum - # Unary - 'VEXTEND'=> {pl=>'VRESIZE (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>rnd_width(%tw-1));'}, - 'VLOGNOT'=> {pl=>'VLOGNOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDAND'=> {pl=>'VREDAND (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDOR'=> {pl=>'VREDOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDNAND'=> {pl=>'VREDNAND (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDNOR'=> {pl=>'VREDNOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDXOR'=> {pl=>'VREDXOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VREDXNOR'=> {pl=>'VREDXNOR (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VNOT'=> {pl=>'VNOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VNEGATE'=> {pl=>'VNEGATE (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VCOUNTONES'=> {pl=>'VCOUNTONES(%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VONEHOT'=> {pl=>'VONEHOT (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - 'VONEHOT0'=> {pl=>'VONEHOT0 (%tr,%1v);', rnd=>'%1r=gen_leaf(width=>0);'}, - # Binary - 'VAND'=> {pl=>'VAND (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VOR'=> {pl=>'VOR (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VNAND'=> {pl=>'VNAND (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VNOR'=> {pl=>'VNOR (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VXOR'=> {pl=>'VXOR (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VXNOR'=> {pl=>'VXNOR (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VEQ'=> {pl=>'VEQ (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VNEQ'=> {pl=>'VNE (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VGT'=> {pl=>'VGT (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VGTE'=> {pl=>'VGE (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VLT'=> {pl=>'VLT (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VLTE'=> {pl=>'VLE (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VEQCASE'=> {pl=>'VEQ (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VNEQCASE'=> {pl=>'VNE (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>%1w,signed=>%1g);'}, - 'VLOGOR'=> {pl=>'VLOGOR (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>0);'}, - 'VLOGAND'=> {pl=>'VLOGAND(%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>0); %2r=gen_leaf(width=>0);'}, - 'VADD'=> {pl=>'VADD (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);', trunc=>1,}, - 'VSUB'=> {pl=>'VSUB (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);', trunc=>1,}, - 'VMUL'=> {pl=>'VMUL (%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);', trunc=>1,}, # Multiply generates larger width, so need truncate for safety - 'VDIV'=> {pl=>'VDIV (%tr,%1r,%2r,0);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - 'VMODDIV'=> {pl=>'VDIV (%tr,%1r,%2r,1);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>%tw,signed=>%tg);'}, - #'VPOW'=> {pl=>'VPOW (%tr,%1r,%2r);', rnd=>'%1r=gen_leaf(width=>min(%tw,6),signed=>%tg); %2r=gen_leaf(width=>min(%tw,8),signed=>%tg);', trunc=>1,}, # Generates larger width, so need truncate for safety - 'VSHIFTL'=> {pl=>'VSHIFTL(%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);'}, - 'VSHIFTLS'=> {pl=>'VSHIFTL(%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);'}, - 'VSHIFTR'=> {pl=>'VSHIFTR(%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);'}, - 'VSHIFTRS'=> {pl=>'VSHIFTRS(%tr,%1v,%2v);', rnd=>'%1r=gen_leaf(width=>%tw,signed=>%tg); %2r=gen_leaf(width=>log2(%tw)+1,signed=>%tg);'}, - 'VCONCAT'=> {pl=>'VCONCAT(%tr,%1v,%2v);', rnd=>'my $d=(rnd(%tw-2)+1); %1r=gen_leaf(width=>$d,signed=>0); %2r=gen_leaf(width=>(%tw-$d),signed=>0);'}, - 'VREPLIC'=> {pl=>'VREPLIC(%tr,%1v,%2v);', rnd=>'my $d=rnd_rep_width(%tw); %1r=val_leaf($d); %2r=gen_leaf(width=>(%tw/$d),signed=>0);'}, - 'VREPLIC1W'=> {pl=>'VREPLIC(%tr,%1v,%2v);', rnd=>'%1r=val_leaf(%tw); %2r=gen_leaf(width=>1,signed=>0);'}, - 'VSIGNED'=> {pl=>'VCLONE (%tr,%1v,0);', rnd=>'%1r=gen_leaf(width=>%tw);'}, - 'VUNSIGNED'=> {pl=>'VCLONE (%tr,%1v,0);', rnd=>'%1r=gen_leaf(width=>%tw);'}, - # Triops - 'VCOND'=> {pl=>'VCOND(%tr,%1v,%2v,%3v);', rnd=>'%1r=gen_leaf(width=>1); %2r=gen_leaf(width=>%tw,signed=>%tg); %3r=gen_leaf(width=>%tw,signed=>%tg);'}, - ); - -foreach my $op (keys %ops2) { - while ((my $key,my $val) = each %{$ops2{$op}}) { - $Ops{$op}{$key} = $val; - } -} - -#====================================================================== -# main - -#Bit::Vector->Configuration("ops=arithmetic"); - - -my $opt_seed=5; -our $Opt_NumOps = 30; -our $Opt_Depth = 4; -our $Opt_Output; -our $Opt_Signed = 1; -our $Opt_Raise; -our $Opt_BlockStmts = 2; -our $Signed_Pct = 60; -$Debug = 0; -if (! GetOptions ( - "help" => \&usage, - "debug" => \&debug, - "depth=i" => \$Opt_Depth, - "blockstmts=i"=> \$Opt_BlockStmts, - "numops=i" => \$Opt_NumOps, - "o=s" => \$Opt_Output, - "raise=i" => \$Opt_Raise, - "seed=i" => \$opt_seed, - "signed!" => \$Opt_Signed, - "<>" => \¶meter, - )) { - usage(); -} - -if ($opt_seed==0) { - srand(); - $opt_seed = rnd(1<<20)+1; - $Rerun_Args =~ s/-seed[= ]+0/-seed=$opt_seed/; - print " $Rerun_Args\n"; -} -srand($opt_seed); -init(); -selftest(); -gentest(); -$Opt_Output or die "%Error: Need -o option,"; -write_output_v($Opt_Output); - -#---------------------------------------------------------------------- - -sub usage { - pod2usage(-verbose=>2, -exitval=>0, -output=>\*STDOUT); - exit(1); # Unreachable -} - -sub debug { - $Debug = 1; -} - -sub parameter { - my $param = shift; - die "%Error: Unknown parameter: $param\n"; -} - -####################################################################### -####################################################################### -####################################################################### -####################################################################### -# Global Functions - -sub init { - for my $op (keys %Ops) { - my $opref = $Ops{$op}; - $opref->{name} = $op; - gen_v($opref); - gen_pl($opref); - gen_rnd($opref); - } - raise(); -} - -sub raise { - for (my $i=0; $i<($Opt_Raise||0); $i++) { - my @ops = (values %Ops); - while (1) { - my $rndop = $ops[rnd($#ops + 1)]; - next if !$rndop->{weight}; # Don't turn on disabled ops - $rndop->{weight} += rnd($Raise_Weight_Max); - printf "\tWeight %-15s +%d\n",$rndop->{name},$rndop->{weight}; - last; - } - } -} - -sub gentest { - for (my $opn=0; $opn<$Opt_NumOps/$Opt_BlockStmts; $opn++) { - do_a_test(); - } -} - -####################################################################### -# Randomization - -sub _rnd_op_ok { - my $opref = shift; - my $paramref = shift; - return (($opref->{width} == 0 - || $opref->{width} == $paramref->{width} - # Note -2 means >, while -32 means {width}==-31 && $paramref->{width}<=31) # -31... must be <31 bits - || ($opref->{width}==-32 && $paramref->{width}<=32) # -32... must be <32 bits - || ($opref->{width}==-63 && $paramref->{width}<=63) # -63... must be <63 bits - || ($opref->{width}==-64 && $paramref->{width}<=64) # -64... must be <64 bits - || ($opref->{width}==-2 && $paramref->{width}>=2) # -2... must be >2 bits - ) - && (!$opref->{ok_id_width} || $IdWidth{$paramref->{width}}{$paramref->{signed}||0}) - && (!defined $opref->{signed} || ($opref->{signed} == ($paramref->{signed}||0))) - && (!$opref->{trunc} || $paramref->{trunc}) - && (!$opref->{opt_signed} || $Opt_Signed) - && (($Depth < $Opt_Depth && !$paramref->{need_terminal}) - || $opref->{terminal})); -} - -sub rnd_op { - my $paramref = shift; - - my $totweight = 0; - foreach my $opref (values %Ops) { - if (_rnd_op_ok($opref,$paramref)) { - $totweight += $opref->{weight}; - } - } - my $chooseweight = rnd($totweight); - $totweight = 0; - foreach my $opref (sort {$a->{name} cmp $b->{name}} values %Ops) { - if (_rnd_op_ok($opref,$paramref)) { - $totweight += $opref->{weight}; - if ($chooseweight < $totweight) { - return $opref; - } - } - } - die "%Error: No instructions match,"; -} - -sub rnd_width { - my $max = shift; - my $v = rnd(100); - my $n = (0 - || (($v<20) && 1) - || (($v<25) && 2) - || (($v<30) && 31) - || (($v<35) && 32) - || (($v<40) && 63) - || (($v<45) && 64) - || (($v<50) && 95) - || (($v<55) && 96) - || (rnd(128)+1)); - if ($max && $n>=$max) { $n = rnd($max-1)+1; } - return $n; -} - -sub rnd_rep_width { - my $out = shift; - return 1 if $out==1; - # We'd like to pick any divisor that works. - my @factors; - for (my $div=1; $div<$out; $div++) { - if (int($out/$div)==($out/$div)) { - push @factors, $div; - } - } - my $fac = $factors[rnd($#factors+1)]; - #print "RND REP $out -> $fac (@factors)\n" if $Debug; - return $fac; -} - -sub rnd_const { - my $treeref = shift; - my $width = $treeref->{width} or die; - my $v = rnd(100); - - my $val = Bit::Vector->new($width); - if ($v<25) { # zero - } elsif ($v<50) { # ones - for (my $w=0; $w<$val->Word_Size; ++$w) { - $val->Word_Store(0,~0); - } - } elsif ($v<60) { # one - $val->Word_Store(0,1); - } else { # random - for (my $w=0; $w<$val->Word_Size; ++$w) { - $val->Word_Store($w,rnd_int()); - } - } - $treeref->{val} = $val; -} - -sub rnd_int { - my $v = rnd(100); - return 0 if ($v<25); - return ~0 if ($v<50); - return 1 if ($v<60); - return rnd32(); -} - -sub rnd_lsb { - return 0; - #return rnd(8)-4; # Not working yet -} - -sub rnd { - return (int(rand($_[0]))) if ($_[0] < (1<<15)); - return (rnd32() % $_[0]); -} -sub rnd32 { - my $vp = int(rand(1<<16)); - $vp ^= (int(rand(1<<8)))<<16; # Single 1<<16 doesn't work - $vp ^= (int(rand(1<<8)))<<24; - return ($vp); -} - -####################################################################### - -our $Next_Id = 0; -sub next_id { - # Note width hasn't been determined yet - $Next_Id++; - my $id = sprintf("W%04d",$Next_Id); - return $id; -} -sub id_commit { - my $treeref = shift; - my $width = $treeref->{width}; - my $signed = $treeref->{signed}; - my $id = shift; - push @Commit, sub { - $IdWidth{$width}{$signed} = [] if !$IdWidth{$width}{$signed}; - push @{$IdWidth{$width}{$signed}}, $id; - $VarsBlock{$id}{set} = 1; - 1; - }; -} - -sub id_old { - my $treeref = shift; - my $width = $treeref->{width}; - my $signed = $treeref->{signed}; - - my $n = $#{$IdWidth{$width}{$signed}} + 1; - my $idn = rnd($n); - my $id = $IdWidth{$width}{$signed}[$idn]; - $VarsBlock{$id}{used} = 1; - return $id; -} - -sub id_same { - my $treeref = shift; - my $width = $treeref->{width}; - my $signed = $treeref->{signed}; - - my @possible; - foreach my $id (keys %VarsBlock) { - next if !$VarsBlock{$id}{used}; - my $varref = $Vars{$id}; - next if $varref->{signed} != $signed; - next if $varref->{width} != $width; - push @possible, $id; - } - my $n = $#possible + 1; - if ($n<1) { # Nothing, grab another! - return id_old($treeref,$width,$signed); - } - my $idn = rnd($n); - my $id = $possible[$idn]; - $VarsBlock{$id}{used} = 1; - return $id; -} - -sub write_output_v { - my $filename = shift; - - my $fh = IO::File->new($filename, "w") or die("%Error: $! $filename,\n"); - print $fh "// Created by: $Rerun_Args\n"; - - print $fh "module vgen (clk);\n"; - print $fh " input clk;\n"; - print $fh " reg check; initial check = '0;\n"; - print $fh ' initial $write("\n*** Vgen.v starting, seed = ',$opt_seed,'\n");',"\n"; - - print $fh " // verilator lint_off UNSIGNED\n"; - print $fh " // verilator lint_off CMPCONST\n"; - print $fh " // verilator lint_off WIDTH\n"; - print $fh "\n"; - - my $cycles = 2; - - foreach my $var (sort (keys %Vars)) { - print $fh "",decl_text ($var),"\n"; - } - - foreach my $block (@Blocks) { - print $fh "\t//".('='x60)."\n"; - my $style = rnd(100); - if ($style < 15) { - # This allows statements to get split up, and constants to propagate - print $fh " always @(", join(" or ", ('check', @{$block->{inputs}})); - print $fh ") begin : $block->{name}\n"; - print $fh @{$block->{preass}}; - print $fh " end\n"; - print $fh " always @(posedge clk) begin : $block->{name}Check\n"; - print $fh @{$block->{body}}; - print $fh " end\n"; - } - elsif ($style < 40) { - print $fh " always @(", join(" or ", ('check', @{$block->{inputs}})); - print $fh ") begin : $block->{name}\n"; - print $fh @{$block->{preass}}; - print $fh @{$block->{body}}; - print $fh " end\n"; - } - else { - foreach my $stmt (@{$block->{preass}}) { - $cycles++; - print $fh " always @(posedge clk) begin\n"; - $stmt =~ s/ = / <= /mg; - print $fh $stmt; - print $fh " end\n"; - } - print $fh " always @(posedge clk) begin\n"; - print $fh @{$block->{body}}; - print $fh " end\n"; - } - } - - print $fh "\n"; - print $fh " parameter [31:0] CYCLES /*verilator public*/ = $cycles;\n"; - print $fh "\n"; - print $fh " integer cyc; initial cyc = 0;\n"; - print $fh " always @(posedge clk) begin\n"; - print $fh "`ifdef TEST_VERBOSE\n"; - print $fh ' $write("[%0t] cyc=%0d check=%d\n", $time, cyc, check);',"\n"; - print $fh "`endif\n"; - print $fh " cyc <= cyc + 1;\n"; - print $fh " if (cyc < CYCLES) begin\n"; - print $fh " check <= 1'b0;\n"; - print $fh " end\n"; - print $fh " else if (cyc >= CYCLES) begin\n"; - print $fh " check <= 1'b1;\n"; - print $fh " if (cyc >= (CYCLES+10)) begin\n"; - print $fh ' $write("*-* All Finished *-*\n");',"\n"; - print $fh ' $finish;',"\n"; - print $fh " end\n"; - print $fh " end\n"; - print $fh " end\n"; - - print $fh "endmodule\n"; - - $fh->close(); -} - -###################################################################### - -sub callers { - for (my $i=0; ; $i++) { - my @c = caller($i); - last if !$c[0]; - print "Caller $i: ",join(' ',@c[0..3]),"\n"; - } -} - -####################################################################### -####################################################################### -####################################################################### -####################################################################### -# Code generation/emitting Functions - -sub do_a_test { - local $Depth = 0; - @Commit = (); - %VarsBlock = (); - - my $block = { - name=>"Block".($#Blocks+2), - body=>[], - preass=>[], - inputs=>[], - outputs=>[], - }; - - for (my $i=0; $i<$Opt_BlockStmts; $i++) { - my $treeref = gen_leaf(width=>0); - push @{$block->{body}}, - "\tif ($treeref->{text} != ".$treeref->val_to_text().") if (check) ".stop_text().";\n"; - } - - foreach my $var (keys %VarsBlock) { - push @{$block->{inputs}}, $var - if $VarsBlock{$var}{used} && !$VarsBlock{$var}{set}; - } - - foreach my $var (reverse (sort (keys %Vars))) { - my $varref = $Vars{$var}; - next if $varref->{printedit}; - $varref->{printedit} = 1; - push @{$block->{outputs}}, $var; - push @{$block->{preass}}, sprintf ("\t$var = %s;\n" - ,$varref->{text}); - } - - foreach my $com (@Commit) { - &{$com} or die "%Error: Can't eval:\n$com\n $@ "; - } - - push @Blocks, $block; -} - -sub gen_leaf { - my $inforef = {width=>0, # Anything - need_terminal=>0, - #trunc=>undef, # Allow multiply op - @_}; - - $inforef->{width} ||= rnd_width(); - $inforef->{signed} = ($Opt_Signed && $inforef->{width}>1 && (rnd(100)<$Signed_Pct))?1:0 - if !defined $inforef->{signed}; - print +((" "x$Depth)."Leaf of width $inforef->{width}\n") if $Debug; - my $op = rnd_op($inforef); - - my $treeref = new Vg::Base; - while ((my $key,my $val) = each %{$op}) { - $treeref->{$key} = $val; - } - while ((my $key,my $val) = each %{$inforef}) { - $treeref->{$key} = $val; - } - - local $Depth = $Depth+1; - print "RndSub $treeref->{rnd_sub_text}\n" if $Debug; - $treeref->{rnd_sub}($treeref); - $treeref->tree_dump() if $Debug; - - print "RndPl\n" if $Debug; - $treeref->{pl_sub}($treeref); - print "RndV\n" if $Debug; - $treeref->{text} = $treeref->{v_sub}($treeref); - print "Done\n" if $Debug; - print " Value ",$treeref->{val}," = ",$treeref->val_to_text(),"\n" if $Debug; - #$treeref->tree_dump() if $Debug; - - $treeref->{val_size} = $treeref->{val}->Size; # Debugging - $treeref->{val_text} = $treeref->{val}->to_Hex; # Debugging - - ($treeref->{val}->Size == $treeref->{width}) - or die "%Error: Size mismatch ",$treeref->{val}->Size,"!=",$treeref->{width},"\n",Dumper($treeref); - - return $treeref; -} - -sub gen_v { - my $opref = shift; - - my $fmt = $opref->{v}; - $fmt =~ s/%1/%s/g; - $fmt =~ s/%2/%s/g; - $fmt =~ s/%3/%s/g; - $fmt =~ s/%v/%s/g; - $fmt =~ s/%i/%s/g; - $fmt =~ s/%x[wds]/%s/g; - - my $argl = $opref->{v}; - my @args; - while ($argl =~ s/(%x.|%.)//) { - my $arg = $1; - push @args, '$treeref->{op1}{text}' if $arg =~ /%1/; - push @args, '$treeref->{op2}{text}' if $arg =~ /%2/; - push @args, '$treeref->{op3}{text}' if $arg =~ /%3/; - push @args, '$treeref->val_to_text' if $arg =~ /%v/; - push @args, '$treeref->{id}' if $arg =~ /%i/; - push @args, '$treeref->{signed}?"s":""' if $arg =~ /%xs/; - push @args, '$treeref->{width}' if $arg =~ /%xw/; - push @args, '$treeref->{width}-$treeref->{op1}{width}' if $arg =~ /%xd/; - } - - my $func = ("sub { " - ." my \$treeref = shift;" - ." sprintf(\"$fmt\",".join(',',@args).");" - ."}"); - my $set = ("\$opref->{v_sub} = $func; 1;"); - $opref->{v_sub_text} = $func; # For seeing it in debugging dumps - #print "Op V $opref->{name} $set\n"; - eval($set) or die "%Error: Can't eval:\n$set\n $@ "; -} - -sub escapes { - my $str = shift; - my $cmt = shift; - $str =~ s/%tr/\$treeref/g; - $str =~ s/%tg/\$treeref->{signed}/g; - $str =~ s/%tv/\$treeref->{val}/g; - $str =~ s/%tw/\$treeref->{width}/g; - # - $str =~ s/%1r/\$treeref->{op1}/g; - $str =~ s/%1g/\$treeref->{op1}{signed}/g; - $str =~ s/%1n/(\$treeref->{op1}{val}->Word_Read(0))/g; - $str =~ s/%1v/\$treeref->{op1}{val}/g; - $str =~ s/%1w/\$treeref->{op1}{width}/g; - # - $str =~ s/%2r/\$treeref->{op2}/g; - $str =~ s/%2g/\$treeref->{op2}{signed}/g; - $str =~ s/%2n/(\$treeref->{op2}{val}->Word_Read(0))/g; - $str =~ s/%2v/\$treeref->{op2}{val}/g; - $str =~ s/%2w/\$treeref->{op2}{width}/g; - # - $str =~ s/%3r/\$treeref->{op3}/g; - $str =~ s/%3g/\$treeref->{op3}{signed}/g; - $str =~ s/%3n/(\$treeref->{op3}{val}->Word_Read(0))/g; - $str =~ s/%3v/\$treeref->{op3}{val}/g; - $str =~ s/%3w/\$treeref->{op3}{width}/g; - # - $str =~ s/%i/\$treeref->{id}/g; - ($str !~ /%/) or die "%Error: $cmt: Unknown %% escape in $str,"; - return $str; -} - -sub gen_pl { - my $opref = shift; - - my $str = escapes($opref->{pl}, $opref->{name}); - my $func = ("sub { " - ." my \$treeref = shift;" - ." $str;" - ."}"); - my $set = ("\$opref->{pl_sub} = $func; 1;"); - $opref->{pl_sub_text} = $func; # For seeing it in debugging dumps - #print "Op PL $opref->{name} $set\n"; - eval($set) or die "%Error: Can't eval:\n$set\n $@ "; -} - -sub gen_rnd { - my $opref = shift; - - my $str = escapes($opref->{rnd}, $opref->{name}); - - my $func = ("sub { " - ." my \$treeref = shift;" - ." $str;" - ."}"); - my $set = ("\$opref->{rnd_sub} = $func; 1;"); - $opref->{rnd_sub_text} = $func; # For seeing it in debugging dumps - #print "Op RND $opref->{name} $set\n"; - eval($set) or die "%Error: Can't eval:\n$set\n $@ "; -} - -sub stop_text { - return '$stop'; -} - -sub decl_text { - my $var = shift; - my $decl_with = shift; - - my $varref = $Vars{$var}; - return sprintf(" reg %s [%3d:%3d] %s %s; //=%d'h%s" - , ($varref->{signed}?"signed":" ") - , ($varref->{val}->Size)-1+$VarAttrs{$var}{lsb}, - , $VarAttrs{$var}{lsb} - , $var - , (rnd(100)<30 ? "/*verilator public*/":(" "x length("/*verilator public*/"))) - , $varref->{val}->Size - , lc $varref->{val}->to_Hex); -} - -####################################################################### -####################################################################### -####################################################################### -####################################################################### -# Math Functions - -sub selftest { - my $o = {}; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0xff)}, {val=>Bit::Vector->new_Dec(8,0x13)}, 0); - ($o->{val}->Word_Read(0) == 0x0d) or die; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0xff)}, {val=>Bit::Vector->new_Dec(8,0x13)}, 1); - ($o->{val}->Word_Read(0) == 0x08) or die; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0xff), signed=>1}, {val=>Bit::Vector->new_Dec(8,0x13), signed=>1}, 0); - ($o->{val}->Word_Read(0) == 0x00) or die; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0xff), signed=>1}, {val=>Bit::Vector->new_Dec(8,0x13), signed=>1}, 1); - ($o->{val}->Word_Read(0) == 0xff) or die; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0xff), signed=>1}, {val=>Bit::Vector->new_Dec(8,0xdb), signed=>1}, 1); - ($o->{val}->Word_Read(0) == 0xff) or die; - VDIV($o, {val=>Bit::Vector->new_Dec(8,0x72), signed=>1}, {val=>Bit::Vector->new_Dec(8,0xdb), signed=>1}, 1); - ($o->{val}->Word_Read(0) == 0x3) or die; -} -sub val_leaf { return {width=>32, signed=>0, val=>Bit::Vector->new_Dec(32,$_[0]), text=>$_[0],}; } - -sub makebool { return (Bit::Vector->new_Dec(1,$_[0])); } -sub newsized { return (Bit::Vector->new($_[0]->Size)); } -sub max { return $_[0]<$_[1] ? $_[1] : $_[0]; } -sub min { return $_[0]>$_[1] ? $_[1] : $_[0]; } - -sub log2 { - for (my $i=31; $i>=0; $i--) { - return $i+1 if $_[0]>(1<<$i); - } - return 0; -} - -sub countones { - my $out = 0; - for (my $bit=0; $bit < $_[0]->Size; $bit++) { - $out ++ if $_[0]->bit_test($bit); - } - return $out; -} - - -sub VLOGNOT { $_[0]{val} = makebool(($_[1]->is_empty)?1:0); } -sub VNEGATE { $_[0]{val} = my $o = newsized($_[1]); $o->Negate($_[1]); } -sub VCOUNTONES { $_[0]{val} = Bit::Vector->new_Dec(32,countones($_[1])); } -sub VONEHOT { $_[0]{val} = makebool((countones($_[1])==1)?1:0); } -sub VONEHOT0 { $_[0]{val} = makebool((countones($_[1])<=1)?1:0); } -sub VLOGAND { $_[0]{val} = makebool((!($_[1]->is_empty) && !($_[2]->is_empty))?1:0); } -sub VLOGOR { $_[0]{val} = makebool((!($_[1]->is_empty) || !($_[2]->is_empty))?1:0); } - -sub VCOND { if (!($_[1]->is_empty)) { $_[0]{val}=$_[2]->Clone; } else { $_[0]{val}=$_[3]->Clone; } } - -sub VREDAND { $_[0]{val} = makebool(($_[1]->is_full)?1:0); } -sub VREDOR { $_[0]{val} = makebool(($_[1]->is_empty)?0:1); } -sub VREDNAND { $_[0]{val} = makebool(($_[1]->is_full)?0:1); } -sub VREDNOR { $_[0]{val} = makebool(($_[1]->is_empty)?1:0); } -sub VREDXOR { - my $out = 0; - for (my $bit=0; $bit < $_[1]->Size; $bit++) { - $out ^= $_[1]->bit_test($bit); - } - $_[0]{val} = makebool($out); -} -sub VREDXNOR { - my $out = 1; - for (my $bit=0; $bit < $_[1]->Size; $bit++) { - $out ^= $_[1]->bit_test($bit); - } - $_[0]{val} = makebool($out); -} -sub eithercompare { ($_[1]->{signed} && $_[2]->{signed}) - ? $_[1]{val}->Compare($_[2]{val}) - : $_[1]{val}->Lexicompare($_[2]{val}); } -sub VEQ { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])==0) ?1:0); } -sub VNE { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])!=0) ?1:0); } -sub VLT { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])< 0) ?1:0); } -sub VLE { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])<=0) ?1:0); } -sub VGT { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])> 0) ?1:0); } -sub VGE { $_[0]{val} = makebool( (eithercompare($_[0],$_[1],$_[2])>=0) ?1:0); } - -sub VSHIFTLxx { - print "$Vars{vq}->ShiftL($_[0],$_[1]);\n"; - print " ",$_[0]->to_Hex," ",$_[1]->to_Hex,";\n"; - my $out = $_[0]->Clone; - $out->Move_Left($_[1]->Word_Read(0)); - print $out->to_Hex,"\n"; - return $out; } -sub VAND { $_[0]{val}=my $o=newsized($_[1]); $o->Intersection($_[1],$_[2]); } -sub VOR { $_[0]{val}=my $o=newsized($_[1]); $o->Union($_[1],$_[2]); } -sub VNAND { $_[0]{val}=my $o=newsized($_[1]); $o->Intersection($_[1],$_[2]); $o->Complement($o); } -sub VNOR { $_[0]{val}=my $o=newsized($_[1]); $o->Union($_[1],$_[2]); $o->Complement($o); } -sub VXOR { $_[0]{val}=my $o=newsized($_[1]); $o->ExclusiveOr($_[1],$_[2]); } -sub VXNOR{ $_[0]{val}=my $o=newsized($_[1]); $o->ExclusiveOr($_[1],$_[2]); $o->Complement($o); } -sub VNOT { $_[0]{val}=my $o=newsized($_[1]); $o->Complement($_[1]); } -sub VSHIFTL{ $_[0]{val}=my $o=$_[1]->Clone; $o->Move_Left ($_[2]->Word_Read(0)); } -sub VSHIFTR{ $_[0]{val}=my $o=$_[1]->Clone; $o->Move_Right($_[2]->Word_Read(0)); } -sub VSHIFTRS{$_[0]{val}=my $o=$_[1]->Clone; $o->Move_Right($_[2]->Word_Read(0)); - if ($_[1]->msb() && $_[2]->Word_Read(0)>0) {$o->Interval_Fill(max(0,$o->Size-1-$_[2]->Word_Read(0)), $o->Size-1); } - #print (" SHI ",$_[0]{val}->to_Hex,' = ',$_[1]->to_Hex,' >>> ',$_[2]->Word_Read(0),"\n"); -} -sub VCLONE { $_[0]{val}=$_[1]->Clone; } -sub VRESIZE { - $_[0]{val}=$_[1]->Clone; - $_[0]{val}->Resize($_[0]{width}); -} -sub VADD { $_[0]{val}=my $o=newsized($_[1]); $o->add($_[1],$_[2],0); } -sub VSUB { $_[0]{val}=my $o=newsized($_[1]); $o->subtract($_[1],$_[2],0); } -sub VMUL { - # Multiply is signed, so need an additional sign bit - my $a=$_[1]->Clone; $a->Resize($a->Size + 1); - my $b=$_[2]->Clone; $b->Resize($b->Size + 1); - my $mo=Bit::Vector->new($_[1]->Size + $_[2]->Size + 1); - $mo->Multiply($a,$b); - my $o=newsized($_[1]); $o->Interval_Copy($mo,0,0,$_[1]->Size); - $_[0]{val}=$o; -} -sub VDIV { - my $is_mod = $_[3]; - if ($_[2]{val}->is_empty) { # Avoid divide by zero - $_[0]{val}=newsized($_[1]{val}); - return; - } - my $a=$_[1]{val}->Clone; if (!$_[1]->{signed}) { $a->Resize($a->Size + 1); } - my $b=$_[2]{val}->Clone; if (!$_[2]->{signed}) { $b->Resize($b->Size + 1); } - #print ("//DIVpp ",$_[1]->to_Hex,' ',$_[2]->to_Hex,' ',$_[1]->Size,'.',$_[2]->Size," \n"); - #print ("//DIVpp ",$a->to_Hex,' ',$b->to_Hex,' ',$a->Size,'.',$b->Size," \n"); - my $quo=newsized($a); my $rem=newsized($a); - $quo->Divide($a,$b,$rem); # No division by zero - handled by if above - my $o=newsized($_[1]{val}); - $o->Interval_Copy($is_mod ? $rem : $quo,0,0,$_[1]{val}->Size); - #print "//DIV",($_[1]->{signed}?"S":" "),' w',$a->Size,' ',$_[1]{val}->to_Hex,' ',$_[2]{val}->to_Hex,' =',$quo->to_Hex,'.',$rem->to_Hex," \n"; - $_[0]{val}=$o; -} -sub VPOW { # Power is a signed operation - my $a=$_[1]{val}->Clone; if (!$_[1]->{signed}) { $a->Resize($_[1]{val}->Size + 1); } - my $b=$_[2]{val}->Clone; if (!$_[2]->{signed}) { $b->Resize($_[2]{val}->Size + 1); } - print "VVpow = ",$_[1]{val}->to_Hex," ** ",$_[2]{val}->to_Hex,"\n"; - my $mo=Bit::Vector->new($_[1]{val}->Size + 1); - $mo->Power($a,$b); - my $o=Bit::Vector->new($_[0]{width}); $o->Interval_Copy($mo,0,0,$_[1]{val}->Size); - $_[0]{val}=$o; - print "VV = $o\n"; -} -sub VRANGE { - #print "RANGE ",$_[1]->to_Hex,' ',$_[2]->to_Hex,' ',$_[3]->to_Hex," \n"; - return VRANGE_CONST($_[0], $_[1], $_[2]->Word_Read(0), - $_[3]->Word_Read(0), $_[4]); -} -sub VBITSELP { - return VRANGE_CONST($_[0], $_[1], $_[2]->Word_Read(0)+$_[3]->Word_Read(0)-1, - $_[2]->Word_Read(0), $_[4]); -} -sub VBITSELM { - return VRANGE_CONST($_[0],$_[1],$_[2]->Word_Read(0), - $_[2]->Word_Read(0)-$_[3]->Word_Read(0)+1, $_[4]); -} -sub VRANGE_CONST { - # to, from, msb, lsb, variable_lsb_to_subtract - #print "RANGE ",$_[1]->to_Hex,' ',$_[2],' ',$_[3],' ',$_[4]," \n"; - my $size = $_[2] - $_[3] + 1; - my $o=Bit::Vector->new($size); - if ($_[3] < $_[1]->Size) { - $o->Interval_Copy($_[1],0,$_[3]-$_[4],$size); - } - $_[0]{val}=$o; } -sub VCONCAT { - my $o=Bit::Vector->new($_[1]->Size + $_[2]->Size); - $o->Interval_Copy($_[1],$_[2]->Size,0,$_[1]->Size); - $o->Interval_Copy($_[2],0,0,$_[2]->Size); - $_[0]{val}=$o; -} -sub VREPLIC { - my $o=Bit::Vector->new($_[1]->Word_Read(0) * $_[2]->Size); - my $pos = 0; - for (my $time=0; $time<($_[1]->Word_Read(0)); $time++) { - $o->Interval_Copy($_[2],$pos,0,$_[2]->Size); - $pos += $_[2]->Size; - } - $_[0]{val}=$o; -} - -####################################################################### -####################################################################### -####################################################################### - -package Vg::Base; -use Data::Dumper; -use strict; - -#------------------------------------------------------------ -# CREATORS - -sub new { - my $class = shift; - my $self = { - width=>0, # Width of expression, 0=Pick a width - #signed=>0/1, # Undef = pick a sign - @_}; - bless $self, $class; - return $self; -} - -# ACCESSORS - -#------------------------------------------------------------ -# OUTPUTTING - -sub val_to_text { - my $treeref = shift; - my $val = lc $treeref->{val}->to_Hex(); - $val = "0" if $treeref->{val}->is_empty; - return ($treeref->{width} - .($treeref->{signed}?"'sh":"'h") - .$val); -} - -sub tree_dump { - my $treeref = shift; - print Dumper($treeref); -} - -####################################################################### -__END__ - -=pod - -=head1 NAME - -vgen.pl - Generate random verilog code - -=head1 SYNOPSIS - - vgen.pl -o vgen.v - -=head1 DESCRIPTION - -vgen.pl generates automatic random verilog programs. - -=head1 ARGUMENTS - -=over 4 - -=item --help - -Displays this message and program version and exits. - -=item --blockstmts - -Number of statements per block. Defaults to 2. - -=item --depth - -Maximum depth of generated expressions. - -=item --initial - -Put all statements into an initial block. This will probably be optimized -down to a NOP. - -=item --numops - -Number of operations to create. - -=item -o I - -Specify output filename. - -=item --raise - -Pick the specified number of random opcodes, and raise their frequency. - -=item --seed - -Seed for the random number generator. Defaults to 5, 0=randomize. - -=item --signed - -Include some signed arithmetic in the generated code. Experimental. - -=back - -=head1 DISTRIBUTION - -Copyright 2001-2020 by Wilson Snyder. This program is free software; you -can redistribute it and/or modify it under the terms of either the GNU -Lesser General Public License Version 3 or the Perl Artistic License -Version 2.0. - -SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0 - -=head1 AUTHORS - -Wilson Snyder - -=head1 SEE ALSO - -=cut - -###################################################################### -### Local Variables: -### compile-command: "./vgen.pl --depth=10 --blockstmts=10 -o obj_dir/vgen.v" -### compile-command: "v4make test_regress/t/t_vgen.pl " -### End: