Merge from master for release.

This commit is contained in:
Wilson Snyder 2020-12-02 20:13:31 -05:00
commit b7fec513cf
421 changed files with 13443 additions and 5591 deletions

View File

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

28
Changes
View File

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

View File

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

View File

@ -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<ext>
@ -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<make> 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<make> 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

View File

@ -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);

View File

@ -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 && \

View File

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

View File

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

View File

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

View File

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

View File

@ -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<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
t_state[1] = ((static_cast<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
} else {
t_state[0] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(vl_sys_rand32())));
t_state[1] = ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(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<int>(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<vlsint64_t>(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<double>(ld), left, width);
output += _vl_vsformat_time(t_tmp, static_cast<double>(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='"<<pos[0]<<"' floc="<<floc<<" file='"<<_vl_vsss_peek(fp, floc,
// fromp, fstr)<<"'"<<endl);
// fromp, fstr)<<"'\n");
if (!inPct && pos[0] == '%') {
inPct = true;
inIgnore = false;
@ -1101,13 +1098,13 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
}
case 's': {
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, tmp, nullptr);
if (!tmp[0]) goto done;
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, nullptr);
if (!t_tmp[0]) goto done;
if (owp) {
int lpos = (static_cast<int>(strlen(tmp))) - 1;
int lpos = (static_cast<int>(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<vluint64_t>(Verilated::randSeed()) << 32)
^ (static_cast<vluint64_t>(Verilated::randSeed())));
} else {
return ((static_cast<vluint64_t>(vl_sys_rand32()) << 32)
^ (static_cast<vluint64_t>(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<char*>(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 <list>
// in verilated.h (for compilation speed)
typedef std::list<std::pair<Verilated::VoidPCb, void*>> 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<Verilated::VoidPCb, void*> 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);

View File

@ -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;

View File

@ -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 T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
template <class T> 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<const std::string, int> 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';
}
}
};

View File

@ -88,7 +88,7 @@ template <class T> 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:

View File

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

View File

@ -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<VerilatedFst> {
class VerilatedFst final : public VerilatedTrace<VerilatedFst> {
private:
// Give the superclass access to private bits (to avoid virtual functions)
friend class VerilatedTrace<VerilatedFst>;
@ -128,7 +128,7 @@ template <> void VerilatedTrace<VerilatedFst>::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

View File

@ -32,6 +32,7 @@
#include <memory>
#include <set>
#include <string>
#include <unordered_set>
//===================================================================
// 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 T_Value, size_t T_MaxSize = 0> class VlQueue {
template <class T_Value, size_t T_MaxSize = 0> class VlQueue final {
private:
// TYPES
typedef std::deque<T_Value> 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 <typename Func> 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 <typename Func> 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<T_Value> saw;
std::unordered_set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
@ -273,7 +282,7 @@ public:
VlQueue<IData> unique_index() const {
VlQueue<IData> out;
IData index = 0;
std::set<T_Value> saw;
std::unordered_set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
if (it == saw.end()) {
@ -286,39 +295,54 @@ public:
}
template <typename Func> 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 <typename Func> VlQueue<IData> find_index(Func with_func) const {
VlQueue<IData> 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 <typename Func> 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 <typename Func> VlQueue<IData> 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<IData>{};
return VlQueue<IData>::cons(std::distance(m_deque.begin(), it));
IData index = 0;
for (const auto& i : m_deque) {
if (with_func(index, i)) return VlQueue<IData>::cons(index);
++index;
}
return VlQueue<IData>{};
}
template <typename Func> 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 <typename Func> VlQueue<IData> 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<IData>{};
// Return index must be relative to beginning
return VlQueue<IData>::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<IData>::cons(index);
--index;
}
return VlQueue<IData>{};
}
// Reduction operators
@ -340,7 +364,8 @@ public:
}
template <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <class T_Value> std::string VL_TO_STRING(const VlQueue<T_Value>& 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 <std::size_t T_Words> class VlWide {
template <std::size_t T_Words> 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::size_t T_Words> std::string VL_TO_STRING(const VlWide<T_Words>& o
// There are no multithreaded locks on this; the base variable must
// be protected by other means
//
template <class T_Key, class T_Value> class VlAssocArray {
template <class T_Key, class T_Value> class VlAssocArray final {
private:
// TYPES
typedef std::map<T_Key, T_Value> 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 <typename Func> VlQueue<T_Value> find(Func with_func) const {
VlQueue<T_Value> 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 <typename Func> VlQueue<T_Key> find_index(Func with_func) const {
VlQueue<T_Key> 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 <typename Func> VlQueue<T_Value> find_first(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
@ -598,7 +637,7 @@ public:
template <typename Func> VlQueue<T_Key> find_first_index(Func with_func) const {
const auto it
= std::find_if(m_map.begin(), m_map.end(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.end()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
@ -606,7 +645,7 @@ public:
template <typename Func> VlQueue<T_Value> find_last(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Value>::cons(it->second);
@ -614,7 +653,7 @@ public:
template <typename Func> VlQueue<T_Key> find_last_index(Func with_func) const {
const auto it
= std::find_if(m_map.rbegin(), m_map.rend(), [=](const std::pair<T_Key, T_Value>& i) {
return with_func(i.second);
return with_func(i.first, i.second);
});
if (it == m_map.rend()) return VlQueue<T_Value>{};
return VlQueue<T_Key>::cons(it->first);
@ -647,7 +686,7 @@ public:
}
template <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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 <typename Func> 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);

View File

@ -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<void()>& 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<VerilatedMsg, VerilatedMsg::Cmp> VerilatedThreadQueue;
std::atomic<vluint64_t> 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<VerilatedMsg> 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();

View File

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

View File

@ -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<const VlScBvExposer*>(&base)->sp_datatp();

View File

@ -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<void*>(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

View File

@ -31,6 +31,7 @@
#include "verilated_sym_props.h"
#include <map>
#include <unordered_map>
#include <vector>
//======================================================================
@ -42,26 +43,27 @@ struct VerilatedCStrCmp {
};
/// Map of sorted scope names to find associated scope class
class VerilatedScopeNameMap
class VerilatedScopeNameMap final
: public std::map<const char*, const VerilatedScope*, VerilatedCStrCmp> {
public:
VerilatedScopeNameMap() {}
~VerilatedScopeNameMap() {}
VerilatedScopeNameMap() = default;
~VerilatedScopeNameMap() = default;
};
/// Map of sorted variable names to find associated variable class
class VerilatedVarNameMap : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
class VerilatedVarNameMap final : public std::map<const char*, VerilatedVar, VerilatedCStrCmp> {
public:
VerilatedVarNameMap() {}
~VerilatedVarNameMap() {}
VerilatedVarNameMap() = default;
~VerilatedVarNameMap() = default;
};
typedef std::vector<const VerilatedScope*> VerilatedScopeVector;
class VerilatedHierarchyMap : public std::map<const VerilatedScope*, VerilatedScopeVector> {
class VerilatedHierarchyMap final
: public std::unordered_map<const VerilatedScope*, VerilatedScopeVector> {
public:
VerilatedHierarchyMap() {}
~VerilatedHierarchyMap() {}
VerilatedHierarchyMap() = default;
~VerilatedHierarchyMap() = default;
};
#endif // Guard

View File

@ -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<vluint64_t> 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<VlProfileRec> ProfileTrace;
typedef std::set<ProfileTrace*> ProfileSet;

View File

@ -40,7 +40,7 @@
// Threaded tracing
// A simple synchronized first in first out queue
template <class T> class VerilatedThreadQueue { // LCOV_EXCL_LINE // lcov bug
template <class T> 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 T_Derived> class VerilatedTrace {
template <class T_Derived> class VerilatedTrace VL_NOT_FINAL {
public:
//=========================================================================
// Generic tracing internals

View File

@ -559,7 +559,7 @@ template <> void VerilatedTrace<VL_DERIVED_T>::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);
}

View File

@ -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<VerilatedVcd> {
class VerilatedVcd VL_NOT_FINAL : public VerilatedTrace<VerilatedVcd> {
private:
// Give the superclass access to private bits (to avoid virtual functions)
friend class VerilatedTrace<VerilatedVcd>;
@ -329,7 +329,7 @@ template <> void VerilatedTrace<VerilatedVcd>::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

View File

@ -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);

View File

@ -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<vluint8_t*>(::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<vluint8_t*>(obj)) - 8;
*(reinterpret_cast<void**>(oldp)) = t_freeHead;
t_freeHead = oldp;
}
// MEMBERS
static inline VerilatedVpio* castp(vpiHandle h) {
static VerilatedVpio* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpio*>(reinterpret_cast<VerilatedVpio*>(h));
}
inline vpiHandle castVpiHandle() { return reinterpret_cast<vpiHandle>(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<VerilatedVpioCb*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioConst*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioParam*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioRange*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioScope*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioVar*>(reinterpret_cast<VerilatedVpio*>(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<vluint8_t*>(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<VerilatedVpioMemoryWord*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioVarIter*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioMemoryWordIter*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioModule*>(reinterpret_cast<VerilatedVpio*>(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<const VerilatedScope*>* m_vec;
std::vector<const VerilatedScope*>::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<VerilatedVpioModuleIter*>(reinterpret_cast<VerilatedVpio*>(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<VerilatedVpioCb*> VpioCbList;
typedef std::set<std::pair<QData, VerilatedVpioCb*>, 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<VerilatedVpioVar*> VpioVarSet;
typedef std::unordered_set<VerilatedVpioVar*> 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<PLI_BYTE8*>(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<PLI_BYTE8*>(filehold.c_str()), line);
t_filehold = file;
setError((PLI_BYTE8*)m_buff, nullptr, const_cast<PLI_BYTE8*>(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<CData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT16) {
out[0].aval = *(reinterpret_cast<SData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<SData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT32) {
out[0].aval = *(reinterpret_cast<IData*>(varDatap));
out[0].bval = 0;
t_out[0].aval = *(reinterpret_cast<IData*>(varDatap));
t_out[0].bval = 0;
return;
} else if (varp->vltype() == VLVT_UINT64) {
QData data = *(reinterpret_cast<QData*>(varDatap));
out[1].aval = static_cast<IData>(data >> 32ULL);
out[1].bval = 0;
out[0].aval = static_cast<IData>(data);
out[0].bval = 0;
t_out[1].aval = static_cast<IData>(data >> 32ULL);
t_out[1].bval = 0;
t_out[0].aval = static_cast<IData>(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<EData*>(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<CData*>(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<CData*>(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<unsigned char>(*(reinterpret_cast<CData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT16) {
VL_SNPRINTF(outStr, outStrSz + 1, "%hu",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%hu",
static_cast<unsigned short>(*(reinterpret_cast<SData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT32) {
VL_SNPRINTF(outStr, outStrSz + 1, "%u",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%u",
static_cast<unsigned int>(*(reinterpret_cast<IData*>(varDatap))));
return;
} else if (varp->vltype() == VLVT_UINT64) {
VL_SNPRINTF(outStr, outStrSz + 1, "%llu",
VL_SNPRINTF(t_outStr, t_outStrSz + 1, "%llu",
static_cast<unsigned long long>(*(reinterpret_cast<QData*>(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<CData*>(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<int>(val)];
t_outStr[chars - i - 1] = "0123456789abcdef"[static_cast<int>(val)];
}
outStr[i] = '\0';
t_outStr[i] = '\0';
return;
} else if (valuep->format == vpiStringVal) {
if (varp->vltype() == VLVT_STRING) {
valuep->value.str = reinterpret_cast<char*>(varDatap);
return;
} else {
valuep->value.str = outStr;
valuep->value.str = t_outStr;
int bytes = VL_BYTES_I(varp->packed().elements());
CData* datap = (reinterpret_cast<CData*>(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) {

View File

@ -33,7 +33,7 @@
//======================================================================
class VerilatedVpi {
class VerilatedVpi final {
public:
/// Call timed callbacks
/// Users should call this from their main loops

View File

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

View File

@ -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=<hidden>\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";
}
#######################################################################

View File

@ -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;

View File

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

View File

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

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Active {
class V3Active final {
public:
static void activeAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3ActiveTop {
class V3ActiveTop final {
public:
static void activeTopAll(AstNetlist* nodep);
};

View File

@ -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<AstNode*>(new AstCMath(fl, "Verilated::assertOn()", 1))
: static_cast<AstNode*>(new AstConst(fl, AstConst::LogicFalse()))),
: static_cast<AstNode*>(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);
}
}

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Assert {
class V3Assert final {
public:
static void assertAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3AssertPre {
class V3AssertPre final {
public:
static void assertPreAll(AstNetlist* nodep);
};

View File

@ -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 << "<nullptr>" << 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 << "<nullptr>" << 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 << "<nullptr>" << 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<std::ofstream> logsp(V3File::new_ofstream(filename, append));
if (logsp->fail()) v3fatal("Can't write " << filename);
*logsp << "Verilator Tree Dump (format 0x3900) from <e" << std::dec << editCountLast();
*logsp << "> to <e" << std::dec << editCountGbl() << ">" << endl;
*logsp << "> to <e" << std::dec << editCountGbl() << ">\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<AstNode*>(this)->dump(nsstr);
nsstr << endl;

View File

@ -71,7 +71,7 @@ typedef std::set<int> 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<en>(_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<WidthVP*>(m_u.up); }
VSymEnt* toSymEnt() const { return reinterpret_cast<VSymEnt*>(m_u.up); }
AstNode* toNodep() const { return reinterpret_cast<AstNode*>(m_u.up); }
V3GraphVertex* toGraphVertex() const { return reinterpret_cast<V3GraphVertex*>(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<AstNode*> 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<Ast##name*>(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;
}

View File

@ -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*> AstUnpackArrayDType::unpackDimensions() {
std::vector<AstUnpackArrayDType*> 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<int>(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()) {

File diff suppressed because it is too large Load Diff

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Begin {
class V3Begin final {
public:
static void debeginAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Branch {
class V3Branch final {
public:
// CONSTRUCTORS
static void branchAll(AstNetlist* nodep);

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Broken {
class V3Broken final {
public:
static void brokenAll(AstNetlist* nodep);
static void addNewed(AstNode* nodep);

View File

@ -34,7 +34,7 @@
#include <algorithm>
#include <map>
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);

View File

@ -25,7 +25,7 @@
//============================================================================
class V3CCtors {
class V3CCtors final {
public:
static void cctorsAll();

View File

@ -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);
};

View File

@ -25,7 +25,7 @@
//============================================================================
class V3CUse {
class V3CUse final {
public:
static void cUseAll();
};

View File

@ -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<AstNode*, 1 << CASE_OVERLAP_WIDTH> 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) {

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Case {
class V3Case final {
public:
static void caseAll(AstNetlist* nodep);
static void caseLint(AstNodeCase* nodep);

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Cast {
class V3Cast final {
public:
static void castAll(AstNetlist* nodep);
};

View File

@ -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<std::ofstream> 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<string> 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 {

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Cdc {
class V3Cdc final {
public:
static void cdcAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Changed {
class V3Changed final {
public:
static void changedAll(AstNetlist* nodep);
};

View File

@ -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));
}
}

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Class {
class V3Class final {
public:
static void classAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Clean {
class V3Clean final {
public:
static void cleanAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Clock {
class V3Clock final {
public:
static void clockAll(AstNetlist* nodep);
};

View File

@ -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:

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Combine {
class V3Combine final {
public:
static void combineAll(AstNetlist* nodep);
};

View File

@ -38,8 +38,8 @@ template <typename T> 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<V3ConfigVarAttr> {
class V3ConfigVar final : public std::vector<V3ConfigVarAttr> {
public:
// Update from other by copying all attributes
void update(const V3ConfigVar& node) {
@ -116,14 +116,14 @@ typedef V3ConfigWildcardResolver<V3ConfigVar> 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<V3ConfigFTask> V3ConfigFTaskResolver;
//######################################################################
// Modules have tasks, variables, named blocks and properties
class V3ConfigModule {
class V3ConfigModule final {
typedef std::unordered_set<string> StringSet;
typedef std::set<AstPragmaType> 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<V3ConfigModule> 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<AstPragmaType::ENUM_SIZE> V3ConfigLineAttribute;
// File entity
class V3ConfigFile {
class V3ConfigFile final {
typedef std::map<int, V3ConfigLineAttribute> LineAttrMap; // Map line->bitset of attributes
typedef std::multiset<V3ConfigIgnoresLine> IgnLines; // list of {line,code,on}
typedef std::pair<V3ErrorCode, string> WaiverSetting; // Waive code if string matches
@ -347,16 +347,16 @@ typedef V3ConfigWildcardResolver<V3ConfigFile> 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);

View File

@ -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);

View File

@ -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);

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Const {
class V3Const final {
public:
static AstNode* constifyParamsEdit(AstNode* nodep);
static AstNode* constifyGenerateParamsEdit(AstNode* nodep);

View File

@ -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<string, int> 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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Coverage {
class V3Coverage final {
public:
// CONSTRUCTORS
static void coverage(AstNetlist* rootp);

View File

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

View File

@ -25,7 +25,7 @@
//============================================================================
class V3CoverageJoin {
class V3CoverageJoin final {
public:
// CONSTRUCTORS
static void coverageJoin(AstNetlist* rootp);

View File

@ -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<AstVarScope*, AstNodeAssign*> 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<AstVar*> m_varsp;
std::vector<AstNode*> m_dtypesp;
@ -93,10 +92,10 @@ private:
std::vector<AstClass*> 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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Dead {
class V3Dead final {
public:
// Modules, no vars/dtypes
static void deadifyModules(AstNetlist* nodep);

View File

@ -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<const std::pair<AstNodeModule*, string>, AstVar*> VarMap;
VarMap m_modVarMap; // Table of new var names created under module
VDouble0 m_statSharedSet; // Statistic tracking
typedef std::map<const AstVarScope*, int> ScopeVecMap;
typedef std::unordered_map<const AstVarScope*, int> 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(),

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Delayed {
class V3Delayed final {
public:
static void delayedAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Depth {
class V3Depth final {
public:
static void depthAll(AstNetlist* nodep);
};

View File

@ -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;
};
//######################################################################

View File

@ -25,7 +25,7 @@
//============================================================================
class V3DepthBlock {
class V3DepthBlock final {
public:
static void depthBlockAll(AstNetlist* nodep);
};

View File

@ -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);
}

View File

@ -25,7 +25,7 @@
//============================================================================
class V3Descope {
class V3Descope final {
public:
static void descopeAll(AstNetlist* nodep);
};

View File

@ -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<const AstVar*> VarVec;
typedef std::map<int, VarVec> 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<const EmitVarTspSorter&>(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<AstChangeDet*> 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);

View File

@ -25,7 +25,7 @@
//============================================================================
class V3EmitC {
class V3EmitC final {
public:
static void emitc();
static void emitcInlines();

View File

@ -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; }
};

View File

@ -26,7 +26,7 @@
//######################################################################
class EmitCInlines : EmitCBaseVisitor {
class EmitCInlines final : EmitCBaseVisitor {
// STATE
// METHODS

View File

@ -26,7 +26,7 @@
//######################################################################
class EmitCMain : EmitCBaseVisitor {
class EmitCMain final : EmitCBaseVisitor {
// METHODS
// VISITORS

View File

@ -22,7 +22,7 @@
//============================================================================
class V3EmitCMain {
class V3EmitCMain final {
public:
static void emit();
};

View File

@ -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() {

View File

@ -22,7 +22,7 @@
//============================================================================
class V3EmitCMake {
class V3EmitCMake final {
public:
static void emit();
};

View File

@ -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<string> ScopeNameList;
typedef std::map<const string, ScopeNameList> 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<int, bool> m_usesVfinal; // Split method uses __Vfinal
std::unordered_map<int, bool> 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) + "(");

View File

@ -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 {

Some files were not shown because too many files have changed in this diff Show More