Merge from master for release.

This commit is contained in:
Wilson Snyder 2022-12-14 22:07:37 -05:00
commit 8468af1a20
567 changed files with 38692 additions and 32809 deletions

View File

@ -35,13 +35,13 @@ jobs:
- { cc: gcc, cxx: g++ }
m32: [0, 1]
exclude:
# Build pull requests only with ubuntu-20.04 and without m32
# Build pull requests only with ubuntu-22.04 and without m32
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-20.04
# Build -m32 only on ubuntu-22.04
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-22.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
include:
# Build GCC 10 on ubuntu-20.04
- os: ubuntu-20.04
@ -104,13 +104,13 @@ jobs:
m32: [0, 1]
suite: [dist-vlt-0, dist-vlt-1, dist-vlt-2, vltmt-0, vltmt-1]
exclude:
# Build pull requests only with ubuntu-20.04 and without m32
# Build pull requests only with ubuntu-22.04 and without m32
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-18.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-22.04' || 'do-not-exclude' }}
- os: ${{ github.event_name == 'pull_request' && 'ubuntu-20.04' || 'do-not-exclude' }}
- m32: ${{ github.event_name == 'pull_request' && 1 || 'do-not-exclude' }}
# Build -m32 only on ubuntu-20.04
# Build -m32 only on ubuntu-22.04
- {os: ubuntu-18.04, m32: 1}
- {os: ubuntu-22.04, m32: 1}
- {os: ubuntu-20.04, m32: 1}
include:
# Test with GCC 10 on ubuntu-20.04 without m32
- {os: ubuntu-20.04, compiler: { cc: gcc-10, cxx: g++-10 }, m32: 0, suite: dist-vlt-0}

66
Changes
View File

@ -8,6 +8,60 @@ The changes in each Verilator version are described below. The
contributors that suggested a given feature are shown in []. Thanks!
Verilator 5.004 2022-12-14
==========================
**Major:**
* Support named properties (#3667). [Ryszard Rozak, Antmicro Ltd]
* Add ENUMVALUE warning when value misused for enum (#726) (#3777) (#3783).
* Deprecate --no-threads; use --threads 1 for single threaded (#3703). [Kamil Rakoczy, Antmicro Ltd]
**Minor:**
* Support std::semaphore and typed std::mailbox (#3708). [Krzysztof Bieganski, Antmicro Ltd]
* Support 'with' in unique, unique_index, min, max in queues (#3772). [Ryszard Rozak, Antmicro Ltd]
* Support events in VCD/FST traces (#3759). [Yves Mathieu]
* Support foreach loops on strings (#3760). [Ryszard Rozak, Antmicro Ltd]
* Support member selects in with clauses (#3775). [Ryszard Rozak, Antmicro Ltd]
* Support super.new calls (#3789). [Ryszard Rozak, Antmicro Ltd]
* Support randcase.
* Support pre_randomize and post_randomize.
* Support $timeunit and $timeprecision.
* Support assignment expressions.
* Change ENDLABEL from warning into an error.
* Internal AST improvements, also affect XML format (#3721). [Geza Lore]
* Deprecate verilated_fst_sc.cpp and verilated_vcd_sc.cpp.
* Disable stack size limit (#3706) (#3751). [Mariusz Glebocki]
* Add error when use --exe with --lib-create (#3785). [Yinan Xu]
* Fix jump handling in do while loops (#3731). [Ryszard Rozak, Antmicro Ltd]
* Fix 'with' clause handling in functions (#3739). [Ryszard Rozak, Antmicro Ltd]
* Fix CONTEXT compile error on mingw64 (#3741). [William D. Jones]
* Fix MSVC compiler errors (#3742) (#3746). [Kritik Bhimani]
* Fix CASEINCOMPLETE when covers all enum values (#3745) (#3782). [Guy-Armand Kamendje]
* Fix return type of $countbits functions to int (#3725). [Ryszard Rozak, Antmicro Ltd]
* Fix timing control in while-break loops (#3733) (#3769). [Ryszard Rozak, Antmicro Ltd]
* Fix return in constructors (#3734). [Ryszard Rozak, Antmicro Ltd]
* Fix missing UNUSED warnings with --coverage (#3736). [alejandro-castro-ortegon]
* Fix tracing parameters overridden with -G (#3723). [Iztok Jeras]
* Fix folding of LogAnd with non-bool operands (#3726). [Geza Lore]
* Fix Dfg optimization issues (#3740) (#3771). [Geza Lore]
* Fix pre/postincrement operations (#3744) (#3756). [Ryszard Rozak, Antmicro Ltd]
* Fix cross-compile for MingW, Arm and RiscV (#3752). [Miodrag Milanović]
* Fix $unit as base package for other packages (#3755). [Ryszard Rozak, Antmicro Ltd]
* Fix make jobserver with submakes (#3758). [Gus Smith]
* Fix to escape VERILATOR_ROOT file paths (#3764) (#3765). [Jiacheng Qian]
* Fix empty string literals converting to string types (#3774). [miree]
* Fix to remove $date from .vcd files (#3779). [Larry Doolittle]
* Fix missing user objects in --lib-create mode (#3780) (#3784). [Yinan Xu]
* Fix non-blocking assignments in forks (#3781) (#3800). [Krzysztof Bieganski, Antmicro Ltd]
* Fix forks without any delayed statements (#3792) (#3801). [Krzysztof Bieganski, Antmicro Ltd]
* Fix internal error in bit op tree optimization (#3793). [Yutetsu TAKATSUKASA]
* Fix lint_off EOFNEWLINE in .vlt files (#3796). [Andrew Nolte]
* Fix wait 0.
* Fix comparing ranged slices of unpacked arrays.
Verilator 5.002 2022-10-29
==========================
@ -50,7 +104,7 @@ Verilator 5.002 2022-10-29
* Fix linker errors in user-facing timing functions (#3657). [Krzysztof Bieganski, Antmicro Ltd]
* Fix null access on optimized-out fork statements (#3658). [Krzysztof Bieganski, Antmicro Ltd]
* Fix VPI inline module naming mismatch (#3690) (#3694). [Jiuyang Liu]
* Fix deadlock in timeprecision when using systemC (#3707). [Kamil Rakoczy, Antmicro Ltd]
* Fix deadlock in timeprecision when using SystemC (#3707). [Kamil Rakoczy, Antmicro Ltd]
* Fix width mismatch on inside operator (#3714). [Alex Torregrosa]
@ -2962,7 +3016,7 @@ Verilator 3.502 2005-11-30 Stable
* Fix local non-IO variables in public functions and tasks.
* Fix bad lifetime optimization when same signal is assigned multiple
times in both branch of a if. [Danny Ding]
times in both branch of an if. [Danny Ding]
Verilator 3.501 2005-11-16 Stable
@ -3102,8 +3156,8 @@ Verilator 3.450 2005-07-12
* $finish will no longer exit, but set Verilated::gotFinish().
This enables support for final statements, and for other cleanup code.
If this is undesired, redefine the vl_user_finish routine. Top level
loops should use Verilated::gotFinish() as a exit condition for their
loop, and then call top->final(). To prevent a infinite loop, a double
loops should use Verilated::gotFinish() as an exit condition for their
loop, and then call top->final(). To prevent an infinite loop, a double
$finish will still exit; this may be removed in future releases.
* Support SystemVerilog keywords $bits, $countones, $isunknown,
$onehot, $onehot0, always_comb, always_ff, always_latch, finish.
@ -3504,7 +3558,7 @@ Verilator 3.201-beta 2003-12-10
**Major:**
* BETA VERSION, USE 3.124 for stable release!
* Version 3.2XX includes a all new back-end.
* Version 3.2XX includes an all new back-end.
This includes automatic inlining, flattening of signals between
hierarchy, and complete ordering of statements. This results in
60-300% execution speedups, though less pretty C++ output. Even
@ -3533,7 +3587,7 @@ Verilator 3.124 2003-12-05
**Major:**
* A optimized executable will be made by default, in addition to a debug
* An optimized executable will be made by default, in addition to a debug
executable. Invoking Verilator with --debug will pick the debug version.
**Minor:**

View File

@ -204,6 +204,7 @@ VL_INST_INC_BLDDIR_FILES = \
# Files under srcdir, instead of build time
VL_INST_INC_SRCDIR_FILES = \
include/*.[chv]* \
include/*.sv \
include/gtkwave/*.[chv]* \
include/vltstd/*.[chv]* \
@ -302,35 +303,57 @@ install-all: installbin installman installdata install-msg
install-here: installman info
# Use --xml flag to see the cppcheck code to use for suppression
CPPCHECK_CPP = $(wildcard \
$(srcdir)/examples/*/*.cpp \
$(srcdir)/include/*.cpp \
$(srcdir)/src/*.cpp )
CPPCHECK_H = $(wildcard \
CPPCHECK1_CPP = $(wildcard $(srcdir)/include/*.cpp)
CPPCHECK2_CPP = $(wildcard $(srcdir)/examples/*/*.cpp)
CPPCHECK3_CPP = $(wildcard $(srcdir)/src/Vlc*.cpp)
CPPCHECK4_CPP = $(wildcard $(srcdir)/src/V3[A-D]*.cpp $(srcdir)/src/Verilator*.cpp)
CPPCHECK5_CPP = $(wildcard $(srcdir)/src/V3[E-I]*.cpp)
CPPCHECK6_CPP = $(wildcard $(srcdir)/src/V3[P-Z]*.cpp)
CPPCHECK7_CPP = $(wildcard $(srcdir)/src/V3[L-R]*.cpp)
CPPCHECK8_CPP = $(wildcard $(srcdir)/src/V3[S-Z]*.cpp)
CHECK_CPP = $(CPPCHECK1_CPP) $(CPPCHECK2_CPP) $(CPPCHECK3_CPP) $(CPPCHECK4_CPP) \
$(CPPCHECK5_CPP) $(CPPCHECK6_CPP) $(CPPCHECK7_CPP) $(CPPCHECK8_CPP)
CHECK_H = $(wildcard \
$(srcdir)/include/*.h \
$(srcdir)/src/*.h )
CPPCHECK_YL = $(wildcard \
CHECK_YL = $(wildcard \
$(srcdir)/src/*.y \
$(srcdir)/src/*.l )
CPPCHECK = src/cppcheck_filtered cppcheck
CPPCHECK_FLAGS = --enable=all --inline-suppr \
--suppress=unusedScopedObject --suppress=cstyleCast --suppress=useInitializationList \
--suppress=nullPointerRedundantCheck
--suppress=cstyleCast --suppress=useInitializationList \
--suppress=nullPointer --suppress=nullPointerRedundantCheck --suppress=ctunullpointer \
--suppress=unusedFunction --suppress=unusedScopedObject \
--suppress=useStlAlgorithm
CPPCHECK_FLAGS += --xml
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CHECK_CPP))
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
cppcheck: $(CPPCHECK_DEP)
%.cppcheck: %.cpp
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 -DVL_THREADED=1 $(CPPCHECK_INC) $<
cppcheck: cppcheck-1 cppcheck-2 cppcheck-3 cppcheck-4 cppcheck-5 cppcheck-6 cppcheck-7 cppcheck-8
cppcheck-1:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK1_CPP)
cppcheck-2:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK2_CPP)
cppcheck-3:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK3_CPP)
cppcheck-4:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK4_CPP)
cppcheck-5:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK5_CPP)
cppcheck-6:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK6_CPP)
cppcheck-7:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK7_CPP)
cppcheck-8:
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -DVL_CPPCHECK=1 $(CPPCHECK_INC) $(CPPCHECK8_CPP)
CLANGTIDY = clang-tidy
CLANGTIDY_FLAGS = -config='' \
-header-filter='.*' \
-checks='-fuchsia-*,-cppcoreguidelines-avoid-c-arrays,-cppcoreguidelines-init-variables,-cppcoreguidelines-avoid-goto,-modernize-avoid-c-arrays,-readability-magic-numbers,-readability-simplify-boolean-expr,-cppcoreguidelines-macro-usage' \
CLANGTIDY_DEP = $(subst .cpp,.cpp.tidy,$(CPPCHECK_CPP))
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_THREADED=1 -DVL_CPPCHECK=1
CLANGTIDY_DEP = $(subst .cpp,.cpp.tidy,$(CHECK_CPP))
CLANGTIDY_DEFS = -DVL_DEBUG=1 -DVL_CPPCHECK=1
clang-tidy: $(CLANGTIDY_DEP)
%.cpp.tidy: %.cpp
@ -350,7 +373,7 @@ format: clang-format yapf format-pl-exec
CLANGFORMAT = clang-format-14
CLANGFORMAT_FLAGS = -i
CLANGFORMAT_FILES = $(CPPCHECK_CPP) $(CPPCHECK_H) $(CPPCHECK_YL) test_regress/t/*.c* test_regress/t/*.h
CLANGFORMAT_FILES = $(CHECK_CPP) $(CHECK_H) $(CHECK_YL) test_regress/t/*.c* test_regress/t/*.h
clang-format:
@$(CLANGFORMAT) --version | egrep 14.0 > /dev/null \

View File

@ -29,10 +29,10 @@ Welcome to Verilator
* - |verilator multithreaded performance|
- **Fast**
* Outperforms many closed-source commercial simulators
* Single- and multi-threaded output models
* Single- and multithreaded output models
* - **Widely Used**
* Wide industry and academic deployment
* Out-of-the-box support from Arm, and RISC-V vendor IP
* Out-of-the-box support from Arm and RISC-V vendor IP
- |verilator usage|
* - |verilator community|
- **Community Driven & Openly Licensed**
@ -52,7 +52,7 @@ What Verilator Does
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
"Verilates" the specified Verilog or SystemVerilog code by reading it,
performing lint checks, and optionally inserting assertion checks and
coverage-analysis points. It outputs single- or multi-threaded .cpp and .h
coverage-analysis points. It outputs single- or multithreaded .cpp and .h
files, the "Verilated" code.
These Verilated C++/SystemC files are then compiled by a C++ compiler
@ -61,11 +61,11 @@ file to instantiate the Verilated model. Executing the resulting executable
performs the design simulation. Verilator also supports linking Verilated
generated libraries, optionally encrypted, into other simulators.
Verilator may not be the best choice if you are expecting a full featured
replacement for a closed-source Verilog simulator, need SDF annotation,
Verilator may not be the best choice if you are expecting a full-featured
replacement for a closed-source Verilog simulator, needs SDF annotation,
mixed-signal simulation, or are doing a quick class project (we recommend
`Icarus Verilog`_ for classwork.) However, if you are looking for a path
to migrate SystemVerilog to C++/SystemC, or want high speed simulation of
to migrate SystemVerilog to C++/SystemC, or want high-speed simulation of
synthesizable designs containing limited verification constructs, Verilator
is the tool for you.
@ -86,7 +86,7 @@ Verilator has typically similar or better performance versus the
closed-source Verilog simulators (Carbon Design Systems Carbonator,
Modelsim/Questa, Cadence Incisive/NC-Verilog, Synopsys VCS, VTOC, and
Pragmatic CVer/CVC). But, Verilator is open-sourced, so you can spend on
computes rather than licenses. Thus Verilator gives you the best
computes rather than licenses. Thus, Verilator gives you the best
cycles/dollar.
@ -101,7 +101,7 @@ For more information:
- `Verilator manual (HTML) <https://verilator.org/verilator_doc.html>`_,
or `Verilator manual (PDF) <https://verilator.org/verilator_doc.pdf>`_
- `Subscribe to verilator announcements
- `Subscribe to Verilator announcements
<https://github.com/verilator/verilator-announce>`_
- `Verilator forum <https://verilator.org/forum>`_
@ -132,7 +132,7 @@ Related Projects
- `GTKwave <http://gtkwave.sourceforge.net/>`_ - Waveform viewer for
Verilator traces.
- `Icarus Verilog`_ - Icarus is a full featured interpreted Verilog
- `Icarus Verilog`_ - Icarus is a full-featured interpreted Verilog
simulator. If Verilator does not support your needs, perhaps Icarus may.

View File

@ -31,6 +31,7 @@ my $opt_gdb;
my $opt_rr;
my $opt_gdbbt;
my $opt_quiet_exit;
my $opt_unlimited_stack = 1;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
@ -49,16 +50,17 @@ foreach my $sw (@ARGV) {
Getopt::Long::config("no_auto_abbrev", "pass_through");
if (! GetOptions(
# Major operating modes
"help" => \&usage,
"debug" => \&debug,
# "version!" => \&version, # Also passthru'ed
"help" => \&usage,
"debug" => \&debug,
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"quiet-exit!" => \$opt_quiet_exit,
"rr!" => \$opt_rr,
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"quiet-exit!" => \$opt_quiet_exit,
"rr!" => \$opt_rr,
"unlimited-stack!" => \$opt_unlimited_stack,
# Additional parameters
"<>" => sub {}, # Ignored
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus => 2, -verbose => 0);
}
@ -76,7 +78,8 @@ if ($opt_gdbbt && !gdb_works()) {
my @quoted_sw = map { sh_escape($_) } @Opt_Verilator_Sw;
if ($opt_gdb) {
# Generic GDB interactive
run (aslr_off()
run (ulimit_stack_unlimited()
. aslr_off()
. ($ENV{VERILATOR_GDB} || "gdb")
. " " . verilator_bin()
# Note, uncomment to set breakpoints before running:
@ -92,12 +95,14 @@ if ($opt_gdb) {
. " -ex 'bt'");
} elsif ($opt_rr) {
# Record with rr
run (aslr_off()
run (ulimit_stack_unlimited()
. aslr_off()
. "rr record " . verilator_bin()
. " " . join(' ', @quoted_sw));
} elsif ($opt_gdbbt && $Debug) {
# Run under GDB to get gdbbt
run (aslr_off()
run (ulimit_stack_unlimited()
. aslr_off()
. "gdb"
. " " . verilator_bin()
. " --batch --quiet --return-child-result"
@ -106,10 +111,13 @@ if ($opt_gdb) {
. " -ex 'bt' -ex 'quit'");
} elsif ($Debug) {
# Debug
run(aslr_off() . verilator_bin() . " " . join(' ', @quoted_sw));
run(ulimit_stack_unlimited()
. aslr_off()
. verilator_bin()
. " " . join(' ', @quoted_sw));
} else {
# Normal, non gdb
run(verilator_bin() . " " . join(' ', @quoted_sw));
run(ulimit_stack_unlimited() . verilator_bin() . " " . join(' ', @quoted_sw));
}
#----------------------------------------------------------------------
@ -180,6 +188,17 @@ sub aslr_off {
}
}
sub ulimit_stack_unlimited {
return "" if !$opt_unlimited_stack;
system("ulimit -s unlimited 2>/dev/null");
my $status = $?;
if ($status == 0) {
return "ulimit -s unlimited 2>/dev/null; exec ";
} else {
return "";
}
}
sub run {
# Run command, check errors
my $command = shift;
@ -268,7 +287,7 @@ detailed descriptions of these arguments.
=for VL_SPHINX_EXTRACT "_build/gen/args_verilator.rst"
<file.v> Verilog package, module and top module filenames
<file.v> Verilog package, module, and top module filenames
<file.c/cc/cpp> Optional C++ files to compile in
<file.a/o/so> Optional C++ files to link in
@ -360,23 +379,22 @@ detailed descriptions of these arguments.
--MP Create phony dependency targets
+notimingchecks Ignored
-O0 Disable optimizations
-O3 High performance optimizations
-O3 High-performance optimizations
-O<optimization-letter> Selectable optimizations
-o <executable> Name of final executable
--no-order-clock-delay Disable ordering clock enable assignments
--no-verilate Skip Verilation, only compile previously Verilated code
--output-split <statements> Split .cpp files into pieces
--output-split-cfuncs <statements> Split model functions
--output-split-ctrace <statements> Split tracing functions
-P Disable line numbers and blanks with -E
--pins-bv <bits> Specify types for top level ports
--pins-sc-biguint Specify types for top level ports
--pins-sc-uint Specify types for top level ports
--pins-uint8 Specify types for top level ports
--pins-bv <bits> Specify types for top-level ports
--pins-sc-biguint Specify types for top-level ports
--pins-sc-uint Specify types for top-level ports
--pins-uint8 Specify types for top-level ports
--no-pins64 Don't use uint64_t's for 33-64 bit sigs
--pipe-filter <command> Filter all input through a script
--pp-comments Show preprocessor comments with -E
--prefix <topname> Name of top level class
--prefix <topname> Name of top-level class
--private Debugging; see docs
--prof-c Compile C++ code with profiling
--prof-cfuncs Name functions for profiling
@ -408,7 +426,7 @@ detailed descriptions of these arguments.
--timescale <timescale> Sets default timescale
--timescale-override <timescale> Overrides all timescales
--top <topname> Alias of --top-module
--top-module <topname> Name of top level input module
--top-module <topname> Name of top-level input module
--trace Enable waveform creation
--trace-coverage Enable tracing of coverage
--trace-depth <levels> Depth of tracing
@ -420,12 +438,13 @@ detailed descriptions of these arguments.
--trace-threads <threads> Enable FST waveform creation on separate threads
--trace-underscore Enable tracing of _signals
-U<var> Undefine preprocessor define
--no-unlimited-stack Don't disable stack size limit
--unroll-count <loops> Tune maximum loop iterations
--unroll-stmts <stmts> Tune maximum loop body size
--unused-regexp <regexp> Tune UNUSED lint signals
-V Verbose version and config
-v <filename> Verilog library
--no-verilate Skip verilation and just compile previously Verilated code.
--no-verilate Skip verilation and just compile previously Verilated code
+verilog1995ext+<ext> Synonym for +1364-1995ext+<ext>
+verilog2001ext+<ext> Synonym for +1364-2001ext+<ext>
--version Displays program version and exits

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0301,R0902,R0913,R0914,R0912,R0915,W0621
# pylint: disable=C0103,C0114,C0115,C0116,C0123,C0209,C0301,R0902,R0913,R0914,R0912,R0915,W0621
######################################################################
import argparse

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116
# pylint: disable=C0103,C0114,C0116,C0209
######################################################################
import argparse
@ -73,7 +73,7 @@ def diff_file(a, b):
def version_from(filename):
# Return dump format
with open(filename) as fh:
with open(filename, "r", encoding="utf8") as fh:
lineno = 0
for line in fh:
if lineno > 10:
@ -86,8 +86,8 @@ def version_from(filename):
def filterf(fn1, fn2):
# Remove hex numbers before diffing
with open(fn1) as fh1:
with open(fn2, "w") as fh2:
with open(fn1, "r", encoding="utf8") as fh1:
with open(fn2, "w", encoding="utf8") as fh2:
for line in fh1:
if re.search(r' This=', line):
continue

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116,C0301,R0914,R0912,R0915,W0511,eval-used
# pylint: disable=C0103,C0114,C0116,C0209,C0301,R0914,R0912,R0915,W0511,eval-used
######################################################################
import argparse
@ -29,7 +29,7 @@ def process(filename):
def read_data(filename):
with open(filename) as fh:
with open(filename, "r", encoding="utf8") as fh:
re_thread = re.compile(r'^VLPROFTHREAD (\d+)$')
re_record = re.compile(r'^VLPROFEXEC (\S+) (\d+)(.*)$')
re_payload_mtaskBegin = re.compile(
@ -318,7 +318,7 @@ def report_cpus():
def write_vcd(filename):
print("Writing %s" % filename)
with open(filename, "w") as fh:
with open(filename, "w", encoding="utf8") as fh:
vcd = {
'values':
collections.defaultdict(lambda: {}), # {<time>}{<code>} = value

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0116,R0914,R0912,R0915,eval-used
# pylint: disable=C0103,C0114,C0116,C0209,R0914,R0912,R0915,eval-used
######################################################################
import argparse
@ -13,7 +13,7 @@ import re
def profcfunc(filename):
funcs = {}
with open(filename) as fh:
with open(filename, "r", encoding="utf8") as fh:
for line in fh:
# %time cumesec selfsec calls {stuff} name
@ -67,16 +67,15 @@ def profcfunc(filename):
groups['design'] = collections.defaultdict(lambda: 0)
groups['module'] = collections.defaultdict(lambda: 0)
for func in funcs:
pct = funcs[func]['pct']
for func, func_item in funcs.items():
pct = func_item['pct']
vfunc = func
funcarg = re.sub(r'^.*\(', '', func)
design = None
for vde in verilated_mods:
if verilated_mods[vde].match(func) or verilated_mods[vde].match(
funcarg):
for vde, vde_item in verilated_mods.items():
if vde_item.match(func) or vde_item.match(funcarg):
design = vde
break
@ -114,12 +113,12 @@ def profcfunc(filename):
groups['module']['C++'] += pct
if vfunc not in vfuncs:
vfuncs[vfunc] = funcs[func]
vfuncs[vfunc] = func_item
vfuncs[vfunc]['design'] = vdesign
else:
vfuncs[vfunc]['pct'] += funcs[func]['pct']
vfuncs[vfunc]['calls'] += funcs[func]['calls']
vfuncs[vfunc]['sec'] += funcs[func]['sec']
vfuncs[vfunc]['pct'] += func_item['pct']
vfuncs[vfunc]['calls'] += func_item['calls']
vfuncs[vfunc]['sec'] += func_item['sec']
for ftype in ['type', 'design', 'module']:
missing = 100
@ -136,9 +135,9 @@ def profcfunc(filename):
print()
design_width = 1
for func in vfuncs:
if design_width < len(vfuncs[func]['design']):
design_width = len(vfuncs[func]['design'])
for func, func_item in vfuncs.items():
if design_width < len(func_item['design']):
design_width = len(func_item['design'])
print("Verilog code profile:")
print(" These are split into three categories:")

View File

@ -62,12 +62,11 @@ Internals
---------
The Dockerfile builds Verilator and removes the tree when completed to
reduce the image size. The entrypoint is set as a wrapper script
reduce the image size. The entrypoint is a wrapper script
(``verilator-wrap.sh``). That script 1. calls Verilator, and 2. copies the
Verilated runtime files to the ``obj_dir`` or the ``-Mdir``
respectively. This allows the user to have the files to they may later
build the C++ output with the matching runtime files. The wrapper also
patches the Verilated Makefile accordingly.
There is also a hook defined that is run by docker hub via automated
builds.
A hook is also defined and run by Docker Hub via automated builds.

View File

@ -10,7 +10,7 @@
# Then 'make maintainer-dist'
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[5.002 2022-10-29],
AC_INIT([Verilator],[5.004 2022-12-14],
[https://verilator.org],
[verilator],[https://verilator.org])

View File

@ -44,15 +44,10 @@ Did you write a patch that fixes a bug?
- Have your patch include the addition of your name to `docs/CONTRIBUTORS
<CONTRIBUTORS>`__ (preferred).
- Use "git -s" as part of your commit. This adds a "signed-of-by"
attribute which will certify your contribution as described in the
`Signed-of-By convention
<https://github.com/wking/signed-off-by/blob/master/Documentation/SubmittingPatches>`__.
- Email, or post in an issue a statement that you certify your
contributions.
- In any of these cases your name will be added to `docs/CONTRIBUTORS
- In any of these cases, your name will be added to `docs/CONTRIBUTORS
<CONTRIBUTORS>`__ and you are agreeing all future contributions are
also certified.

View File

@ -11,6 +11,7 @@ Alex Chadwick
Aliaksei Chapyzhenka
Ameya Vikram Singh
Andreas Kuster
Andrew Nolte
Arkadiusz Kozdra
Chris Randall
Chuxuan Wang
@ -35,6 +36,7 @@ Glen Gibb
Graham Rushton
Guokai Chen
Gustav Svensk
G-A. Kamendje
Harald Heckmann
Howard Su
Huang Rui
@ -53,6 +55,7 @@ Jamie Iles
Jan Van Winkel
Jean Berniolles
Jeremy Bennett
Jiacheng Qian
Jiuyang Liu
John Coiner
John Demme
@ -65,6 +68,7 @@ Kamil Rakoczy
Kanad Kanhere
Keith Colbert
Kevin Kiningham
Kritik Bhimani
Krzysztof Bieganski
Kuba Ober
Larry Doolittle
@ -130,6 +134,7 @@ Victor Besyakov
William D. Jones
Wilson Snyder
Xi Zhang
Yinan Xu
Yoda Lee
Yossi Nivin
Yuri Victorovich

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0201,R0903
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0201,R0903
# -*- Python -*- See copyright, etc below
######################################################################
@ -14,7 +14,7 @@ class VlSphinxExtract:
SkipBasenames = {}
def process(self, filename):
with open(filename) as fhr:
with open(filename, "r", encoding="utf8") as fhr:
fhw = None
for line in fhr:
# =for VL_SPHINX_EXTRACT "file_to_write_to"
@ -22,7 +22,7 @@ class VlSphinxExtract:
if match:
outname = match.group(1)
print("Writing %s" % outname)
fhw = open(outname, "w")
fhw = open(outname, "w", encoding="utf8") # pylint: disable=consider-using-with
fhw.write(
".. comment: generated by vl_sphinx_extract from " +
filename + "\n")

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0112,C0114,C0115,C0116,C0301,R0903
# pylint: disable=C0112,C0114,C0115,C0116,C0209,C0301,R0903
# -*- Python -*- See copyright, etc below
######################################################################
@ -27,7 +27,7 @@ class VlSphinxFix:
def _edit(self, filename):
is_html = re.search(r'\.(html)$', filename)
with open(filename) as fhr:
with open(filename, "r", encoding="utf8") as fhr:
origfile = fhr.read()
wholefile = origfile
# Option doesn't like spaces, so we use
@ -43,7 +43,7 @@ class VlSphinxFix:
if self.debug:
print("Edit %s" % filename)
tempname = filename + ".tmp"
with open(tempname, "w") as fhw:
with open(tempname, "w", encoding="utf8") as fhw:
fhw.write(wholefile)
os.rename(tempname, filename)

View File

@ -10,7 +10,7 @@ Revision History
"Revision History" in the sidebar.
Changes are contained in the :file:`Changes` file of the distribution, and
also summarized below. To subscribe to new versions see `Verilator
also summarized below. To subscribe to new versions, see `Verilator
Announcements <https://github.com/verilator/verilator-announce>`_.
.. include:: ../_build/gen/Changes

View File

@ -21,7 +21,7 @@ import sphinx_rtd_theme # pylint: disable=wrong-import-position,
def get_vlt_version():
filename = "../../Makefile"
with open(filename) as fh:
with open(filename, "r", encoding="utf8") as fh:
for line in fh:
match = re.search(r"PACKAGE_VERSION_NUMBER *= *([a-z0-9.]+)", line)
if match:

View File

@ -51,8 +51,8 @@ also the instance of the top level instance in the design hierarchy (what
you would refer to with :code:`$root` in SystemVerilog). This meant that
all internal variables that were implemented by Verilator in the root scope
were accessible as members of the model class itself. Note there were often
many such variable due to module inlining, including :code:`/* verilator
public_flat */` items.
many such variable due to module inlining, including
:code:`/* verilator public_flat */` items.
This means that user code that accesses internal signals in the model
(likely including :code:`/* verilator public_flat */` signals, as they are
@ -406,7 +406,7 @@ accesses the above signal "readme" would be:
printf("Value of v: %d\n", v.value.integer); // Prints "readme"
}
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
Verilated::commandArgs(argc, argv);
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
const std::unique_ptr<Vour> top{new Vour{contextp.get()}};

View File

@ -11,7 +11,7 @@ Authors
When possible, please instead report bugs at `Verilator Issues
<https://verilator.org/issues>`_.
Primary author is Wilson Snyder <wsnyder@wsnyder.org>.
The primary author is Wilson Snyder <wsnyder@wsnyder.org>.
Major concepts by Paul Wasson, Duane Galbi, John Coiner, Geza Lore, Yutetsu
Takatsukasa, and Jie Xu.
@ -22,18 +22,18 @@ Contributors
Many people have provided ideas and other assistance with Verilator.
Verilator is receiving major development support from the `CHIPS Alliance
<https://chipsalliance.org>`_, `Antmicro Ltd <https://antmicro.com>`_ and
`Shunyao CAD <https://shunyaocad.com>`_.
Verilator is receiving significant development support from the `CHIPS
Alliance <https://chipsalliance.org>`_, `Antmicro Ltd
<https://antmicro.com>`_ and `Shunyao CAD <https://shunyaocad.com>`_.
Previous major corporate sponsors of Verilator, by providing significant
contributions of time or funds included include: Atmel Corporation, Cavium
contributions of time or funds include: Atmel Corporation, Cavium
Inc., Compaq Corporation, Digital Equipment Corporation, Embecosm Ltd.,
Hicamp Systems, Intel Corporation, Mindspeed Technologies Inc., MicroTune
Inc., picoChip Designs Ltd., Sun Microsystems Inc., Nauticus Networks Inc.,
SiCortex Inc, and Shunyao CAD.
The people who have contributed major functionality are: Krzysztof
The contributors of major functionality are: Krzysztof
Bieganski, Byron Bradley, Jeremy Bennett, Lane Brooks, John Coiner, Duane
Galbi, Geza Lore, Todd Strader, Stefan Wallentowitz, Paul Wasson, Jie Xu,
and Wilson Snyder. Major testers included Jeff Dutton, Jonathon Donaldson,
@ -129,27 +129,28 @@ Jeff Winston, Joshua Wise, Clifford Wolf, Tobias Wolfel, Johan Wouters,
Paul Wright, Junyi Xi, Ding Xiaoliang, Jie Xu, Mandy Xu, Yinan Xu, Luke
Yang, Amir Yazdanbakhsh, Keyi Zhang, and Xi Zhang.
Thanks to them, and all those we've missed including above, or wished to
remain anonymous.
Thanks to them, and all those we've missed mentioning above, and to those
whom have wished to remain anonymous.
Historical Origins
==================
Verilator was conceived in 1994 by Paul Wasson at the Core Logic Group at
Digital Equipment Corporation. The Verilog code that was converted to C
was then merged with a C based CPU model of the Alpha processor and
simulated in a C based environment called CCLI.
was then merged with a C-based CPU model of the Alpha processor and
simulated in a C-based environment called CCLI.
In 1995 Verilator started being used also for Multimedia and Network
Processor development inside Digital. Duane Galbi took over active
development of Verilator, and added several performance enhancements. CCLI
was still being used as the shell.
In 1995 Verilator started being used for Multimedia and Network Processor
development inside Digital. Duane Galbi took over the active development
of Verilator, and added several performance enhancements, and CCLI was
still being used as the shell.
In 1998, through the efforts of existing DECies, mainly Duane Galbi,
Digital graciously agreed to release the source code. (Subject to the code
not being resold, which is compatible with the GNU Public License.)
In 2001, Wilson Snyder took the kit, and added a SystemC mode, and called
In 2001, Wilson Snyder took the kit, added a SystemC mode, and called
it Verilator2. This was the first packaged public release.
In 2002, Wilson Snyder created Verilator 3.000 by rewriting Verilator from
@ -168,5 +169,5 @@ fork/join, delay handling, DFG performance optimizations, and other
improvements.
Currently, various language features and performance enhancements are added
as the need arises, with a focus towards getting to full Universal
Verification Methodology (UVM, IEEE 1800.2-2017) support.
as the need arises, focusing on completing Universal Verification
Methodology (UVM, IEEE 1800.2-2017) support.

View File

@ -13,7 +13,7 @@ can redistribute it and/or modify the Verilator internals under the terms
of either the GNU Lesser General Public License Version 3 or the Perl
Artistic License Version 2.0.
All Verilog and C++/SystemC code quoted within this documentation file are
released as Creative Commons Public Domain (CC0). Many example files and
All Verilog and C++/SystemC code quoted within this documentation file is
released as Creative Commons Public Domain (CC0). Many example files and
test files are likewise released under CC0 into effectively the Public
Domain as described in the files themselves.

View File

@ -10,7 +10,7 @@ associated programs.
.. option:: LD_LIBRARY_PATH
A generic Linux/OS variable specifying what directories have shared
object (.so) files. This path should include SystemC and any other
object (.so) files. This path should include SystemC and other
shared objects needed at simulation runtime.
.. option:: MAKE
@ -20,6 +20,12 @@ associated programs.
this variable to launch GNU make. If this variable is not specified,
"make" is used.
.. option:: MAKEFLAGS
Flags created by :command:`make` to pass to submakes. Verilator searches
this variable to determine if a jobserver is used; see
:vlopt:`--build-jobs`.
.. option:: OBJCACHE
Optionally specifies a caching or distribution program to place in front
@ -54,14 +60,14 @@ associated programs.
.. option:: SYSTEMC_INCLUDE
If set, specifies the directory containing the systemc.h header file. If
not specified, it will come from a default optionally specified at
If set, specifies the directory containing the systemc.h header file.
If not specified, it will come from a default optionally specified at
configure time (before Verilator was compiled), or computed from
SYSTEMC/include.
.. option:: SYSTEMC_LIBDIR
If set, specifies the directory containing the libsystemc.a library. If
If set, specifies the directory containing the libsystemc.a library. If
not specified, it will come from a default optionally specified at
configure time (before Verilator was compiled), or computed from
SYSTEMC/lib-SYSTEMC_ARCH.

View File

@ -42,7 +42,7 @@ Breaking this command down:
#. :vlopt:`-Wall` so Verilator has stronger lint warnings
enabled.
#. An finally, :command:`our.v` which is our SystemVerilog design file.
#. An finally, :command:`our.v`, which is our SystemVerilog design file.
And now we run it:
@ -57,7 +57,7 @@ And we get as output:
Hello World
- our.v:2: Verilog $finish
Really, you're better off using a Makefile to run the steps for you so when
your source changes it will automatically run all of the appropriate steps.
To aid this Verilator can create a makefile dependency file. For examples
that do this see the :file:`examples` directory in the distribution.
You're better off using a Makefile to run the steps for you, so when your
source changes, it will automatically run all of the appropriate steps. To
aid this, Verilator can create a makefile dependency file. For examples
that do this, see the :file:`examples` directory in the distribution.

View File

@ -12,7 +12,7 @@ of what this C++ code is doing, see
.. include:: example_common_install.rst
Now, let's create an example Verilog, and C++ wrapper file:
Now, let's create an example Verilog and C++ wrapper file:
.. code-block:: bash
@ -28,7 +28,7 @@ Now, let's create an example Verilog, and C++ wrapper file:
cat >sim_main.cpp <<'EOF'
#include "Vour.h"
#include "verilated.h"
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
VerilatedContext* contextp = new VerilatedContext;
contextp->commandArgs(argc, argv);
Vour* top = new Vour{contextp};
@ -39,7 +39,7 @@ Now, let's create an example Verilog, and C++ wrapper file:
}
EOF
Now we run Verilator on our little example.
Now we run Verilator on our little example;
.. code-block:: bash
@ -47,8 +47,7 @@ Now we run Verilator on our little example.
Breaking this command down:
#. :vlopt:`--cc` to get C++ output (versus e.g. SystemC
or only linting).
#. :vlopt:`--cc` to get C++ output (versus e.g., SystemC, or only linting).
#. :vlopt:`--exe`, along with our :command:`sim_main.cpp` wrapper file, so
the build will create an executable instead of only a library.
@ -58,13 +57,13 @@ Breaking this command down:
own compile rules, and run make yourself as we show in :ref:`Example
SystemC Execution`.)
#. :vlopt:`-j` `0' to Verilate using use as many CPU threads as the machine
has.
#. :vlopt:`-j 0 <-j>` to Verilate using use as many CPU threads as the
machine has.
#. :vlopt:`-Wall` so Verilator has stronger lint warnings
enabled.
#. An finally, :command:`our.v` which is our SystemVerilog design file.
#. And finally, :command:`our.v` which is our SystemVerilog design file.
Once Verilator completes we can see the generated C++ code under the
:file:`obj_dir` directory.
@ -89,7 +88,7 @@ And we get as output:
Hello World
- our.v:2: Verilog $finish
Really, you're better off using a Makefile to run the steps for you so when
your source changes it will automatically run all of the appropriate steps.
To aid this Verilator can create a makefile dependency file. For examples
that do this see the :file:`examples` directory in the distribution.
You're better off using a Makefile to run the steps for you, so when your
source changes, it will automatically run all of the appropriate steps. To
aid this, Verilator can create a makefile dependency file. For examples
that do this, see the :file:`examples` directory in the distribution.

View File

@ -1,7 +1,7 @@
.. Copyright 2003-2022 by Wilson Snyder.
.. SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
First you need Verilator installed, see :ref:`Installation`. In brief, if
First you need Verilator installed, see :ref:`Installation`. In brief, if
you installed Verilator using the package manager of your operating system,
or did a :command:`make install` to place Verilator into your default path,
you do not need anything special in your environment, and should not have

View File

@ -7,7 +7,7 @@ Examples in the Distribution
============================
See the ``examples/`` directory that is part of the distribution, and
is installed (in a OS-specific place, often in e.g.
is installed (in an OS-specific place, often in e.g.
``/usr/local/share/verilator/examples``). These examples include:
examples/make_hello_binary

View File

@ -82,10 +82,10 @@ Summary:
.. option:: +verilator+rand+reset+<value>
When a model was Verilated using :vlopt:`--x-initial unique
<--x-initial>`, sets the simulation runtime initialization technique. 0
= Reset to zeros. 1 = Reset to all-ones. 2 = Randomize. See
:ref:`Unknown States`.
When a model was Verilated using
:vlopt:`--x-initial unique <--x-initial>`, sets the simulation runtime
initialization technique. 0 = Reset to zeros. 1 = Reset to all-ones. 2
= Randomize. See :ref:`Unknown States`.
.. option:: +verilator+seed+<value>

File diff suppressed because it is too large Load Diff

View File

@ -12,8 +12,8 @@ coverage points exist on the same source code line, additional lines will
be inserted to report the additional points.
Additional Verilog-XL-style standard arguments specify the search paths
necessary to find the source code that the coverage analysis was performed
on.
necessary to find the source code on which the coverage analysis was
performed.
To filter those items to be included in coverage, you may read
logs/coverage.dat into an editor and do a M-x keep-lines to include only
@ -24,7 +24,7 @@ statement to the appropriate statement block, or see
:option:`/*verilator&32;coverage_off*/`. This will remove the coverage
points after the model is re-Verilated.
For an overview of use of verilator_coverage, see :ref:`Coverage Analysis`.
For an overview of the use of verilator_coverage, see :ref:`Coverage Analysis`.
verilator_coverage Example Usage
@ -50,25 +50,25 @@ verilator_coverage Arguments
.. option:: <filename>
Specifies the input coverage data file. Multiple filenames may be provided
to read multiple inputs. If no data file is specified, by default
to read multiple inputs. If no data file is specified, by default,
"coverage.dat" will be read.
.. option:: --annotate <output_directory>
Specifies the directory name that source files with annotated coverage data
should be written to.
Specifies the directory name to which source files with annotated coverage
data should be written.
.. option:: --annotate-all
Specifies all files should be shown. By default, only those source files
which have low coverage are written to the output directory.
with low coverage are written to the output directory.
.. option:: --annotate-min <count>
Specifies if the coverage point does not include the count number of
coverage hits, then the coverage point will be considered above the
threshold, and the coverage report will put a "%" to indicate the coverage
is not sufficient. Defaults to 10.
is insufficient. Defaults to 10.
.. option:: --help
@ -78,12 +78,12 @@ Displays a help summary, the program version, and exits.
Prints an experimental report listing the relative importance of each test
in covering all of the coverage points. The report shows "Covered" which
indicates the number of points that test covers; a test is considered to
indicates the number of points the test covers; a test is considered to
cover a point if it has a bucket count of at least 1. The "rank" column has
a higher number t indicate the test is more important, and rank 0 means the
a higher number t indicate the test is more critical, and rank 0 means the
test does not need to be run to cover the points. "RankPts" indicates the
number of coverage points this test will contribute to overall coverage if
all tests are run in the order of highest to lowest rank.
all tests are run in the order of highest to the lowest rank.
.. option:: --unlink
@ -98,8 +98,8 @@ Displays program version and exits.
Specifies the aggregate coverage results, summed across all the files,
should be written to the given filename in verilator_coverage data format.
This is useful for use in scripts to combine many coverage data files
(likely generated from random test runs) into one master coverage file.
This is useful in scripts to combine many coverage data files (likely
generated from random test runs) into one master coverage file.
.. option:: --write-info <filename.info>
@ -108,7 +108,8 @@ should be written to the given filename in :command:`lcov` .info format.
This may be used to feed into :command:`lcov` to aggregate or generate
reports.
The info format loses data compared to the Verilator coverage data format;
the info will all forms of coverage converted to line style coverage, and
if there are multiple coverage points on a single line, the minimum
coverage across those points will be used to report coverage of the line.
Converting from the Verilator coverage data format to the info format is
lossy; the info will have all forms of coverage merged line coverage, and
if there are multiple coverage points on a single line they will merge.
The minimum coverage across all merged points will be used to report
coverage of the line.

View File

@ -5,16 +5,16 @@ verilator_gantt
===============
Verilator_gantt creates a visual representation to help analyze Verilator
multithreaded simulation performance, by showing when each macro-task
starts and ends, and showing when each thread is busy or idle.
multithreaded simulation performance by showing when each macro-task
starts, ends, and when each thread is busy or idle.
For an overview of use of verilator_gantt, see :ref:`Profiling`.
For an overview of the use of verilator_gantt, see :ref:`Profiling`.
Gantt Chart VCD
---------------
Verilated_gantt creates a value change dump (VCD) format dump file which
may be viewed in a waveform viewer (e.g. C<GTKWave>):
may be viewed in a waveform viewer (e.g., C<GTKWave>):
.. figure:: figures/fig_gantt_min.png
@ -27,9 +27,8 @@ time tick of the system's high-performance counter.
Gantt Chart VCD Signals
-----------------------
In waveforms there are the following signals. In GTKWave, using a data
format of "decimal" will remove the leading zeros and make the traces
easier to read.
In waveforms, there are the following signals. In GTKWave, use "decimal"
data format to remove the leading zeros and make the traces easier to read.
evals
Increments each time when eval_step was measured to be active. This
@ -37,12 +36,12 @@ evals
eval_loop
Increments each time when the evaluation loop within eval_step was
measured to be active. For best performance there is only a single
evaluation loop within each eval_step call, that is the eval_loop
measured to be active. For best performance, there is only a single
evaluation loop within each eval_step call; that is, the eval_loop
waveform looks identical to the evals waveform.
measured_parallelism
The number of mtasks active at this time, for best performance this will
The number of mtasks active at this time, for best performance, this will
match the thread count. In GTKWave, use a data format of "analog step" to
view this signal.
@ -72,7 +71,7 @@ verilator_gantt Arguments
.. option:: <filename>
The filename to read data from, defaults to "profile_exec.dat".
The filename to read data from; the default is "profile_exec.dat".
.. option:: --help
@ -84,4 +83,4 @@ Disables creating a .vcd file.
.. option:: --vcd <filename>
Sets the output filename for vcd dump. Default is "verilator_gantt.vcd".
Sets the output filename for vcd dump; the default is "verilator_gantt.vcd".

View File

@ -6,14 +6,14 @@ verilator_profcfunc
Verilator_profcfunc reads a profile report created by gprof. The names of
the functions are then transformed, assuming the user used Verilator's
--prof-cfuncs, and a report printed showing the percentage of time, etc, in
each Verilog block.
--prof-cfuncs, and a report printed showing the percentage of the time,
etc., in each Verilog block.
Due to rounding errors in gprof reports, the input report's percentages may
not total to 100%. In the verilator_profcfunc report this will get
not total 100%. In the verilator_profcfunc report this will get
reported as a rounding error.
For an overview of use of verilator_profcfunc, see :ref:`Profiling`.
For an overview of the use of verilator_profcfunc, see :ref:`Profiling`.
verilator_profcfunc Arguments
-----------------------------

View File

@ -12,19 +12,25 @@ or "`ifdef`"'s may break other tools.
.. option:: `__FILE__
The :option:`\`__FILE__` define expands to the current filename as a
string, like C++'s __FILE__. This Verilator feature added in 2006 was
incorporated into the IEEE 1800-2009 standard.
string, like C++'s __FILE__. This Verilator feature, added in 2006, was
incorporated into IEEE 1800-2009.
.. option:: `__LINE__
The :option:`\`__LINE__` define expands to the current filename as a
string, like C++'s __LINE__. This Verilator feature added in 2006 was
incorporated into the IEEE 1800-2009 standard.
incorporated into IEEE 1800-2009.
.. option:: `error [string]
This will report an error when encountered, like C++'s #error.
.. option:: """ [string] """
A triple-quoted block specifies a string that may include newlines and
single quotes. This extension is experimental and may be removed
without deprecation.
.. option:: $c([string], ...);
The string will be embedded directly in the output C++ code at the point
@ -45,24 +51,24 @@ or "`ifdef`"'s may break other tools.
rather than hard-coding variable names in the string
:code:`$c("func(a)")`, instead pass the variable as an expression
::code:`$c("func(",a,")")`. This will allow the call to work inside
Verilog functions where the variable is flattened out, and also enable
other optimizations.
Verilog functions where the variable is flattened out and enable other
optimizations.
Verilator does not use any text inside the quotes for
ordering/scheduling. If you need the $c to be called at a specific
time, e.g. when a variable changes, then the $c must be under an
appropriate sensitivity statement, e.g. :code:`always @(posedge clk)
$c("func()")` to call it on every edge, or e.g. :code:`always @*
c("func(",a,")")` to call it when :code:`a` changes (the latter working
because :code:`a` is outside the quotes).
time, e.g., when a variable changes, then the $c must be under an
appropriate sensitivity statement, e.g.,
:code:`always @(posedge clk) $c("func()")` to call it on every edge, or,
e.g., :code:`always @* c("func(",a,")")` to call it when :code:`a`
changes (the latter working because :code:`a` is outside the quotes).
If you will be reading or writing any Verilog variables inside the C++
functions, the Verilog signals must be declared with
:option:`/*verilator&32;public*/` metacomments.
You may also append an arbitrary number to $c, generally the width of
the output; :code:`signal_32_bits = $c32("...");`. This allows for
compatibility with other simulators which require a differently named
You may also append a number to $c, which specifies the bit width of
the output, e.g., :code:`signal_32_bits = $c32("...");`. This allows for
compatibility with other simulators, which require a differently named
PLI function name for each different output width.
.. option:: $display, $write, $fdisplay, $fwrite, $sformat, $swrite
@ -70,61 +76,71 @@ or "`ifdef`"'s may break other tools.
Format arguments may use C fprintf sizes after the % escape. Per the
Verilog standard, %x prints a number with the natural width, and %0x
prints a number with minimum width. Verilator extends this so %5x
prints 5 digits per the C standard (this is unspecified in Verilog, but
was incorporated into the 1800-2009).
prints 5 digits per the C standard. This extension was standardized into
1800-2009.
.. option:: $timeprecision
Returns the timeprecision of the model as an integer. This extension is
experimental and may be removed without deprecation.
.. option:: $timeunit
Returns the timeunit of the current module as an integer. This
extension is experimental and may be removed without deprecation.
.. option:: `coverage_block_off
Specifies the entire begin/end block should be ignored for coverage
analysis. Must be inside a code block, e.g. within a begin/end pair.
analysis. Must be inside a code block, e.g., within a begin/end pair.
Same as :option:`coverage_block_off` in :ref:`Configuration Files`.
.. option:: `systemc_header
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the output .h file's header. Must be placed as a module
item, e.g. directly inside a module/endmodule pair. Despite the name of
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_ctor
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class constructor. Must be placed as a module
item, e.g. directly inside a module/endmodule pair. Despite the name of
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_dtor
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class destructor. Must be placed as a module
item, e.g. directly inside a module/endmodule pair. Despite the name of
item, e.g., directly inside a module/endmodule pair. Despite the name of
this macro, this also works in pure C++ code.
.. option:: `systemc_interface
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the C++ class interface. Must be placed as a module item,
e.g. directly inside a module/endmodule pair. Despite the name of this
e.g., directly inside a module/endmodule pair. Despite the name of this
macro, this also works in pure C++ code.
.. option:: `systemc_imp_header
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into the header of all files for this C++ class implementation.
Must be placed as a module item, e.g. directly inside a module/endmodule
Must be placed as a module item, e.g., directly inside a module/endmodule
pair. Despite the name of this macro, this also works in pure C++ code.
.. option:: `systemc_implementation
Take remaining text up to the next :option:`\`verilog` or
Take the remaining text up to the next :option:`\`verilog` or
:option:`\`systemc_... <\`systemc_header>` mode switch and place it
verbatim into a single file of the C++ class implementation. Must be
placed as a module item, e.g. directly inside a module/endmodule
placed as a module item, e.g., directly inside a module/endmodule
pair. Despite the name of this macro, this also works in pure C++ code.
If you will be reading or writing any Verilog variables in the C++
@ -134,7 +150,7 @@ or "`ifdef`"'s may break other tools.
.. option:: `SYSTEMVERILOG
The SYSTEMVERILOG, SV_COV_START and related standard defines are set by
The SYSTEMVERILOG, SV_COV_START, and related standard defines are set by
default when :vlopt:`--language <--language>` is "1800-\*".
.. option:: `VERILATOR
@ -148,13 +164,13 @@ or "`ifdef`"'s may break other tools.
.. option:: `verilator_config
Take remaining text up to the next :option:`\`verilog` mode switch and
Take the remaining text up to the next :option:`\`verilog` mode switch and
treat it as Verilator configuration commands. See :ref:`Configuration Files`.
.. option:: `VERILATOR_TIMING
The VERILATOR_TIMING define is set when :vlopt:`--timing` is used to
allow an "\`ifdef" of code dependent on this feature. Note this define
allow an "\`ifdef" of code dependent on this feature. Note that this define
is not affected by the :option:`timing_off` configuration file option
nor timing metacomments.
@ -169,10 +185,10 @@ or "`ifdef`"'s may break other tools.
Deprecated and has no effect (ignored).
In versions prior to 5.000:
In versions before 5.000:
Used after a signal declaration to indicate the signal is used to gate a
clock, and the user takes responsibility for insuring there are no races
clock, and the user is responsible for ensuring there are no races
related to it. (Typically by adding a latch, and running static timing
analysis.) For example:
@ -193,7 +209,7 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;no_clocker*/
Specifies that the signal is used as clock or not. See :vlopt:`--clk`.
Specifies whether the signal is used as clock or not. See :vlopt:`--clk`.
Same as :option:`clocker` and :option:`no_clocker` in configuration
files.
@ -207,12 +223,12 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;coverage_off*/
Specifies that following lines of code should have coverage disabled.
Specifies that that following lines of code should have coverage disabled.
Often used to ignore an entire module for coverage analysis purposes.
.. option:: /*verilator&32;coverage_on*/
Specifies that following lines of code should have coverage re-enabled
Specifies that that following lines of code should have coverage re-enabled
(if appropriate :vlopt:`--coverage` flags are passed) after being
disabled earlier with :option:`/*verilator&32;coverage_off*/`.
@ -220,7 +236,7 @@ or "`ifdef`"'s may break other tools.
Specifies that the signal (net or variable) should be made forceable from
C++ code by generating public `<signame>__VforceEn` and
`<signame>__VforceVal` signals The force control signals are created as
`<signame>__VforceVal` signals. The force control signals are created as
:option:`public_flat` signals.
To force a marked signal from C++, set the corresponding `__VforceVal`
@ -256,10 +272,10 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;isolate_assignments*/
Used after a signal declaration to indicate the assignments to this
signal in any blocks should be isolated into new blocks. When there is
a large combinatorial block that is resulting in an ``UNOPTFLAT``
warning, attaching this to the signal causing a false loop may clear up
the problem.
signal in any blocks should be isolated into new blocks. When large
combinatorial block results in a :option:`UNOPTFLAT` warning, attaching
this to the signal that was causing a false loop may work around the
warning.
IE, with the following:
@ -313,7 +329,7 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;lint_save*/
Push the current state of what lint messages are turned on or turned off
Push the current state of what lint messages are turned on or off
to a stack. Later meta-comments may then lint_on or lint_off specific
messages, then return to the earlier message state by using
:code:`/*verilator&32;lint_restore*/`. For example:
@ -325,8 +341,8 @@ or "`ifdef`"'s may break other tools.
... // code needing WIDTH turned off
// verilator lint_restore
If WIDTH was on before the lint_off, it will now be restored to on, and
if it was off before the lint_off it will remain off.
If WIDTH was on before the lint_off, it would now be restored to on, and
if it was off before the lint_off it would remain off.
.. option:: /*verilator&32;no_inline_module*/
@ -370,13 +386,12 @@ or "`ifdef`"'s may break other tools.
Used after an input, output, register, or wire declaration to indicate
the signal should be declared so that C code may read or write the value
of the signal. This will also declare this module public, otherwise use
of the signal. This will also declare this module public; otherwise, use
:code:`/*verilator&32;public_flat*/`.
Instead of using public variables, consider instead making a DPI or
public function that accesses the variable. This is nicer as it
provides an obvious entry point that is also compatible across
simulators.
Instead of using public variables, consider making a DPI or public
function that accesses the variable. This is nicer as it provides an
obvious entry point compatible across simulators.
Same as :option:`public` configuration file option.
@ -386,7 +401,7 @@ or "`ifdef`"'s may break other tools.
indicate the function or task should be made into a C++ function, public
to outside callers. Public tasks will be declared as a void C++
function, public functions will get the appropriate non-void (bool,
uint32_t, etc) return type. Any input arguments will become C++
uint32_t, etc.) return type. Any input arguments will become C++
arguments to the function. Any output arguments will become C++
reference arguments. Any local registers/integers will become function
automatic variables on the stack.
@ -424,10 +439,10 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;public_flat_rw @(<edge_list>)*/ (on variable)
Used after an input, output, register, or wire declaration to indicate
the signal should be declared public_flat_rd (see above), and also
writable, where writes should be considered to have the timing specified
by the given sensitivity edge list. Set for all variables, ports and
wires using the :vlopt:`--public-flat-rw` option.
the signal should be declared public_flat_rd (see above), and writable,
where writes should be considered to have the timing specified by the
given sensitivity edge list. Use of this is implied when using the
:vlopt:`--public-flat-rw` option.
Same as :option:`public_flat_rw` configuration file option.
@ -436,8 +451,8 @@ or "`ifdef`"'s may break other tools.
Used after a module statement to indicate the module should not be
inlined (unless specifically requested) so that C code may access the
module. Verilator automatically sets this attribute when the module
contains any public signals or \`systemc_ directives. Also set for all
modules when using the :vlopt:`--public` option.
contains public signals or \`systemc_ directives. Use of this is
implied when using the :vlopt:`--public` option.
Same as :option:`public` configuration file option.
@ -446,27 +461,26 @@ or "`ifdef`"'s may break other tools.
Deprecated and ignored. Previously used after an input declaration to
indicate the signal should be declared in SystemC as a sc_clock instead
of a bool. This was needed in SystemC 1.1 and 1.2 only; versions 2.0
and later do not require clock pins to be sc_clocks and this is no
and later do not require clock pins to be sc_clocks, and this is no
longer needed and is ignored.
.. option:: /*verilator&32;sc_bv*/
Used after a port declaration. It sets the port to be of
:code:`sc_bv<{width}>` type, instead of bool, uint32_t or uint64_t.
:code:`sc_bv<{width}>` type, instead of bool, uint32_t, or uint64_t.
This may be useful if the port width is parameterized and the
instantiating C++ code wants to always have a sc_bv so it can accept any
width. In general you should avoid using this attribute when not
necessary as with increasing usage of sc_bv the performance decreases
significantly.
instantiating C++ code always wants to have a sc_bv accept any width.
In general, you should avoid using this attribute when unnecessary, as
the performance decreases significantly with increasing usage of sc_bv.
Same as :option:`sc_bv` configuration file option.
.. option:: /*verilator&32;sformat*/
Attached to the final argument of type "input string" of a function or
task to indicate the function or task should pass all remaining
task to indicate that the function or task should pass all remaining
arguments through $sformatf. This allows creation of DPI functions with
$display like behavior. See the :file:`test_regress/t/t_dpi_display.v`
$display-like behavior. See the :file:`test_regress/t/t_dpi_display.v`
file for an example.
Same as :option:`sformat` configuration file option.
@ -476,7 +490,7 @@ or "`ifdef`"'s may break other tools.
Attached to a variable or a net declaration to break the variable into
multiple pieces typically to resolve ``UNOPTFLAT`` performance issues.
Typically the variables to attach this to are recommended by Verilator
itself, see :option:`UNOPTFLAT`.
itself; see :option:`UNOPTFLAT`.
For example, Verilator will internally convert a variable with the
metacomment such as:
@ -493,12 +507,12 @@ or "`ifdef`"'s may break other tools.
logic [7:0] x__BRA__1__KET__ /*verilator split_var*/;
Note that the generated packed variables retain the split_var
metacomment because they may be split into further smaller pieces
according to the access patterns.
metacomment because they may be split into smaller pieces according to
the access patterns.
This only supports unpacked arrays, packed arrays, and packed structs of
integer types (reg, logic, bit, byte, int...); otherwise if a split was
requested but cannot occur a SPLITVAR warning is issued. Splitting
integer types (reg, logic, bit, byte, int...); otherwise, if a split was
requested but cannot occur, a SPLITVAR warning is issued. Splitting
large arrays may slow down the Verilation speed, so use this only on
variables that require it.
@ -535,12 +549,22 @@ or "`ifdef`"'s may break other tools.
.. option:: /*verilator&32;tracing_off*/
Disable waveform tracing for all future signals that are declared in
this module, or instances below this module. Often this is placed just
after a primitive's module statement, so that the entire module and
instances below it are not traced.
Disable waveform tracing for all future signals declared in this module,
or instances below this module. Often this is placed just after a
primitive's module statement, so that the entire module and instances
below it are not traced.
.. option:: /*verilator&32;tracing_on*/
Re-enable waveform tracing for all future signals or instances that are
declared.
.. option:: $stacktrace
Called as a task, print a stack trace. Called as a function, return a
string with a stack trace. This relies on the C++ system trace, which
may give less meaningful results if the model is not compiled with debug
symbols. Also, the data represents the C++ stack; the SystemVerilog
functions/tasks involved may be renamed and/or inlined before becoming
the C++ functions that may be visible in the stack trace. This
extension is experimental and may be removed without deprecation.

View File

@ -14,8 +14,8 @@ Can I contribute?
"""""""""""""""""
Please contribute! Just submit a pull request, or raise an issue to
discuss if looking for something to help on. For more information see our
contributor agreement.
discuss if you are looking for something to help on. For more information
see our contributor agreement.
How widely is Verilator used?
@ -24,7 +24,7 @@ How widely is Verilator used?
Verilator is used by many of the largest silicon design companies, large
organizations such as CERN, and even by college student projects.
Verilator is one of the "big 4" simulators, meaning one of the 4 main
Verilator is one of the "big 4" simulators, meaning one of the four leading
SystemVerilog simulators available, namely the closed-source products Synopsys
VCS (tm), Mentor Questa/ModelSim (tm), Cadence
Xcelium/Incisive/NC-Verilog/NC-Sim (tm), and the open-source Verilator.
@ -35,8 +35,8 @@ simulators.
Does Verilator run under Windows?
"""""""""""""""""""""""""""""""""
Yes, ideally run Ubuntu under Windows Subsystem for Linux (WSL2).
Alternatively use Cygwin, though this tends to be slower and is not
Yes, ideally, run Ubuntu under Windows Subsystem for Linux (WSL2).
Alternatively, use Cygwin, though this tends to be slower and is not
regularly tested. Verilated output also compiles under Microsoft Visual
C++, but this is also not regularly tested.
@ -58,14 +58,14 @@ How can it be faster than (name-a-big-3-closed-source-simulator)?
Generally, the implied part of the question is "... with all of the
manpower they can put into developing it."
Most simulators have to be compliant with the complete IEEE 1364 (Verilog)
and IEEE 1800 (SystemVerilog) standards, meaning they have to be event
driven. This prevents them from being able to reorder blocks and make
netlist-style optimizations, which are where most of the gains come from.
Most simulators must comply with the complete IEEE 1364 (Verilog) and IEEE
1800 (SystemVerilog) standards, meaning they have to be event-driven. This
prevents them from being able to reorder blocks and make netlist-style
optimizations, which are where most of the gains come from.
You should not be scared by non-compliance. Your synthesis tool isn't
compliant with the whole standard to start with, so your simulator need not
be either. Verilator is closer to the synthesis interpretation, so this is
be either. Verilator is closer to the synthesis interpretation, which is
a good thing for getting working silicon.
@ -81,17 +81,17 @@ the licenses for details.
Some examples:
* Any SystemVerilog or other input fed into Verilator remain your own.
* Any SystemVerilog or other input fed into Verilator remains your own.
* Any of your VPI/DPI C++ routines that Verilator calls remain your own.
* Any of your main() C++ code that calls into Verilator remain your own.
* Any of your main() C++ code that calls into Verilator remains your own.
* If you change Verilator itself, for example changing or adding a file
* If you change Verilator itself, for example, changing or adding a file
under the src/ directory in the repository, you must make the source code
available under the GNU Lesser Public License.
* If you change a header Verilator provides, for example under include/ in
* If you change a header Verilator provides, for example, under include/ in
the repository, you must make the source code available under the GNU
Lesser Public License.
@ -101,9 +101,9 @@ license also allows you to modify Verilator for internal use without
distributing the modified version. But please contribute back to the
community!
Under both license you can offer a commercial product that is based on
Verilator either directly or embedded within. However under both licenses,
any changes you make to Verilator for such a product must be open sourced.
Under both licenses, you can offer a commercial product based on
Verilator directly or embedded within. However, under both licenses,
any changes you make to Verilator for such a product must be open-sourced.
As is standard with Open Source, contributions back to Verilator will be
placed under the Verilator copyright and LGPL/Artistic license. Small test
@ -114,11 +114,11 @@ and large tests under the LGPL/Artistic, unless requested otherwise.
Why is running Verilator (to create a model) so slow?
"""""""""""""""""""""""""""""""""""""""""""""""""""""
Verilator may require more memory than the resulting simulator will
require, as Verilator internally creates all of the state of the resulting
generated simulator in order to optimize it. If it takes more than a few
Verilator may require more memory than the resulting simulation,
as Verilator internally creates all of the state of the resulting
generated simulator to optimize it. If it takes more than a few
minutes or so (and you're not using :vlopt:`--debug` since debug mode is
disk bound), see if your machine is paging; most likely you need to run it
disk bound), see if your machine is paging; most likely, you need to run it
on a machine with more memory. Very large designs are known to have topped
64 GB resident set size. Alternatively, see :ref:`Hierarchical Verilation`.
@ -128,14 +128,14 @@ How do I generate waveforms (traces) in C++?
See also the next question for tracing in SystemC mode.
A. Pass the :vlopt:`--trace` option to Verilator, and in your top level C
A. Pass the :vlopt:`--trace` option to Verilator, and in your top-level C
code, call ``Verilated::traceEverOn(true)``. Then you may use
``$dumpfile`` and ``$dumpvars`` to enable traces, same as with any
``$dumpfile`` and ``$dumpvars`` to enable traces, the same as with any
Verilog simulator. See ``examples/make_tracing_c`` in the distribution.
B. Or, for finer-grained control, or C++ files with multiple Verilated
modules you may also create the trace purely from C++. Create a
VerilatedVcdC object, and in your main loop right after ``eval()`` call
modules, you may also create the trace purely from C++. Create a
VerilatedVcdC object, and in your main loop, right after ``eval()`` call
``trace_object->dump(contextp->time())`` every time step, and finally
call ``trace_object->close()``.
@ -144,7 +144,7 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated
#include "verilated_vcd_c.h"
...
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
const std::unique_ptr<VerilatedContext> contextp{new VerilatedContext};
...
Verilated::traceEverOn(true);
@ -163,8 +163,8 @@ B. Or, for finer-grained control, or C++ files with multiple Verilated
You also need to compile :file:`verilated_vcd_c.cpp` and add it to your
link, preferably by adding the dependencies in your Makefile's
:code:`$(VK_GLOBAL_OBJS)` link rule. This is done for you if using the
Verilator :vlopt:`--exe` option.
:code:`$(VK_GLOBAL_OBJS)` link rule. This is done for you if you are using
the Verilator :vlopt:`--binary` or :vlopt:`--exe` option.
you can call :code:`trace_object->trace()` on multiple Verilated objects
with the same trace file if you want all data to land in the same output
@ -174,22 +174,22 @@ file.
How do I generate waveforms (traces) in SystemC?
""""""""""""""""""""""""""""""""""""""""""""""""
A. Pass the :vlopt:`--trace` option to Verilator, and in your top level
A. Pass the :vlopt:`--trace` option to Verilator, and in your top-level
:code:`sc_main()`, call :code:`Verilated::traceEverOn(true)`. Then you
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, same as
with any Verilog simulator, see the non-SystemC example in
may use :code:`$dumpfile` and code:`$dumpvars` to enable traces, as
with any Verilog simulator; see the non-SystemC example in
:file:`examples/make_tracing_c`. This will trace only the module
containing the :code:`$dumpvar`.
B. Or, you may create a trace purely from SystemC, which may trace all
Verilated designs in the SystemC model. Create a VerilatedVcdSc object
as you would create a normal SystemC trace file. For an example, see
as you would create a standard SystemC trace file. For an example, see
the call to ``VerilatedVcdSc`` in the
:file:`examples/make_tracing_sc/sc_main.cpp` file of the distribution,
and below.
C. Alternatively you may use the C++ trace mechanism described in the
previous question, note the timescale and timeprecision will be
C. Alternatively, you may use the C++ trace mechanism described in the
previous question; note that the timescale and timeprecision will be
inherited from your SystemC settings.
.. code-block:: C++
@ -197,7 +197,7 @@ C. Alternatively you may use the C++ trace mechanism described in the
#include "verilated_vcd_sc.h"
...
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
...
Verilated::traceEverOn(true);
VerilatedVcdSc* tfp = new VerilatedVcdSc;
@ -214,13 +214,14 @@ C. Alternatively you may use the C++ trace mechanism described in the
You also need to compile :file:`verilated_vcd_sc.cpp` and
:file:`verilated_vcd_c.cpp` and add them to your link, preferably by adding
the dependencies in your Makefile's :code:`$(VK_GLOBAL_OBJS)` link rule.
This is done for you if using the Verilator :vlopt:`--exe` option.
This is done for you if you are using the Verilator :vlopt:`--binary` or
:vlopt:`--exe` option.
You can call :code:`->trace()` on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
When using SystemC 2.3, the SystemC library must have been built with the
experimental simulation phase callback based tracing disabled. This is
experimental simulation phase callback-based tracing disabled. This is
disabled by default when building SystemC with its configure based build
system, but when building SystemC with CMake, you must pass
``-DENABLE_PHASE_CALLBACKS_TRACING=OFF`` to disable this feature.
@ -242,7 +243,7 @@ Or, in C++ change the include described in the VCD example above:
VerilatedFstC* tfp = new VerilatedFstC;
Or, in SystemC change the include described in the VCD example above:
Or, in SystemC, change the include described in the VCD example above:
.. code-block:: C++
@ -250,17 +251,16 @@ Or, in SystemC change the include described in the VCD example above:
VerilatedFstC* tfp = new VerilatedFstSc;
Note that currently supporting both FST and VCD in a single simulation is
impossible, but such requirement should be rare. You can however ifdef
around the trace format in your C++ main loop, and select VCD or FST at
build time, should you require.
Currently, supporting FST and VCD in a single simulation is impossible, but
such requirement should be rare. You can however ifdef around the trace
format in your C++ main loop, and select VCD or FST at compile time.
How do I view waveforms (aka dumps or traces)?
""""""""""""""""""""""""""""""""""""""""""""""
Verilator creates standard VCD (Value Change Dump) and FST files. VCD
files are viewable with the open source GTKWave (recommended) or Dinotrace
files are viewable with the open-source GTKWave (recommended), or Dinotrace
(legacy) programs, or any of the many closed-source offerings; FST is
supported only by GTKWave.
@ -273,20 +273,20 @@ A. Instead of calling ``VerilatedVcdC->open`` or ``$dumpvars`` at the
tracing to begin.
B. Add the :option:`/*verilator&32;tracing_off*/` metacomment to any very
low level modules you never want to trace (such as perhaps library
low-level modules you never want to trace (such as perhaps library
cells).
C. Use the :vlopt:`--trace-depth` option to limit the depth of tracing, for
example :vlopt:`--trace-depth 1 <--trace-depth>` to see only the top
level signals.
C. Use the :vlopt:`--trace-depth` option to limit the tracing depth, for
example :vlopt:`--trace-depth 1 <--trace-depth>` to see only the
top-level signals.
D. You can also consider using FST tracing instead of VCD. FST dumps are a
fraction of the size of the equivalent VCD. FST tracing can be slower
than VCD tracing, but it might be the only option if the VCD file size
is prohibitively large.
E. Be sure you write your trace files to a local solid-state drive, instead
of to a network drive. Network drives are generally far slower.
E. Write your trace files to a machine-local solid-state drive instead of a
network drive. Network drives are generally far slower.
Where is the translate_off command? (How do I ignore a construct?)
@ -313,7 +313,7 @@ Why do I get "unexpected 'do'" or "unexpected 'bit'" errors?
The words \ ``do``\ , \ ``bit``\ , \ ``ref``\ , \ ``return``\ , and others
are reserved keywords in SystemVerilog. Older Verilog code might use these
as identifiers. You should change your code to not use them to ensure it
as identifiers, and you should change your code to not use them to ensure it
works with newer tools. Alternatively, surround them by the Verilog
2005/SystemVerilog begin_keywords pragma to indicate Verilog 2001 code.
@ -325,7 +325,7 @@ works with newer tools. Alternatively, surround them by the Verilog
`end_keywords
If you want the whole design to be parsed as Verilog 2001, see the
If you want the whole design parsed as Verilog 2001, see the
:vlopt:`--default-language` option.
@ -342,11 +342,11 @@ Why do I get "undefined reference to sc_time_stamp()?
In Verilator 4.200 and later, using the timeInc function is recommended
instead. See the :ref:`Connecting to C++` examples. Some linkers (MSVC++)
still require :code:`sc_time_stamp()` to be defined, either define this
still require :code:`sc_time_stamp()` to be defined; either define this
with :code:`double sc_time_stamp() { return 0; }` or compile the Verilated
code with :code:`-CFLAGS -DVL_TIME_CONTEXT`.
Prior to Verilator 4.200, the :code:`sc_time_stamp()` function needs to be
Before Verilator 4.200, the :code:`sc_time_stamp()` function needs to be
defined in C++ (non SystemC) to return the current simulation time.
@ -369,17 +369,17 @@ also use the "import DPI" SystemVerilog feature to call C code (see the
chapter above). There is also limited VPI access to public signals.
If you want something more complex, since Verilator emits standard C++
code, you can write your own C++ routines that can access and modify signal
code, you can write C++ routines that can access and modify signal
values without needing any PLI interface code, and call it with
$c("{any_c++_statement}").
See the :ref:`Connecting` section.
How do I make a Verilog module that contain a C++ object?
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""
How do I make a Verilog module that contains a C++ object?
""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
You need to add the object to the structure that Verilator creates, then
You need to add the object to the structure Verilator creates, then
use $c to call a method inside your object. The
:file:`test_regress/t/t_extend_class` files in the distribution show an
example of how to do this.
@ -388,9 +388,9 @@ example of how to do this.
How do I get faster build times?
""""""""""""""""""""""""""""""""
* When running make, pass the make variable VM_PARALLEL_BUILDS=1 so that
* When running make, pass the make variable VM_PARALLEL_BUILDS=1, so that
builds occur in parallel. Note this is now set by default if an output
file was large enough to be split due to the :vlopt:`--output-split`
file is large enough to be split due to the :vlopt:`--output-split`
option.
* Verilator emits any infrequently executed "cold" routines into separate
@ -401,17 +401,17 @@ How do I get faster build times?
* Use a recent compiler. Newer compilers tend to be faster.
* Compile in parallel on many machines and use caching; see the web for the
ccache, distcc and icecream packages. ccache will skip GCC runs between
ccache, distcc, and icecream packages. ccache will skip GCC runs between
identical source builds, even across different users. If ccache was
installed when Verilator was built it is used, or see OBJCACHE
installed when Verilator was built, it is used, or see OBJCACHE
environment variable to override this. Also see the
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`
:vlopt:`--output-split` option and :ref: `Profiling ccache efficiency`.
* To reduce the compile time of classes that use a Verilated module (e.g. a
* To reduce the compile time of classes that use a Verilated module (e.g., a
top CPP file) you may wish to add a
:option:`/*verilator&32;no_inline_module*/` metacomment to your top level
:option:`/*verilator&32;no_inline_module*/` metacomment to your top-level
module. This will decrease the amount of code in the model's Verilated
class, improving compile times of any instantiating top level C++ code,
class, improving compile times of any instantiating top-level C++ code,
at a relatively small cost of execution performance.
* Use :ref:`hierarchical verilation`.
@ -421,7 +421,7 @@ Why do so many files need to recompile when I add a signal?
"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""
Adding a new signal requires the symbol table to be recompiled. Verilator
uses one large symbol table, as that results in 2-3 less assembly
uses one large symbol table, resulting in 2-3 fewer assembly
instructions for each signal access. This makes the execution time 10-15%
faster, but can result in more compilations when something changes.
@ -449,8 +449,8 @@ How do I access signals in C?
The best thing to do is to make a SystemVerilog "export DPI" task or
function that accesses that signal, as described in the DPI chapter in the
manual and DPI tutorials on the web. This will allow Verilator to better
optimize the model and should be portable across simulators.
manual and DPI tutorials on the web. This will allow Verilator to
optimize the model better and should be portable across simulators.
If you really want raw access to the signals, declare the signals you will
be accessing with a :option:`/*verilator&32;public*/` metacomment before
@ -459,17 +459,17 @@ the signal, as you would any other member variable.
Signals are the smallest of 8-bit unsigned chars (equivalent to uint8_t),
16-bit unsigned shorts (uint16_t), 32-bit unsigned longs (uint32_t), or
64-bit unsigned long longs (uint64_t) that fits the width of the signal.
64-bit unsigned long longs (uint64_t) that fit the width of the signal.
Generally, you can use just uint32_t's for 1 to 32 bits, or uint64_t for
1 to 64 bits, and the compiler will properly up-convert smaller entities.
Note even signed ports are declared as unsigned; you must sign extend
Note that even signed ports are declared as unsigned; you must sign extend
yourself to the appropriate signal width.
Signals wider than 64 bits are stored as an array of 32-bit uint32_t's.
Thus to read bits 31:0, access signal[0], and for bits 63:32, access
signal[1]. Unused bits (for example bit numbers 65-96 of a 65-bit vector)
will always be zero. If you change the value you must make sure to pack
zeros in the unused bits or core-dumps may result, because Verilator strips
Thus, to read bits 31:0, access signal[0], and for bits 63:32, access
signal[1]. Unused bits (for example, bit numbers 65-96 of a 65-bit vector)
will always be zero. If you change the value, you must pack
zeros in the unused bits, or core-dumps may result because Verilator strips
array bound checks where it believes them to be unnecessary to improve
performance.
@ -490,16 +490,16 @@ From the sc_main.cpp file, you'd then:
In this example, clk is a bool you can read or set as any other variable.
The value of normal signals may be set, though clocks shouldn't be changed
by your code or you'll get strange results.
The value of normal signals may be set, though your code shouldn't change
clocks, or you'll get strange results.
Should a module be in Verilog or SystemC?
"""""""""""""""""""""""""""""""""""""""""
Sometimes there is a block that only interconnects instances, and have a
choice as to if you write it in Verilog or SystemC. Everything else being
equal, best performance is when Verilator sees all of the design. So, look
Sometimes there is a block that only interconnects instances, and you have a
choice if you write it in Verilog or SystemC. Everything else being
equal, the best performance is when Verilator sees all of the design. So, look
at the hierarchy of your design, labeling instances as to if they are
SystemC or Verilog. Then:
@ -510,6 +510,6 @@ SystemC or Verilog. Then:
* A module with only Verilog instances below can be either, but for best
performance should be Verilog. (The exception is if you have a design
that is instantiated many times; in this case Verilating one of the lower
that is instantiated many times; in this case, Verilating one of the lower
modules and instantiating that Verilated instances multiple times into a
SystemC module *may* be faster.)

View File

@ -59,13 +59,13 @@ For --cc/--sc, it creates:
* - *{prefix}*\ .cpp
- Model C++ file
* - *{prefix}*\ ___024root.h
- Top level (SystemVerilog $root) internal header file
- Top-level internal header file (from SystemVerilog $root)
* - *{prefix}*\ ___024root.cpp
- Top level (SystemVerilog $root) internal C++ file
- Top-level internal C++ file (from SystemVerilog $root)
* - *{prefix}*\ ___024root\ *{__n}*\ .cpp
- Additional top level internal C++ files
- Additional top-level internal C++ files
* - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
- Additional top level internal C++ files (hashed to reduce build times)
- Additional top-level internal C++ files (hashed to reduce build times)
* - *{prefix}*\ ___024root__Slow\ *{__n}*\ .cpp
- Infrequent cold routines
* - *{prefix}*\ ___024root\ *{__DepSet_hash__n}*\ .cpp
@ -106,7 +106,7 @@ For --hierarchy mode, it creates:
* - *{prefix}*\ __hier.dir
- Directory to store .dot, .vpp, .tree of top module (from --hierarchy)
In certain debug and other modes, it also creates:
In specific debug and other modes, it also creates:
.. list-table::

View File

@ -16,14 +16,14 @@ Package Manager Quick Install
Using a distribution's package manager is the easiest way to get
started. (Note packages are unlikely to have the most recent version, so
:ref:`Git Install`, might be a better alternative.) To install as a
:ref:`Git Install` might be a better alternative.) To install as a
package:
::
apt-get install verilator # On Ubuntu
For other distributions refer to `Repology Verilator Distro Packages
For other distributions, refer to `Repology Verilator Distro Packages
<https://repology.org/project/verilator>`__.
.. _Git Install:
@ -31,8 +31,8 @@ For other distributions refer to `Repology Verilator Distro Packages
Git Quick Install
=================
Installing Verilator from Git provides the most flexibility. For additional
options and details see :ref:`Detailed Build Instructions` below.
Installing Verilator from Git provides the most flexibility; for additional
options and details, see :ref:`Detailed Build Instructions` below.
In brief, to install from git:
@ -68,7 +68,7 @@ In brief, to install from git:
Detailed Build Instructions
===========================
This section describes details of the build process, and assumes you are
This section describes details of the build process and assumes you are
building from Git. For using a pre-built binary for your Linux
distribution, see instead :ref:`Package Manager Quick Install`.
@ -77,11 +77,11 @@ OS Requirements
---------------
Verilator is developed and has primary testing on Ubuntu, with additional
testing on FreeBSD and Apple OS-X. Versions have also built on Red Hat
Linux, and other flavors of GNU/Linux-ish platforms. Verilator also works
on Windows Subsystem for Linux (WSL2), Windows under Cygwin, and Windows
under MinGW (gcc -mno-cygwin). Verilated output (not Verilator itself)
compiles under all the options above, plus using MSVC++.
testing on FreeBSD and Apple OS-X. Versions have also been built on Red Hat
Linux, other flavors of GNU/Linux-ish platforms, Windows Subsystem for
Linux (WSL2), Windows under Cygwin, and Windows under MinGW (gcc
-mno-cygwin). Verilated output (not Verilator itself) compiles under all
the options above, plus using MSVC++.
Install Prerequisites
@ -153,13 +153,13 @@ required at Verilator build time.
Obtain Sources
--------------
Get the sources from the git repository: (You need do this only once,
Get the sources from the git repository: (You need to do this only once,
ever.)
::
git clone https://github.com/verilator/verilator # Only first time
## Note the URL above is not a page you can see with a browser, it's for git only
## Note the URL above is not a page you can see with a browser; it's for git only
Enter the checkout and determine what version/branch to use:
@ -186,7 +186,7 @@ Create the configuration script:
Eventual Installation Options
-----------------------------
Before configuring the build, you have to decide how you're going to
Before configuring the build, you must decide how you're going to
eventually install Verilator onto your system. Verilator will be compiling
the current value of the environment variables :option:`VERILATOR_ROOT`,
:option:`SYSTEMC_INCLUDE`, and :option:`SYSTEMC_LIBDIR` as defaults into
@ -220,8 +220,8 @@ the path to all needed files.
You may eventually be installing onto a project/company-wide "CAD" tools
disk that may support multiple versions of every tool. Tell configure the
eventual destination directory name. We recommend the destination location
include the Verilator version name:
eventual destination directory name. We recommend that the destination
location include the Verilator version name:
::
@ -255,7 +255,7 @@ as most GNU tools support:
unsetenv VERILATOR_ROOT # if your shell is csh
./configure --prefix /opt/verilator-VERSION
Then after installing (below steps) you will need to add
Then after installing (below steps), you will need to add
``/opt/verilator-VERSION/bin`` to your ``$PATH`` environment variable.
@ -271,7 +271,7 @@ configure's default system paths:
unsetenv VERILATOR_ROOT # if your shell is csh
./configure
Then after installing (below) the binaries should be in a location that is
Then after installing (below), the binaries should be in a location
already in your ``$PATH`` environment variable.

View File

@ -41,7 +41,7 @@ union, var, void, priority case/if, and unique case/if.
It also supports .name and .\* interconnection.
Verilator partially supports concurrent assert and cover statements; see
the enclosed coverage tests for the syntax which is allowed.
the enclosed coverage tests for the allowed syntax.
Verilator has limited support for class and related object-oriented
constructs.
@ -58,8 +58,8 @@ function call-like preprocessor defines, default define arguments,
SystemVerilog 2017 (IEEE 1800-2017) Support
-------------------------------------------
Verilator supports the 2017 "for" loop constructs, and several minor
cleanups IEEE made in 1800-2017.
Verilator supports the 2017 "for" loop constructs and several cleanups IEEE
made in 1800-2017.
Verilog AMS Support
@ -67,31 +67,31 @@ Verilog AMS Support
Verilator implements a very small subset of Verilog AMS (Verilog Analog and
Mixed-Signal Extensions) with the subset corresponding to those VMS
keywords with near equivalents in the Verilog 2005 or SystemVerilog 2009
languages.
keywords with near-equivalents in Verilog 2005 or SystemVerilog 2017.
AMS parsing is enabled with :vlopt:`--language VAMS <--language>` or
:vlopt:`--language 1800+VAMS <--language>`.
At present Verilator implements ceil, exp, floor, ln, log, pow, sqrt,
string, and wreal.
Verilator implements ceil, exp, floor, ln, log, pow, sqrt, string, and
wreal.
Synthesis Directive Assertion Support
-------------------------------------
With the :vlopt:`--assert` option, Verilator reads any :code:`//synopsys
full_case` or :code:`//synopsys parallel_case` directives. The same
applies to any :code:`//ambit synthesis`, :code:`//cadence` or
:code:`//pragma` directives of the same form.
With the :vlopt:`--assert` option, Verilator reads any
:code:`//synopsys full_case` or :code:`//synopsys parallel_case`
directives. The same applies to any :code:`//ambit synthesis`,
:code:`//cadence` or :code:`//pragma` directives of the same form.
When these synthesis directives are discovered, Verilator will either
formally prove the directive to be true, or failing that, will insert the
formally prove the directive to be true, or, failing that, will insert the
appropriate code to detect failing cases at simulation runtime and print an
"Assertion failed" error message.
Verilator likewise also asserts any "unique" or "priority" SystemVerilog
keywords on case statement, as well as "unique" on if statements. However,
keywords on case statements, as well as "unique" on if statements. However,
"priority if" is currently ignored.
@ -108,7 +108,7 @@ With :vlopt:`--timing`, all timing controls are supported:
as well as all flavors of :code:`fork`.
Compiling a verilated design that makes use of these features requires a
Compiling a Verilated design that uses these features requires a
compiler with C++20 coroutine support, e.g. Clang 5, GCC 10, or newer.
:code:`#0` delays cause Verilator to issue the :option:`ZERODLY` warning, as
@ -124,11 +124,11 @@ always the one chosen. Such expressions cause the :option:`MINTYPMAX` warning.
Another consequence of using :vlopt:`--timing` is that the :vlopt:`--main`
option generates a main file with a proper timing eval loop, eliminating the
need for writing any driving C++ code. You can then simply compile the
need for writing any driving C++ code. You can simply compile the
simulation (perhaps using :vlopt:`--build`) and run it.
With :vlopt:`--no-timing`, all timing controls cause the :option:`NOTIMING`
error, with the exception of:
error, except:
* delay statements they are ignored (as they are in synthesis), though they
do issue a :option:`STMTDLY` warning,
@ -137,16 +137,15 @@ error, with the exception of:
* net delays they are ignored,
* event controls at the top of the procedure,
Forks cause this error as well, with the exception of:
Forks cause this error as well, except:
* forks with no statements,
* :code:`fork..join` or :code:`fork..join_any` with one statement,
* forks with :vlopt:`--bbox-unsup`.
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all timing
controls cause the :option:`NEEDTIMINGOPT` error, with the exception of event
controls at the top of the process. Forks cause this error as well, with the
exception of:
If neither :vlopt:`--timing` nor :vlopt:`--no-timing` is specified, all
timing controls cause the :option:`NEEDTIMINGOPT` error, except event
controls at the top of the process. Forks cause this error as well, except:
* forks with no statements,
* :code:`fork..join` or :code:`fork..join_any` with one statement,
@ -174,15 +173,15 @@ Synthesis Subset
Verilator supports the Synthesis subset with other verification constructs
being added over time. Verilator also simulates events as Synopsys's Design
Compiler would; namely given a block of the form:
Compiler would, namely given a block of the form:
.. code-block:: sv
always @(x) y = x & z;
This will recompute y when there is even a potential for change in x or a
change in z, that is when the flops computing x or z evaluate (which is
what Design Compiler will synthesize.) A compliant simulator would only
This will recompute y when there is a potential for change in x or a change
in z; that is when the flops computing x or z evaluate (which is what
Design Compiler will synthesize.) A compliant simulator will only
calculate y if x changes. We recommend using always_comb to make the code
run the same everywhere. Also avoid putting $displays in combo blocks, as
they may print multiple times when not desired, even on compliant
@ -195,7 +194,7 @@ Signal Naming
To avoid conflicts with C symbol naming, any character in a signal name
that is not alphanumeric nor a single underscore will be replaced by __0hh
where hh is the hex code of the character. To avoid conflicts with
Verilator's internal symbols, any double underscore are replaced with
Verilator's internal symbols, any double underscore is replaced with
___05F (5F is the hex code of an underscore.)
@ -210,14 +209,13 @@ Class
-----
Verilator class support is limited but in active development. Verilator
supports members, and methods. Verilator does not support class static
members, class extend, or class parameters.
supports members, methods, class extend, and class parameters.
Dotted cross-hierarchy references
---------------------------------
Verilator supports dotted references to variables, functions and tasks in
Verilator supports dotted references to variables, functions, and tasks in
different modules. The portion before the dot must have a constant value;
for example a[2].b is acceptable, while a[x].b is generally not.
@ -231,7 +229,7 @@ code.
Latches
-------
Verilator is optimized for edge sensitive (flop based) designs. It will
Verilator is optimized for edge-sensitive (flop-based) designs. It will
attempt to do the correct thing for latches, but most performance
optimizations will be disabled around the latch.
@ -251,38 +249,38 @@ unsupported.
Unknown States
--------------
Verilator is mostly a two state simulator, not a four state simulator.
However, it has two features which uncover most initialization bugs
(including many that a four state simulator will miss.)
Verilator is mostly a two-state simulator, not a four-state simulator.
However, it has two features that uncover most initialization bugs
(including many that a four-state simulator will miss.)
Identity comparisons (=== or !==) are converted to standard ==/!= when
neither side is a constant. This may make the expression yield a different
result compared to a four state simulator. An === comparison to X will
result than a four-state simulator. An === comparison to X will
always be false, so that Verilog code which checks for uninitialized logic
will not fire.
Assigning X to a variable will actually assign a constant value as
determined by the :vlopt:`--x-assign` option. This allows runtime
randomization, thus if the value is actually used, the random value should
cause downstream errors. Integers also get randomized, even though the
Verilog 2001 specification says they initialize to zero. Note however that
randomization happens at initialization time and hence during a single
simulation run, the same constant (but random) value will be used every
time the assignment is executed.
Assigning X to a variable will assign a constant value as determined by the
:vlopt:`--x-assign` option. This allows runtime randomization; thus, if
the value is used, the random value should cause downstream errors.
Integers also get randomized, even though the Verilog 2001 specification
says they initialize to zero. However, randomization happens at
initialization time; hence, during a single simulation run, the same
constant (but random) value will be used every time the assignment is
executed.
All variables, depending on :vlopt:`--x-initial` setting, are typically
randomly initialized using a function. By running several random
simulation runs you can determine that reset is working correctly. On the
first run, have the function initialize variables to zero. On the second,
have it initialize variables to one. On the third and following runs have
it initialize them randomly. If the results match, reset works. (Note
this is what the hardware will really do.) In practice, just setting all
variables to one at startup finds most problems (since typically control
signals are active-high).
randomly initialized using a function. You can determine that reset is
working correctly by running several random simulation runs. On the first
run, have the function initialize variables to zero. On the second, have
it initialize variables to one. On the third and following runs, have it
initialize them randomly. If the results match, reset works. (Note that
this is what the hardware will do.) In practice, setting all variables to
one at startup finds the most problems (since control signals are typically
active-high).
:vlopt:`--x-assign` applies to variables explicitly initialized or assigned
an X. Uninitialized clocks are initialized to zero, while all other state
holding variables are initialized to a random value. Event driven
holding variables are initialized to a random value. Event-driven
simulators will generally trigger an edge on a transition from X to 1
(posedge) or X to 0 (negedge). However, by default, since clocks are
initialized to zero, Verilator will not trigger an initial negedge. Some
@ -318,19 +316,19 @@ External logic will be needed to combine these signals with any external
drivers.
Tristate drivers are not supported inside functions and tasks; an inout
there will be considered a two state variable that is read and written
instead of a four state variable.
there will be considered a two-state variable that is read and written
instead of a four-state variable.
Functions & Tasks
-----------------
All functions and tasks will be inlined (will not become functions in C.)
The only support provided is for simple statements in tasks (which may
The only support provided is simple statements in tasks (which may
affect global variables).
Recursive functions and tasks are not supported. All inputs and outputs
are automatic, as if they had the Verilog 2001 "automatic" keyword
are automatic as if they had the Verilog 2001 "automatic" keyword
prepended. (If you don't know what this means, Verilator will do what you
probably expect, what C does. The default behavior of Verilog is
different.)
@ -362,14 +360,14 @@ error for more information.
Array Out of Bounds
-------------------
Writing a memory element that is outside the bounds specified for the array
may cause a different memory element inside the array to be written
instead. For power-of-2 sized arrays, Verilator will give a width warning
and the address. For non-power-of-2-sizes arrays, index 0 will be written.
Writing a memory element outside the bounds specified for the array may
cause a different memory element inside the array to be written instead.
For power-of-2 sized arrays, Verilator will give a width warning and the
address. For non-power-of-2-sizes arrays, index 0 will be written.
Reading a memory element that is outside the bounds specified for the array
will give a width warning and wrap around the power-of-2 size. For
non-power-of-2 sizes, it will return a unspecified constant of the
Reading a memory element outside the bounds specified for the array will
give a width warning and wrap around the power-of-2 size. For
non-power-of-2 sizes, it will return an unspecified constant of the
appropriate width.
@ -389,14 +387,14 @@ Force statement
---------------
Verilator supports the procedural `force` (and corresponding `release`)
statement. The behavior of the `force` statement however does not entirely
comply with the IEEE 1800 SystemVerilog standard. According to the standard,
statement. However, the behavior of the `force` statement does not entirely
comply with IEEE 1800. According to the standard,
when a procedural statement of the form `force a = b;` is executed, the
simulation should behave as if from that point forwards, a continuous
assignment `assign a = b;` have been added to override the drivers of `a`.
More specifically: the value of `a` should be updated, whenever the value of
`b` changes, all the way until a `release a;` statement is executed.
Verilator instead evaluates the current value of `b` at the time the `force`
simulation should behave as if, from that point forwards, a continuous
assignment `assign a = b;` has been added to override the drivers of `a`.
More specifically: the value of `a` should be updated whenever the value of
`b` changes, until a `release a;` statement is executed.
Verilator instead evaluates the current value of `b` when the `force`
statement is executed, and forces `a` to that value, without updating it
until a new `force` or `release` statement is encountered that applies to
`a`. This non-standard behavior is nevertheless consistent with some other
@ -406,7 +404,7 @@ simulators.
Encrypted Verilog
-----------------
Open source simulators like Verilator are unable to use encrypted RTL
Open-source simulators like Verilator cannot use encrypted RTL
(i.e. IEEE P1735). Talk to your IP vendor about delivering IP blocks via
Verilator's :vlopt:`--protect-lib` feature.
@ -447,12 +445,12 @@ This section describes specific limitations for each language keyword.
certain limited cases.
'{} operator
Assignment patterns with order based, default, constant integer (array)
Assignment patterns with an order based, default, constant integer (array)
or member identifier (struct/union) keys are supported. Data type keys
and keys which are computed from a constant expression are not supported.
and keys computed from a constant expression are not supported.
\`uselib
Uselib, a vendor specific library specification method, is ignored along
Uselib, a vendor-specific library specification method, is ignored along
with anything following it until the end of that line.
cast operator
@ -460,8 +458,8 @@ cast operator
unsigned, not arrays nor structs.
chandle
Treated as a "longint"; does not yet warn about operations that are
specified as illegal on chandles.
Treated as a "longint"; does not yet warn about operations specified as
illegal on chandles.
disable
Disable statements may be used only if the block being disabled is a
@ -474,7 +472,7 @@ inside
upper bound. Case inside and case matches are also unsupported.
interface
Interfaces and modports, including with generated data types are
Interfaces and modports, including generated data types are
supported. Generate blocks around modports are not supported, nor are
virtual interfaces nor unnamed interfaces.
@ -486,25 +484,25 @@ specify specparam
All specify blocks and timing checks are ignored.
uwire
Verilator does not perform warning checking on uwires, it treats the
Verilator does not perform warning checking on uwires; it treats the
uwire keyword as if it were the normal wire keyword.
$bits, $countbits, $countones, $finish, $isunknown, $onehot, $onehot0, $signed, $stime, $stop, $time, $unsigned,
Generally supported.
$dump/$dumpports and related
$dumpfile or $dumpports will create a VCD or FST file (which is based on
$dumpfile or $dumpports will create a VCD or FST file (based on
the :vlopt:`--trace` option given when the model was Verilated). This
will take effect starting at the next eval() call. If you have multiple
Verilated designs under the same C model, then this will dump signals
Verilated designs under the same C model, this will dump signals
only from the design containing the $dumpvars.
$dumpvars and $dumpports module identifier is ignored; the traced
instances will always start at the top of the design. The levels argument
is also ignored, use tracing_on/tracing_off pragmas instead.
is also ignored; use tracing_on/tracing_off pragmas instead.
$dumpportson/$dumpportsoff/$dumpportsall/$dumpportslimit filename
argument is ignored, only a single trace file may be active at once.
argument is ignored; only a single trace file may be active at once.
$dumpall/$dumpportsall, $dumpon/$dumpportson, $dumpoff/$dumpportsoff, and
$dumplimit/$dumpportlimit are currently ignored.
@ -513,7 +511,7 @@ $error, $fatal, $info, $warning.
Generally supported.
$exit, $finish, $stop
The rarely used optional parameter to $finish and $stop is ignored. $exit
The rarely used optional parameter to $finish and $stop is ignored; $exit
is aliased to $finish.
$fopen, $fclose, $fdisplay, $ferror, $feof, $fflush, $fgetc, $fgets, $fscanf, $fwrite, $fscanf, $sscanf
@ -529,8 +527,8 @@ $random, $urandom, $urandom_range
per object for random stability of $urandom/$urandom_range.
$readmemb, $readmemh
Read memory commands are supported. Note Verilator and the Verilog
specification does not include support for readmem to multi-dimensional
Read memory commands are supported. Verilator and the Verilog
specification do not include support for readmem to multi-dimensional
arrays.
$test$plusargs, $value$plusargs

View File

@ -8,30 +8,30 @@ Overview
Welcome to Verilator!
The Verilator package converts Verilog [#]_ and SystemVerilog [#]_ hardware
description language (HDL) designs into a C++ or SystemC model that after
compiling can be executed. Verilator is not a traditional simulator, but a
description language (HDL) designs into a C++ or SystemC model that, after
compiling, can be executed. Verilator is not a traditional simulator but a
compiler.
Verilator is typically used as follows:
1. The :command:`verilator` executable is invoked with parameters similar
to GCC, or other simulators such as Cadence Verilog-XL/NC-Verilog, or
to GCC or other simulators such as Cadence Verilog-XL/NC-Verilog, or
Synopsys VCS. Verilator reads the specified SystemVerilog code, lints it,
optionally adds coverage and waveform tracing support, and compiles the
design into a source level multithreaded C++ or SystemC "model". The
design into a source-level multithreaded C++ or SystemC "model". The
resulting model's C++ or SystemC code is output as .cpp and .h files. This
is referred to as "Verilating" and the process is "to Verilate"; the output
is a "Verilated" model.
is referred to as "Verilating", and the process is "to Verilate"; the
output is a "Verilated" model.
2. For simulation, a small user written C++ wrapper file is required, the
"wrapper". This wrapper defines the C++ standard function "main()" which
2. For simulation, a small-user written C++ wrapper file is required, the
"wrapper". This wrapper defines the C++ standard function "main()", which
instantiates the Verilated model as a C++/SystemC object.
3. The user C++ wrapper, the files created by Verilator, a "runtime
library" provided by Verilator, and if applicable SystemC libraries are
library" provided by Verilator, and, if applicable SystemC libraries are
then compiled using a C++ compiler to create a simulation executable.
4. The resulting executable will perform the actual simulation, during
4. The resulting executable will perform the actual simulation during
"simulation runtime".
5. If appropriately enabled, the executable may also generate waveform
@ -44,12 +44,12 @@ The best place to get started is to try the :ref:`Examples`.
.. [#] Verilog is defined by the `Institute of Electrical and Electronics
Engineers (IEEE) Standard for Verilog Hardware Description
Language`, Std. 1364, released in 1995, 2001, and 2005. The
Verilator documentation uses the shorthand e.g. "IEEE 1394-2005" to
refer to the e.g. 2005 version of this standard.
Verilator documentation uses the shorthand, e.g., "IEEE 1394-2005",
to refer to the, e.g., 2005 version of this standard.
.. [#] SystemVerilog is defined by the `Institute of Electrical and
Electronics Engineers (IEEE) Standard for SystemVerilog - Unified
Hardware Design, Specification, and Verification Language`, Standard
1800, released in 2005, 2009, 2012, and 2017. The Verilator
documentation uses the shorthand e.g. "IEEE 1800-2017" to refer to
the e.g. 2017 version of this standard.
documentation uses the shorthand e.g., "IEEE 1800-2017", to refer to
the, e.g., 2017 version of this standard.

View File

@ -7,7 +7,7 @@
Simulating (Verilated-Model Runtime)
************************************
This section describes items related to simulating, that is, the use of a
This section describes items related to simulating, that is, using a
Verilated model's executable. For the runtime arguments to a simulated
model, see :ref:`Simulation Runtime Arguments`.
@ -18,30 +18,32 @@ Benchmarking & Optimization
===========================
For best performance, run Verilator with the :vlopt:`-O3`
:vlopt:`--x-assign fast <--x-assign>` :vlopt:`--x-initial fast
<--x-initial>` :vlopt:`--noassert <--assert>` options. The :vlopt:`-O3`
option will require longer time to run Verilator, and :vlopt:`--x-assign
fast <--x-assign>` :vlopt:`--x-initial fast <--x-assign>` may increase the
risk of reset bugs in trade for performance; see the above documentation
for these options.
:vlopt:`--x-assign fast <--x-assign>`
:vlopt:`--x-initial fast <--x-initial>`
:vlopt:`--noassert <--assert>` options. The :vlopt:`-O3`
option will require a longer time to run Verilator, and
:vlopt:`--x-assign fast <--x-assign>`
:vlopt:`--x-initial fast <--x-assign>`
may increase the risk of reset bugs in trade for performance; see the above
documentation for these options.
If using Verilated multithreaded, use ``numactl`` to ensure you are using
non-conflicting hardware resources. See :ref:`Multithreading`. Also
consider using profile-guided optimization, see :ref:`Thread PGO`.
If using Verilated multithreaded, use ``numactl`` to ensure you use
non-conflicting hardware resources. See :ref:`Multithreading`. Also,
consider using profile-guided optimization; see :ref:`Thread PGO`.
Minor Verilog code changes can also give big wins. You should not have any
UNOPTFLAT warnings from Verilator. Fixing these warnings can result in
huge improvements; one user fixed their one UNOPTFLAT warning by making a
simple change to a clock latch used to gate clocks and gained a 60%
performance improvement.
:option:`UNOPTFLAT` warnings from Verilator. Fixing these warnings can
result in huge improvements; one user fixed their one UNOPTFLAT warning by
making a simple change to a clocked latch used to gate clocks and gained a
60% performance improvement.
Beyond that, the performance of a Verilated model depends mostly on your
C++ compiler and size of your CPU's caches. Experience shows that large
models are often limited by the size of the instruction cache, and as such
reducing code size if possible can be beneficial.
Beyond that, the performance of a Verilated model depends primarily on your
C++ compiler and the size of your CPU's caches. Experience shows that the
instruction cache size often limits large models, and reducing code size,
if possible, can be beneficial.
The supplied $VERILATOR_ROOT/include/verilated.mk file uses the OPT,
OPT_FAST, OPT_SLOW and OPT_GLOBAL variables to control optimization. You
OPT_FAST, OPT_SLOW, and OPT_GLOBAL variables to control optimization. You
can set these when compiling the output of Verilator with Make, for
example:
@ -49,17 +51,17 @@ example:
make OPT_FAST="-Os -march=native" -f Vour.mk Vour__ALL.a
OPT_FAST specifies optimization options for those parts of the model that
are on the fast path. This is mostly code that is executed every
cycle. OPT_SLOW applies to slow-path code, which executes rarely, often
only once at the beginning or end of simulation. Note that OPT_SLOW is
OPT_FAST specifies optimization options for those parts of the model
on the fast path. This is mostly code that is executed every
cycle. OPT_SLOW applies to slow-path code, which rarely executes, often
only once at the beginning or end of the simulation. OPT_SLOW is
ignored if VM_PARALLEL_BUILDS is not 1, in which case all generated code
will be compiled in a single compilation unit using OPT_FAST. See also the
Verilator :vlopt:`--output-split` option. The OPT_GLOBAL variable applies
to common code in the runtime library used by Verilated models (shipped in
$VERILATOR_ROOT/include). Additional C++ files passed on the verilator
command line use OPT_FAST. The OPT variable applies to all compilation
units in addition to the specific "OPT" variables described above.
units and the specific "OPT" variables described above.
You can also use the :vlopt:`-CFLAGS` and/or :vlopt:`-LDFLAGS` options on
the verilator command line to pass arguments directly to the compiler or
@ -68,53 +70,53 @@ linker.
The default values of the "OPT" variables are chosen to yield good
simulation speed with reasonable C++ compilation times. To this end,
OPT_FAST is set to "-Os" by default. Higher optimization such as "-O2" or
"-O3" may help (though often they provide only a very small performance
benefit), but compile times may be excessively large even with medium sized
"-O3" may help (though often they provide only a minimal performance
benefit), but compile times may be excessively large even with medium-sized
designs. Compilation times can be improved at the expense of simulation
speed by reducing optimization, for example with OPT_FAST="-O0". Often good
simulation speed can be achieved with OPT_FAST="-O1 -fstrict-aliasing" but
with improved compilation times. Files controlled by OPT_SLOW have little
effect on performance and therefore OPT_SLOW is empty by default
(equivalent to "-O0") for improved compilation speed. In common use-cases
speed by reducing optimization, for example, with OPT_FAST="-O0". Often
good simulation speed can be achieved with OPT_FAST="-O1 -fstrict-aliasing"
but with improved compilation times. Files controlled by OPT_SLOW have
little effect on performance, and therefore OPT_SLOW is empty by default
(equivalent to "-O0") for improved compilation speed. In common use cases,
there should be little benefit in changing OPT_SLOW. OPT_GLOBAL is set to
"-Os" by default and there should rarely be a need to change it. As the
runtime library is small in comparison to a lot of Verilated models,
disabling optimization on the runtime library should not have a serious
effect on overall compilation time, but may have detrimental effect on
simulation speed, especially with tracing. In addition to the above, for
best results use OPT="-march=native", the latest Clang compiler (about 10%
faster than GCC), and link statically.
"-Os" by default, and there should rarely be a need to change it. As the
runtime library is small compared to many Verilated models, disabling
optimization on the runtime library should not seriously affect overall
compilation time but may have a detrimental effect on simulation speed,
especially with tracing. In addition to the above, for best results, use
OPT="-march=native", the latest Clang compiler (about 10% faster than GCC),
and link statically.
Generally the answer to which optimization level gives the best user
experience depends on the use case and some experimentation can pay
Generally, the answer to which optimization level gives the best user
experience depends on the use case, and some experimentation can pay
dividends. For a speedy debug cycle during development, especially on large
designs where C++ compilation speed can dominate, consider using lower
optimization to get to an executable faster. For throughput oriented use
cases, for example regressions, it is usually worth spending extra
optimization to get to an executable faster. For throughput-oriented use
cases, for example, regressions, it is usually worth spending extra
compilation time to reduce total CPU time.
If you will be running many simulations on a single model, you can
investigate profile guided optimization. See :ref:`Compiler PGO`.
investigate profile-guided optimization. See :ref:`Compiler PGO`.
Modern compilers also support link-time optimization (LTO), which can help
Modern compilers also support link-time optimization (LTO), which can help,
especially if you link in DPI code. To enable LTO on GCC, pass "-flto" in
both compilation and link. Note LTO may cause excessive compile times on
large designs.
both compilation and link. Note that LTO may cause excessive compile times
on large designs.
Unfortunately, using the optimizer with SystemC files can result in
compilation taking several minutes. (The SystemC libraries have many little
inlined functions that drive the compiler nuts.)
If you are using your own makefiles, you may want to compile the Verilated
If using your own makefiles, you may want to compile the Verilated
code with ``--MAKEFLAGS -DVL_INLINE_OPT=inline``. This will inline
functions, however this requires that all cpp files be compiled in a single
functions; however, this requires that all cpp files be compiled in a single
compiler run.
You may uncover further tuning possibilities by profiling the Verilog code.
See :ref:`profiling`.
When done optimizing, please let the author know the results. We like to
keep tabs on how Verilator compares, and may be able to suggest additional
keep tabs on how Verilator compares and may be able to suggest additional
improvements.
@ -141,14 +143,14 @@ Functional Coverage
-------------------
With :vlopt:`--coverage` or :vlopt:`--coverage-user`, Verilator will
translate functional coverage points which the user has inserted manually
into the SystemVerilog design, into the Verilated model.
translate functional coverage points the user has inserted manually win
SystemVerilog code through into the Verilated model.
Currently, all functional coverage points are specified using SystemVerilog
assertion syntax which must be separately enabled with :vlopt:`--assert`.
assertion syntax, which must be separately enabled with :vlopt:`--assert`.
For example, the following SystemVerilog statement will add a coverage
point, under the coverage name "DefaultClock":
point under the coverage name "DefaultClock":
.. code-block:: sv
@ -161,13 +163,13 @@ Line Coverage
-------------
With :vlopt:`--coverage` or :vlopt:`--coverage-line`, Verilator will
automatically add coverage analysis at each code flow change point (e.g. at
branches). At each such branch a unique counter is incremented. At the
end of a test, the counters along with the filename and line number
corresponding to each counter are written into the coverage file.
automatically add coverage analysis at each code flow change point (e.g.,
at branches). At each such branch, a counter is incremented. At the end
of a test, the counters, filename, and line number corresponding to each
counter are written into the coverage file.
Verilator automatically disables coverage of branches that have a $stop in
them, as it is assumed $stop branches contain an error check that should
Verilator automatically disables coverage of branches with a $stop in
them, as it is assumed that $stop branches contain an error check that should
not occur. A :option:`/*verilator&32;coverage_block_off*/` metacomment
will perform a similar function on any code in that block or below, or
:option:`/*verilator&32;coverage_off*/` and
@ -175,8 +177,9 @@ will perform a similar function on any code in that block or below, or
respectively around a block of code.
Verilator may over-count combinatorial (non-clocked) blocks when those
blocks receive signals which have had the UNOPTFLAT warning disabled; for
most accurate results do not disable this warning when using coverage.
blocks receive signals which have had the :option:`UNOPTFLAT` warning
disabled; for the most accurate results, do not disable this warning when
using coverage.
.. _Toggle Coverage:
@ -187,8 +190,8 @@ Toggle Coverage
With :vlopt:`--coverage` or :vlopt:`--coverage-toggle`, Verilator will
automatically add toggle coverage analysis into the Verilated model.
Every bit of every signal in a module has a counter inserted. The counter
will increment on every edge change of the corresponding bit.
Every bit of every signal in a module has a counter inserted, and the
counter will increment on every edge change of the corresponding bit.
Signals that are part of tasks or begin/end blocks are considered local
variables and are not covered. Signals that begin with underscores (see
@ -196,17 +199,17 @@ variables and are not covered. Signals that begin with underscores (see
total storage across all dimensions, see :vlopt:`--coverage-max-width`) are
also not covered.
Hierarchy is compressed, such that if a module is instantiated multiple
times, coverage will be summed for that bit across **all** instantiations
of that module with the same parameter set. A module instantiated with
different parameter values is considered a different module, and will get
counted separately.
Hierarchy is compressed, so if a module is instantiated multiple times,
coverage will be summed for that bit across **all** instantiations of that
module with the same parameter set. A module instantiated with different
parameter values is considered a different module and will get counted
separately.
Verilator makes a minimally-intelligent decision about what clock domain
the signal goes to, and only looks for edges in that clock domain. This
means that edges may be ignored if it is known that the edge could never be
seen by the receiving logic. This algorithm may improve in the future.
The net result is coverage may be lower than what would be seen by looking
means that edges may be ignored if it is known that the receiving logic
could never see the edge. This algorithm may improve in the future. The
net result is that coverage may be lower than what would be seen by looking
at traces, but the coverage is a more accurate representation of the
quality of stimulus into the design.
@ -224,7 +227,7 @@ signals that do not need toggle analysis, such as RAMs and register files.
Coverage Collection
-------------------
When any coverage flag was used to Verilate, Verilator will add appropriate
When any coverage flag is used to Verilate, Verilator will add appropriate
coverage point insertions into the model and collect the coverage data.
To get the coverage data from the model, in the user wrapper code,
@ -237,23 +240,23 @@ Run each of your tests in different directories, potentially in parallel.
Each test will create a :file:`logs/coverage.dat` file.
After running all of the tests, execute the :command:`verilator_coverage`
command, passing arguments pointing to the filenames of all of the
individual coverage files. :command:`verilator_coverage` will reads the
command, passing arguments pointing to the filenames of all the
individual coverage files. :command:`verilator_coverage` will read the
:file:`logs/coverage.dat` file(s), and create an annotated source code
listing showing code coverage details.
:command:`verilator_coverage` may also be used for test grading, that is
computing which tests are important to fully cover the design.
:command:`verilator_coverage` may also be used for test grading, computing
which tests are important to give full verification coverage on the design.
For an example, see the :file:`examples/make_tracing_c/logs` directory.
Grep for lines starting with '%' to see what lines Verilator believes need
more coverage.
Additional options of :command:`verilator_coverage` allow for merging of
coverage data files or other transformations.
Additional options of :command:`verilator_coverage` allow for the merging
of coverage data files or other transformations.
Info files can be written by verilator_coverage for import to
:command:`lcov`. This enables use of :command:`genhtml` for HTML reports
:command:`lcov`. This enables using :command:`genhtml` for HTML reports
and importing reports to sites such as `https://codecov.io
<https://codecov.io>`_.
@ -274,7 +277,7 @@ To use profiling:
#. Build and run the simulation model.
#. The model will create gmon.out.
#. Run :command:`gprof` to see where in the C++ code the time is spent.
#. Run the gprof output through the :command:`verilator_profcfunc` program
#. Run the gprof output through the :command:`verilator_profcfunc` program,
and it will tell you what Verilog line numbers on which most of the time
is being spent.
@ -284,7 +287,7 @@ To use profiling:
Execution Profiling
===================
For performance optimization, it is useful to see statistics and visualize how
For performance optimization, it is helpful to see statistics and visualize how
execution time is distributed in a verilated model.
With the :vlopt:`--prof-exec` option, Verilator will:
@ -294,14 +297,13 @@ With the :vlopt:`--prof-exec` option, Verilator will:
* Add code to save profiling data in non-human-friendly form to the file
specified with :vlopt:`+verilator+prof+exec+file+\<filename\>`.
* In multi-threaded models, add code to record the start and end time of each
macro-task across a number of calls to eval. (What is a macro-task? See the
* In multithreaded models, add code to record each macro-task's start and
end time across several calls to eval. (What is a macro-task? See the
Verilator internals document (:file:`docs/internals.rst` in the
distribution.)
The :command:`verilator_gantt` program may then be run to transform the
saved profiling file into a nicer visual format and produce some related
statistics.
saved profiling file into a visual format and produce related statistics.
.. figure:: figures/fig_gantt_min.png
@ -309,11 +311,11 @@ statistics.
The measured_parallelism shows the number of CPUs being used at a given moment.
The cpu_thread section shows which thread is executing on each of the physical CPUs.
The cpu_thread section shows which thread is executing on each physical CPU.
The thread_mtask section shows which macro-task is running on a given thread.
For more information see :command:`verilator_gantt`.
For more information, see :command:`verilator_gantt`.
.. _Profiling ccache efficiency:
@ -321,12 +323,11 @@ For more information see :command:`verilator_gantt`.
Profiling ccache efficiency
===========================
The Verilator generated Makefile provides support for basic profiling of
ccache behavior during the build. This can be used to track down files that
might be unnecessarily rebuilt, though as of today even small code changes
will usually require rebuilding a large number of files. Improving ccache
efficiency during the edit/compile/test loop is an active area of
development.
The Verilator-generated Makefile supports basic profiling of ccache
behavior during the build. This can be used to track down files that might
be unnecessarily rebuilt, though as of today, even minor code changes will
usually require rebuilding a large number of files. Improving ccache
efficiency during the edit/compile/test loop is an active development area.
To get a basic report of how well ccache is doing, add the `ccache-report`
target when invoking the generated Makefile:
@ -350,17 +351,17 @@ releases.
Save/Restore
============
The intermediate state of a Verilated model may be saved, so that it may
The intermediate state of a Verilated model may be saved so that it may
later be restored.
To enable this feature, use :vlopt:`--savable`. There are limitations in
what language features are supported along with :vlopt:`--savable`; if you
attempt to use an unsupported feature Verilator will throw an error.
attempt to use an unsupported feature, Verilator will throw an error.
To use save/restore, the user wrapper code must create a VerilatedSerialize
or VerilatedDeserialze object then calling the :code:`<<` or :code:`>>`
operators on the generated model and any other data the process needs
saved/restored. These functions are not thread safe, and are typically
or VerilatedDeserialze object and then call the :code:`<<` or :code:`>>`
operators on the generated model and any other data the process needs to be
saved/restored. These functions are not thread-safe and are typically
called only by a main thread.
For example:
@ -370,7 +371,7 @@ For example:
void save_model(const char* filenamep) {
VerilatedSave os;
os.open(filenamep);
os << main_time; // user code must save the timestamp, etc
os << main_time; // user code must save the timestamp
os << *topp;
}
void restore_model(const char* filenamep) {
@ -385,11 +386,11 @@ Profile-Guided Optimization
===========================
Profile-guided optimization is the technique where profiling data is
collected by running your simulation executable, then this information is
collected by running your simulation executable; then this information is
used to guide the next Verilation or compilation.
There are two forms of profile-guided optimizations. Unfortunately for
best results they must each be performed from the highest level code to the
There are two forms of profile-guided optimizations. Unfortunately, for
best results, they must each be performed from the highest level code to the
lowest, which means performing them separately and in this order:
* :ref:`Thread PGO`
@ -397,7 +398,7 @@ lowest, which means performing them separately and in this order:
Other forms of PGO may be supported in the future, such as clock and reset
toggle rate PGO, branch prediction PGO, statement execution time PGO, or
others as they prove beneficial.
others, as they prove beneficial.
.. _Thread PGO:
@ -405,7 +406,7 @@ others as they prove beneficial.
Thread Profile-Guided Optimization
----------------------------------
Verilator supports profile-guided optimization (Verilation) of multi-threaded
Verilator supports profile-guided optimization (Verilation) of multithreaded
models (Thread PGO) to improve performance.
When using multithreading, Verilator computes how long macro tasks take and
@ -423,24 +424,24 @@ optimization.
Run the model executable. When the executable exits, it will create a
profile.vlt file.
Rerun Verilator, optionally omitting the :vlopt:`--prof-pgo` option,
and adding the profile.vlt generated earlier to the command line.
Rerun Verilator, optionally omitting the :vlopt:`--prof-pgo` option and
adding the :file:`profile.vlt` generated earlier to the command line.
Note there is no Verilator equivalent to GCC's --fprofile-use. Verilator's
profile data file (profile.vlt) can be placed on the verilator command line
directly without any prefix.
Note there is no Verilator equivalent to GCC's --fprofile-use. Verilator's
profile data file (:file:`profile.vlt`) can be placed directly on the
verilator command line without any option prefix.
If results from multiple simulations are to be used in generating the
optimization, multiple simulation's profile.vlt may be concatenated
externally, or each of the files may be fed as separate command line
options into Verilator. Verilator will sum the profile results, so a
longer running test will have proportionally more weight for optimization
than a shorter running test.
externally, or each file may be fed as separate command line options into
Verilator. Verilator will sum the profile results, so a long-running test
will have more weight for optimization proportionally than a
shorter-running test.
If you provide any profile feedback data to Verilator, and it cannot use
If you provide any profile feedback data to Verilator and it cannot use
it, it will issue the :option:`PROFOUTOFDATE` warning that threads were
scheduled using estimated costs. This usually indicates that the profile
data was generated from different Verilog source code than Verilator is
data was generated from a different Verilog source code than Verilator is
currently running against. Therefore, repeat the data collection phase to
create new profiling data, then rerun Verilator with the same input source
files and that new profiling data.
@ -452,12 +453,12 @@ Compiler Profile-Guided Optimization
------------------------------------
GCC and Clang support compiler profile-guided optimization (PGO). This
optimizes any C/C++ program including Verilated code. Using compiler PGO
optimizes any C/C++ program, including Verilated code. Using compiler PGO
typically yields improvements of 5-15% on both single-threaded and
multi-threaded models.
multithreaded models.
To use compiler PGO with GCC or Clang, please see the appropriate compiler
documentation. The process in GCC 10 was as follows:
Please see the appropriate compiler documentation to use PGO with GCC or
Clang. The process in GCC 10 was as follows:
1. Compile the Verilated model with the compiler's "-fprofile-generate"
flag:
@ -467,7 +468,7 @@ documentation. The process in GCC 10 was as follows:
verilator [whatever_flags] --make \
-CFLAGS -fprofile-generate -LDFLAGS -fprofile-generate
or, if calling make yourself, add -fprofile-generate appropriately to your
Or, if calling make yourself, add -fprofile-generate appropriately to your
Makefile.
2. Run your simulation. This will create \*.gcda file(s) in the same
@ -494,6 +495,6 @@ documentation. The process in GCC 10 was as follows:
or, if calling make yourself, add these CFLAGS switches appropriately to
your Makefile.
Clang and GCC also support -fauto-profile which uses sample-based
Clang and GCC also support -fauto-profile, which uses sample-based
feedback-directed optimization. See the appropriate compiler
documentation.

View File

@ -8,7 +8,7 @@ Verilating
Verilator may be used in five major ways:
* With the :vlopt:`--cc` or :vlopt:`--sc` options, Verilator will translate
the design into C++ or SystemC code respectively. See :ref:`C++ and
the design into C++ or SystemC code, respectively. See :ref:`C++ and
SystemC Generation`.
* With the :vlopt:`--lint-only` option, Verilator will lint the design to
@ -19,8 +19,8 @@ Verilator may be used in five major ways:
:file:`docs/xml.rst` in the distribution.
* With the :vlopt:`-E` option, Verilator will preprocess the code according
to IEEE preprocessing rules, and write the output to standard out. This
is useful to feed other tools, and to debug how "\`define" statements are
to IEEE preprocessing rules and write the output to standard out. This
is useful to feed other tools and to debug how "\`define" statements are
expanded.
@ -34,10 +34,10 @@ Verilator will translate a SystemVerilog design into C++ with the
When using these options:
#. Verilator reads the input Verilog code, determines all "top modules" that
is modules or programs that are not used as instances under other cells.
If :vlopt:`--top-module` is used, then that determines the top module and
all other top modules are removed, otherwise a :vlopt:`MULTITOP` warning
#. Verilator reads the input Verilog code and determines all "top modules", that
is, modules or programs that are not used as instances under other cells.
If :vlopt:`--top-module` is used, then that determines the top module, and
all other top modules are removed; otherwise a :vlopt:`MULTITOP` warning
is given.
#. Verilator writes the C++/SystemC code to output files into the
@ -46,13 +46,13 @@ When using these options:
top module.
#. If :vlopt:`--exe` is used, Verilator creates makefiles to generate a
simulation executable, otherwise it creates makefiles to generate an
simulation executable, otherwise, it creates makefiles to generate an
archive (.a) containing the objects.
#. If :vlopt:`--build` option was used, it calls :ref:`GNU Make` or
:ref:`CMake` to build the model.
Once a model is built it is then typically run, see :ref:`Simulating`.
Once a model is built, it is then typically run, see :ref:`Simulating`.
.. _Hierarchical Verilation:
@ -60,14 +60,14 @@ Once a model is built it is then typically run, see :ref:`Simulating`.
Hierarchical Verilation
=======================
Large designs may take long (e.g. 10+ minutes) and huge memory (e.g. 100+
Large designs may take long (e.g., 10+ minutes) and huge memory (e.g., 100+
GB) to Verilate. In hierarchical mode, the user manually selects some
large lower-level hierarchy blocks to separate from the larger design. For
example a core may be the hierarchy block, and separated out of a
multi-core SoC.
example, a core may be the hierarchy block separated out of a multi-core
SoC design.
Verilator is run in hierarchical mode on the whole SoC. Verilator will
make two models, one for the CPU hierarchy block, and one for the SoC. The
make two models, one for the CPU hierarchy block and one for the SoC. The
Verilated code for the SoC will automatically call the CPU Verilated model.
The current hierarchical Verilation is based on :vlopt:`--lib-create`. Each
@ -78,16 +78,16 @@ blocks will see a tiny wrapper generated by :vlopt:`--lib-create`.
Usage
-----
Users need to mark one or more moderate size module as hierarchy block(s).
Users need to mark one or more moderate-size modules as hierarchy block(s).
There are two ways to mark a module:
* Write :option:`/*verilator&32;hier_block*/` metacomment in HDL code.
* Add a :option:`hier_block` line in a the :ref:`Configuration Files`.
* Add a :option:`hier_block` line in the :ref:`Configuration Files`.
Then pass the :vlopt:`--hierarchical` option to Verilator
Then pass the :vlopt:`--hierarchical` option to Verilator.
Compilation is the same as when not using hierarchical mode.
The compilation is the same as when not using hierarchical mode.
.. code-block:: bash
@ -97,21 +97,20 @@ Compilation is the same as when not using hierarchical mode.
Limitations
-----------
Hierarchy blocks have some limitations including:
Hierarchy blocks have some limitations, including:
* The hierarchy block cannot be accessed using dot (.) from upper module(s)
or other hierarchy blocks.
* The hierarchy block cannot be accessed using dot (.) from the upper
module(s) or other hierarchy blocks.
* Signals in the block cannot be traced.
* Modport cannot be used at the hierarchical block boundary.
* The simulation speed is likely to not be as fast as flat Verilation, in
which all modules are globally scheduled.
* The simulation speed is likely not as fast as flat Verilation, in which
all modules are globally scheduled.
* Generated clocks may not work correctly if they are generated in the
hierarchical model and pass up into another hierarchical model or the top
module.
* Generated clocks may not work correctly if generated in the hierarchical
model and passed into another hierarchical model or the top module.
* Delays are not allowed in hierarchy blocks.
@ -130,8 +129,8 @@ Overlapping Verilation and Compilation
--------------------------------------
Verilator needs to run 2 + *N* times in hierarchical Verilation, where *N*
is the number of hierarchy blocks. One of the two is for the top module
which refers wrappers of all other hierarchy blocks. The second one of the
is the number of hierarchy blocks. One of the two is for the top module,
which refers to the wrappers of all other hierarchy blocks. The second of the
two is the initial run that searches modules marked with
:option:`/*verilator&32;hier_block*/` metacomment and creates a plan and
write in :file:`{prefix}_hier.mk`. This initial run internally invokes
@ -153,19 +152,19 @@ Verilator supports cross-compiling Verilated code. This is generally used
to run Verilator on a Linux system and produce C++ code that is then compiled
on Windows.
Cross compilation involves up to three different OSes. The build system is
where you configured and compiled Verilator, the host system where you run
Verilator, and the target system where you compile the Verilated code and
run the simulation.
Cross-compilation involves up to three different OSes. The build system is
where you configure and compile Verilator, the host system is where you run
Verilator, and the target system is where you compile the Verilated code
and run the simulation.
Currently, Verilator requires the build and host system type to be the
Verilator requires the build and host system types to be the
same, though the target system type may be different. To support this,
:command:`./configure` and make Verilator on the build system. Then, run
Verilator on the host system. Finally, the output of Verilator may be
compiled on the different target system.
To support this, none of the files that Verilator produces will reference
any configure generated build-system specific files, such as
any configure-generated build-system-specific files, such as
:file:`config.h` (which is renamed in Verilator to :file:`config_build.h`
to reduce confusion.) The disadvantage of this approach is that
:file:`include/verilatedos.h` must self-detect the requirements of the
@ -183,41 +182,29 @@ Multithreading
Verilator supports multithreaded simulation models.
With :vlopt:`--no-threads`, the default, the model is not thread safe, and
any use of more than one thread calling into one or even different
Verilated models may result in unpredictable behavior. This gives the
highest single thread performance.
With :vlopt:`--threads 1 <--threads>`, the generated model is single
threaded, however the support libraries are multithread safe. This allows
different instantiations of model(s) to potentially each be run under a
different thread. All threading is the responsibility of the user's C++
testbench.
With :vlopt:`--threads 1 <--threads>`, the generated model is
single-threaded; however, the support libraries are multithread safe. This
allows different instantiations of the model(s) to potentially each be run
under a different thread. All threading is the responsibility of the user's
C++ testbench.
With :vlopt:`--threads {N} <--threads>`, where N is at least 2, the
generated model will be designed to run in parallel on N threads. The
thread calling eval() provides one of those threads, and the generated
model will create and manage the other N-1 threads. It's the client's
responsibility not to oversubscribe the available CPU cores. Under CPU
oversubscription, the Verilated model should not livelock nor deadlock,
oversubscription, the Verilated model should not livelock nor deadlock;
however, you can expect performance to be far worse than it would be with
proper ratio of threads and CPU cores.
The remainder of this section describe behavior with :vlopt:`--threads 1
<--threads>` or :vlopt:`--threads {N} <--threads>` (not
:vlopt:`--no-threads`).
:code:`VL_THREADED` is defined in the C++ code when compiling a threaded
Verilated module, causing the Verilated support classes become threadsafe.
the proper ratio of threads and CPU cores.
The thread used for constructing a model must be the same thread that calls
:code:`eval()` into the model, this is called the "eval thread". The thread
used to perform certain global operations such as saving and tracing must
be done by a "main thread". In most cases the eval thread and main thread
:code:`eval()` into the model; this is called the "eval thread". The thread
used to perform certain global operations, such as saving and tracing, must
be done by a "main thread". In most cases, the eval thread and main thread
are the same thread (i.e. the user's top C++ testbench runs on a single
thread), but this is not required.
When making frequent use of DPI imported functions in a multi-threaded
When making frequent use of DPI imported functions in a multithreaded
model, it may be beneficial to performance to adjust the
:vlopt:`--instr-count-dpi` option based on some experimentation. This
influences the partitioning of the model by adjusting the assumed execution
@ -230,46 +217,46 @@ with :vlopt:`--threads`, and is executed on the same thread pool as the model.
The :vlopt:`--trace-threads` options can be used with :vlopt:`--trace-fst`
to offload FST tracing using multiple threads. If :vlopt:`--trace-threads` is
given without :vlopt:`--threads`, then :vlopt:`--trace-threads` will imply
:vlopt:`--threads 1 <--threads>`, i.e.: the support libraries will be
:vlopt:`--threads 1 <--threads>`, i.e., the support libraries will be
thread safe.
With :vlopt:`--trace-threads 0 <--trace-threads>`, trace dumps are produced
on the main thread. This again gives the highest single thread performance.
on the main thread. This again gives the highest single-thread performance.
With :vlopt:`--trace-threads {N} <--trace-threads>`, where N is at least 1,
up to N additional threads will be created and managed by the trace files
(e.g.: VerilatedFstC), to offload construction of the trace dump. The main
(e.g., VerilatedFstC), to offload construction of the trace dump. The main
thread will be released to proceed with execution as soon as possible, though
some blocking of the main thread is still necessary while capturing the
some main thread blocking is still necessary while capturing the
trace. FST tracing can utilize up to 2 offload threads, so there is no use
of setting :vlopt:`--trace-threads` higher than 2 at the moment.
When running a multithreaded model, the default Linux task scheduler often
works against the model, by assuming threads are short lived, and thus
often schedules threads using multiple hyperthreads within the same
physical core. For best performance use the :command:`numactl` program to
works against the model by assuming short-lived threads and thus
it often schedules threads using multiple hyperthreads within the same
physical core. For best performance, use the :command:`numactl` program to
(when the threading count fits) select unique physical cores on the same
socket. The same applies for :vlopt:`--trace-threads` as well.
As an example, if a model was Verilated with :vlopt:`--threads 4
<--threads>`, we consult:
As an example, if a model was Verilated with
:vlopt:`--threads 4 <--threads>`, we consult:
.. code-block:: bash
egrep 'processor|physical id|core id' /proc/cpuinfo
To select cores 0, 1, 2, and 3 that are all located on the same socket (0)
but different physical cores. (Also useful is :command:`numactl
--hardware`, or :command:`lscpu` but those doesn't show Hyperthreading
cores.) Then we execute:
but have different physical cores. (Also useful is
:command:`numactl --hardware`, or :command:`lscpu`, but those don't show
hyperthreading cores.) Then we execute:
.. code-block:: bash
numactl -m 0 -C 0,1,2,3 -- verilated_executable_name
This will limit memory to socket 0, and threads to cores 0, 1, 2, 3,
(presumably on socket 0) optimizing performance. Of course this must be
adjusted if you want another simulator using e.g. socket 1, or if you
(presumably on socket 0), optimizing performance. Of course, this must be
adjusted if you want another simulator to use, e.g., socket 1, or if you
Verilated with a different number of threads. To see what CPUs are
actually used, use :vlopt:`--prof-exec`.
@ -277,19 +264,19 @@ actually used, use :vlopt:`--prof-exec`.
Multithreaded Verilog and Library Support
-----------------------------------------
$display/$stop/$finish are delayed until the end of an eval() call in order
$display/$stop/$finish are delayed until the end of an eval() call
to maintain ordering between threads. This may result in additional tasks
completing after the $stop or $finish.
If using :vlopt:`--coverage`, the coverage routines are fully thread safe.
If using :vlopt:`--coverage`, the coverage routines are fully thread-safe.
If using the DPI, Verilator assumes pure DPI imports are thread safe,
If using the DPI, Verilator assumes pure DPI imports are thread-safe,
balancing performance versus safety. See :vlopt:`--threads-dpi`.
If using :vlopt:`--savable`, the save/restore classes are not multithreaded
and must be called only by the eval thread.
If using :vlopt:`--sc`, the SystemC kernel is not thread safe, therefore
If using :vlopt:`--sc`, the SystemC kernel is not thread-safe; therefore,
the eval thread and main thread must be the same.
If using :vlopt:`--trace`, the tracing classes must be constructed and
@ -309,8 +296,8 @@ Verilator defaults to creating GNU Make makefiles for the model. Verilator
will call make automatically when the :vlopt:'--build' option is used.
If calling Verilator from a makefile, the :vlopt:'-MMD' option will create
a dependency file which will allow Make to only run Verilator if input
Verilog files change.
a dependency file, allowing Make to only run Verilator if input Verilog
files change.
.. _CMake:
@ -319,8 +306,8 @@ CMake
Verilator can be run using CMake, which takes care of both running
Verilator and compiling the output. There is a CMake example in the
examples/ directory. The following is a minimal CMakeLists.txt that would
build the code listed in :ref:`Example C++ Execution`
:file:`examples/` directory. The following is a minimal CMakeLists.txt that
would build the code listed in :ref:`Example C++ Execution`
.. code-block:: CMake
@ -332,8 +319,8 @@ build the code listed in :ref:`Example C++ Execution`
:code:`find_package` will automatically find an installed copy of
Verilator, or use a local build if VERILATOR_ROOT is set.
It is recommended to use CMake >= 3.12 and the Ninja generator, though
other combinations should work. To build with CMake, change to the folder
Using CMake >= 3.12 and the Ninja generator is recommended, though other
combinations should work. To build with CMake, change to the folder
containing CMakeLists.txt and run:
.. code-block:: bash
@ -352,14 +339,14 @@ Or to build with your system default generator:
cmake ..
cmake --build .
If you're building the example you should have an executable to run:
If you're building the example, you should have an executable to run:
.. code-block:: bash
./Vour
The package sets the CMake variables verilator_FOUND, VERILATOR_ROOT and
VERILATOR_BIN to the appropriate values, and also creates a verilate()
The package sets the CMake variables verilator_FOUND, VERILATOR_ROOT,
and VERILATOR_BIN to the appropriate values and creates a verilate()
function. verilate() will automatically create custom commands to run
Verilator and add the generated C++ sources to the target specified.
@ -374,14 +361,14 @@ Verilate in CMake
[OPT_GLOBAL ..] [DIRECTORY dir] [THREADS num]
[TRACE_THREADS num] [VERILATOR_ARGS ...])
Lowercase and ... should be replaced with arguments, the uppercase parts
delimit the arguments and can be passed in any order, or left out entirely
Lowercase and ... should be replaced with arguments; the uppercase parts
delimit the arguments and can be passed in any order or left out entirely
if optional.
verilate(target ...) can be called multiple times to add other Verilog
modules to an executable or library target.
When generating Verilated SystemC sources, you should also include the
When generating Verilated SystemC sources, you should list the
SystemC include directories and link to the SystemC libraries.
.. describe:: target
@ -391,7 +378,7 @@ SystemC include directories and link to the SystemC libraries.
.. describe:: COVERAGE
Optional. Enables coverage if present, equivalent to "VERILATOR_ARGS
--coverage"
--coverage".
.. describe:: DIRECTORY
@ -419,22 +406,22 @@ SystemC include directories and link to the SystemC libraries.
.. describe:: PREFIX
Optional. Sets the Verilator output prefix. Defaults to the name of the
first source file with a "V" prepended. Must be unique in each call to
verilate(), so this is necessary if you build a module multiple times
with different parameters. Must be a valid C++ identifier, i.e. contains
no white space and only characters A-Z, a-z, 0-9 or _.
first source file with a "V" prepended. It must be unique in each call
to verilate(), so this is necessary if you build a module multiple times
with different parameters. It must be a valid C++ identifier, i.e., it
contains no white space and only characters A-Z, a-z, 0-9 or _.
.. describe:: SOURCES
List of Verilog files to Verilate. Must have at least one file.
List of Verilog files to Verilate. You must provide at least one file.
.. describe:: SYSTEMC
Optional. Enables SystemC mode, defaults to C++ if not specified.
When using Accellera's SystemC with CMake support, a CMake target is
available that simplifies the SystemC steps. This will only work if the
SystemC installation can be found by CMake. This can be configured by
available that simplifies the SystemC steps. This will only work if
CMake can find the SystemC installation, and this can be configured by
setting the CMAKE_PREFIX_PATH variable during CMake configuration.
Don't forget to set the same C++ standard for the Verilated sources as
@ -443,12 +430,11 @@ SystemC include directories and link to the SystemC libraries.
.. describe:: THREADS
Optional. Generated a multi-threaded model, same as "--threads".
Optional. Enable a multithreaded model; see :vlopt:`--threads`.
.. describe:: TRACE_THREADS
Optional. Generated multi-threaded FST trace dumping, same as
"--trace-threads".
Optional. Enable multithreaded FST trace; see :vlopt:`--trace-threads`.
.. describe:: TOP_MODULE
@ -468,7 +454,7 @@ SystemC include directories and link to the SystemC libraries.
.. describe:: VERILATOR_ARGS
Optional. Extra arguments to Verilator. Do not specify :vlopt:`--Mdir`
or :vlopt:`--prefix` here, use DIRECTORY or PREFIX.
or :vlopt:`--prefix` here; use DIRECTORY or PREFIX.
SystemC Link in CMake

File diff suppressed because it is too large Load Diff

View File

@ -39,12 +39,12 @@ The main flow of Verilator can be followed by reading the Verilator.cpp
3. Cells in the AST first linked, which will read and parse additional
files as above.
4. Functions, variable and other references are linked to their
4. Functions, variable, and other references are linked to their
definitions.
5. Parameters are resolved and the design is elaborated.
5. Parameters are resolved, and the design is elaborated.
6. Verilator then performs many additional edits and optimizations on
6. Verilator then performs additional edits and optimizations on
the hierarchical design. This includes coverage, assertions, X
elimination, inlining, constant propagation, and dead code
elimination.
@ -56,15 +56,15 @@ The main flow of Verilator can be followed by reading the Verilator.cpp
a single scope and single VarScope for each variable. A module that
occurs twice will have a scope for each occurrence, and two
VarScopes for each variable. This allows optimizations to proceed
across the flattened design, while still preserving the hierarchy.
across the flattened design while still preserving the hierarchy.
8. Additional edits and optimizations proceed on the pseudo-flat
design. These include module references, function inlining, loop
unrolling, variable lifetime analysis, lookup table creation, always
splitting, and logic gate simplifications (pushing inverters, etc).
splitting, and logic gate simplifications (pushing inverters, etc.).
9. Verilator orders the code. Best case, this results in a single
"eval" function which has all always statements flowing from top to
"eval" function, which has all always statements flowing from top to
bottom with no loops.
10. Verilator mostly removes the flattening, so that code may be shared
@ -95,14 +95,14 @@ this.
Each ``AstNode`` has pointers to up to four children, accessed by the
``op1p`` through ``op4p`` methods. These methods are then abstracted in a
specific Ast\* node class to a more specific name. For example with the
specific Ast\* node class to a more specific name. For example, with the
``AstIf`` node (for ``if`` statements), ``thensp`` calls ``op2p`` to give the
pointer to the AST for the "then" block, while ``elsesp`` calls ``op3p`` to
give the pointer to the AST for the "else" block, or NULL if there is not
one. These accessors are automatically generated by ``astgen`` after
parsing the ``@astgen`` directives in the specific ``AstNode`` subclasses.
``AstNode`` has the concept of a next and previous AST - for example the
``AstNode`` has the concept of a next and previous AST - for example, the
next and previous statements in a block. Pointers to the AST for these
statements (if they exist) can be obtained using the ``back`` and ``next``
methods.
@ -114,6 +114,13 @@ you are at the top of the tree.
By convention, each function/method uses the variable ``nodep`` as a
pointer to the ``AstNode`` currently being processed.
There are notable sub-hierarchies of the ``AstNode`` sub-types, namely:
1. All AST nodes representing data types derive from ``AstNodeDType``.
2. All AST nodes representing expressions (i.e.: anything that stands for,
or evaluates to a value) derive from ``AstNodeExpr``.
``VNVisitor``
^^^^^^^^^^^^^^^
@ -129,7 +136,7 @@ the pass.
A number of passes use graph algorithms, and the class ``V3Graph`` is
provided to represent those graphs. Graphs are directed, and algorithms are
provided to manipulate the graphs and to output them in `GraphViz
provided to manipulate the graphs and output them in `GraphViz
<https://www.graphviz.org>`__ dot format. ``V3Graph.h`` provides
documentation of this class.
@ -142,8 +149,8 @@ an associated ``fanout``, ``color`` and ``rank``, which may be used in
algorithms for ordering the graph. A generic ``user``/``userp`` member
variable is also provided.
Virtual methods are provided to specify the name, color, shape and style to
be used in dot output. Typically users provide derived classes from
Virtual methods are provided to specify the name, color, shape, and style
to be used in dot output. Typically users provide derived classes from
``V3GraphVertex`` which will reimplement these methods.
Iterators are provided to access in and out edges. Typically these are used
@ -166,9 +173,9 @@ vertices. Edges have an associated ``weight`` and may also be made
Accessors, ``fromp`` and ``top`` return the "from" and "to" vertices
respectively.
Virtual methods are provided to specify the label, color and style to be
Virtual methods are provided to specify the label, color, and style to be
used in dot output. Typically users provided derived classes from
``V3GraphEdge`` which will reimplement these methods.
``V3GraphEdge``, which will reimplement these methods.
``V3GraphAlg``
@ -176,7 +183,7 @@ used in dot output. Typically users provided derived classes from
This is the base class for graph algorithms. It implements a ``bool``
method, ``followEdge`` which algorithms can use to decide whether an edge
is followed. This method returns true if the graph edge has weight greater
is followed. This method returns true if the graph edge has a weight greater
than one and a user function, ``edgeFuncp`` (supplied in the constructor)
returns ``true``.
@ -187,11 +194,11 @@ provided and documented in ``V3GraphAlg.cpp``.
``DfgGraph``
^^^^^^^^^^^^^
The data-flow graph based combinational logic optimizer (DFG optimizer)
The data-flow graph-based combinational logic optimizer (DFG optimizer)
converts an ``AstModule`` into a ``DfgGraph``. The graph represents the
combinational equations (~continuous assignments) in the module, and for the
duration of the DFG passes, it takes over the role of the represented
``AstModule``. The ``DfgGraph`` keeps holds of the represented ``AstModule``,
``AstModule``. The ``DfgGraph`` keeps hold of the represented ``AstModule``,
and the ``AstModule`` retains all other logic that is not representable as a
data-flow graph. At the end of optimization, the combinational logic
represented by the ``DfgGraph`` is converted back into AST form and is
@ -205,7 +212,7 @@ writing DFG passes easier.
The ``DfgGraph`` represents combinational logic equations as a graph of
``DfgVertex`` vertices. Each sub-class of ``DfgVertex`` corresponds to an
expression (a sub-class of ``AstNodeMath``), a constanat, or a variable
expression (a sub-class of ``AstNodeExpr``), a constant, or a variable
reference. LValues and RValues referencing the same storage location are
represented by the same ``DfgVertex``. Consumers of such vertices read as the
LValue, writers of such vertices write the RValue. The bulk of the final
@ -218,11 +225,11 @@ Scheduling
Verilator implements the Active and NBA regions of the SystemVerilog scheduling
model as described in IEEE 1800-2017 chapter 4, and in particular sections
4.5 and Figure 4.1. The static (verilation time) scheduling of SystemVerilog
4.5 and Figure 4.1. The static (Verilation time) scheduling of SystemVerilog
processes is performed by code in the ``V3Sched`` namespace. The single
entry-point to the scheduling algorithm is ``V3Sched::schedule``. Some
entry point to the scheduling algorithm is ``V3Sched::schedule``. Some
preparatory transformations important for scheduling are also performed in
``V3Active`` and ``V3ActiveTop``. High level evaluation functions are
``V3Active`` and ``V3ActiveTop``. High-level evaluation functions are
constructed by ``V3Order``, which ``V3Sched`` invokes on subsets of the logic
in the design.
@ -260,8 +267,8 @@ The classes of logic we distinguish between are:
below.
- Clocked logic. Any process or construct that has an explicit sensitivity
list, with no implicit sensitivities is considered 'clocked' (or
'sequential') logic. This includes among other things ``always`` and
list, with no implicit sensitivities, is considered 'clocked' (or
'sequential') logic. This includes, among other things ``always`` and
``always_ff`` processes with an explicit sensitivity list.
Note that the distinction between clocked logic and combinational logic is only
@ -314,7 +321,7 @@ At the highest level, ordering is performed by ``V3Order::order``, which is
invoked by ``V3Sched::schedule`` on various subsets of the combinational and
clocked logic as described below. The important thing to highlight now is that
``V3Order::order`` operates by assuming that the state of all variables driven
by combinational logic are consistent with that combinational logic. While this
by combinational logic is consistent with that combinational logic. While this
might seem subtle, it is very important, so here is an example:
::
@ -328,7 +335,7 @@ first, and all downstream combinational logic (like the assignment to ``d``)
will execute after the clocked logic that drives inputs to the combinational
logic, in data-flow (or dependency) order. At the end of the evaluation step,
this ordering restores the invariant that variables driven by combinational
logic are consistent with that combinational logic (i.e.: the circuit is in a
logic are consistent with that combinational logic (i.e., the circuit is in a
settled/steady state).
One of the most important optimizations for performance is to only evaluate
@ -337,12 +344,12 @@ point in evaluating the above assignment to ``d`` on a negative edge of the
clock signal. Verilator does this by pushing the combinational logic into the
same (possibly multiple) event domains as the logic driving the inputs to that
combinational logic, and only evaluating the combinational logic if at least
one driving domains have been triggered. The impact of this activity gating is
one driving domain has been triggered. The impact of this activity gating is
very high (observed 100x slowdown on large designs when turning it off), it is
the reason we prefer to convert clocked logic to combinational logic in
``V3Active`` whenever possible.
The ordering procedure described above works straight forward unless there are
The ordering procedure described above works straightforward unless there are
combinational logic constructs that are circularly dependent (a.k.a.: the
UNOPTFLAT warning). Combinational scheduling loops can arise in sound
(realizable) circuits as Verilator considers each SystemVerilog process as a
@ -362,7 +369,7 @@ To achieve this, ``V3Sched::schedule`` calls ``V3Sched::breakCycles``, which
builds a dependency graph of all combinational logic in the design, and then
breaks all combinational cycles by converting all combinational logic that
consumes a variable driven via a 'back-edge' into hybrid logic. Here
'back-edge' just means a graph edge that points from a higher rank vertex to a
'back-edge' just means a graph edge that points from a higher-rank vertex to a
lower rank vertex in some consistent ranking of the directed graph. Variables
driven via a back-edge in the dependency graph are marked, and all
combinational logic that depends on such variables is converted into hybrid
@ -375,7 +382,7 @@ logic, with two exceptions:
- Explicit sensitivities of hybrid logic are ignored for the purposes of
data-flow ordering with respect to other combinational or hybrid logic. I.e.:
an explicit sensitivity suppresses the implicit sensitivity on the same
variable. This cold also be interpreted as ordering the hybrid logic as if
variable. This could also be interpreted as ordering the hybrid logic as if
all variables listed as explicit sensitivities were substituted as constants
with their current values.
@ -389,7 +396,7 @@ explicit sensitivities are triggered.
The effect of this transformation is that ``V3Order`` can proceed as if there
are no combinational cycles (or alternatively, under the assumption that the
back-edge driven variables don't change during one evaluation pass). The
back-edge-driven variables don't change during one evaluation pass). The
evaluation loop invoking the ordered code, will then re-invoke it on a follow
on iteration, if any of the explicit sensitivities of hybrid logic have
actually changed due to the previous invocation, iterating until all the
@ -415,8 +422,8 @@ combinationally driven variables are consistent with the combinational logic.
To achieve this, we invoke ``V3Order::order`` on all of the combinational and
hybrid logic, and iterate the resulting evaluation function until no more
hybrid logic is triggered. This yields the `_eval_settle` function which is
invoked at the beginning of simulation, after the `_eval_initial`.
hybrid logic is triggered. This yields the `_eval_settle` function, which is
invoked at the beginning of simulation after the `_eval_initial`.
Partitioning logic for correct NBA updates
@ -425,17 +432,17 @@ Partitioning logic for correct NBA updates
``V3Order`` can order logic corresponding to non-blocking assignments (NBAs) to
yield correct simulation results, as long as all the sensitivity expressions of
clocked logic triggered in the Active scheduling region of the current time
step are known up front. I.e.: the ordering of NBA updates is only correct if
step are known up front. I.e., the ordering of NBA updates is only correct if
derived clocks that are computed in an Active region update (that is, via a
blocking or continuous assignment) are known up front.
We can ensure this by partitioning the logic into two regions. Note these
regions are a concept of the Verilator scheduling algorithm and they do not
regions are a concept of the Verilator scheduling algorithm, and they do not
directly correspond to the similarly named SystemVerilog scheduling regions
as defined in the standard:
- All logic (clocked, combinational and hybrid) that transitively feeds into,
or drives, via a non-blocking or continuous assignments (or via any update
or drives via a non-blocking or continuous assignments (or via any update
that SystemVerilog executes in the Active scheduling region), a variable that
is used in the explicit sensitivity list of some clocked or hybrid logic, is
assigned to the 'act' region.
@ -443,10 +450,10 @@ as defined in the standard:
- All other logic is assigned to the 'nba' region.
For completeness, note that a subset of the 'act' region logic, specifically,
the logic related to the pre-assignments of NBA updates (i.e.: AstAssignPre
the logic related to the pre-assignments of NBA updates (i.e., AstAssignPre
nodes), is handled separately, but is executed as part of the 'act' region.
Also note that all logic representing the committing of an NBA (i.e.: Ast*Post)
Also note that all logic representing the committing of an NBA (i.e., Ast*Post)
nodes) will be in the 'nba' region. This means that the evaluation of the 'act'
region logic will not commit any NBA updates. As a result, the 'act' region
logic can be iterated to compute all derived clock signals up front.
@ -455,7 +462,7 @@ The correspondence between the SystemVerilog Active and NBA scheduling regions,
and the internal 'act' and 'nba' regions, is that 'act' contains all Active
region logic that can compute a clock signal, while 'nba' contains all other
Active and NBA region logic. For example, if the only clocks in the design are
top level inputs, then 'act' will be empty, and 'nba' will contain the whole of
top-level inputs, then 'act' will be empty, and 'nba' will contain the whole of
the design.
The partitioning described above is performed by ``V3Sched::partition``.
@ -468,10 +475,10 @@ We will separately invoke ``V3Order::order`` on the 'act' and 'nba' region
logic.
Combinational logic that reads variables driven from both 'act' and 'nba'
region logic has the problem of needing to be re-evaluated even if only one of
region logic has the problem of needing to be reevaluated even if only one of
the regions updates an input variable. We could pass additional trigger
expressions between the regions to make sure combinational logic is always
re-evaluated, or we can replicate combinational logic that is driven from
reevaluated, or we can replicate combinational logic that is driven from
multiple regions, by copying it into each region that drives it. Experiments
show this simple replication works well performance-wise (and notably
``V3Combine`` is good at combining the replicated code), so this is what we do
@ -499,7 +506,7 @@ the top level `_eval` function, which on the high level has the form:
::
void _eval() {
// Update combinational logic dependent on top level inptus ('ico' region)
// Update combinational logic dependent on top level inputs ('ico' region)
while (true) {
_eval__triggers__ico();
// If no 'ico' region trigger is active
@ -527,7 +534,7 @@ the top level `_eval` function, which on the high level has the form:
// If no 'nba' region trigger is active
if (!nba_triggers.any()) break;
// Evaluate all other Active region logic, and commti NBAs
// Evaluate all other Active region logic, and commit NBAs
_eval_nba();
}
}
@ -621,7 +628,7 @@ coroutines ``co_await`` its ``join`` function, and forked ones call ``done``
when they're finished. Once the required number of coroutines (set using
``setCounter``) finish execution, the forking coroutine is resumed.
Awaitable utilities
Awaitable Utilities
^^^^^^^^^^^^^^^^^^^
There are also two small utility awaitable types:
@ -632,7 +639,7 @@ There are also two small utility awaitable types:
* ``VlForever`` is used for blocking a coroutine forever. See the `Timing pass`
section for more detail.
Timing pass
Timing Pass
^^^^^^^^^^^
The visitor in ``V3Timing.cpp`` transforms each timing control into a ``co_await``.
@ -661,7 +668,7 @@ before them and stored in temporary variables.
and then await changes in variables used in the condition. If the condition is
always false, the ``wait`` statement is replaced by a ``co_await`` on a
``VlForever``. This is done instead of a return in case the ``wait`` is deep in
a call stack (otherwise the coroutine's caller would continue execution).
a call stack (otherwise, the coroutine's caller would continue execution).
Each sub-statement of a ``fork`` is put in an ``AstBegin`` node for easier
grouping. In a later step, each of these gets transformed into a new, separate
@ -741,7 +748,7 @@ doesn't suspend the forking process.
In forked processes, references to local variables are only allowed in
``fork..join``, as this is the only case that ensures the lifetime of these
locals is at least as long as the execution of the forked processes. This is
locals are at least as long as the execution of the forked processes. This is
where ``VlNow`` is used, to ensure the locals are moved to the heap before they
are passed by reference to the forked processes.
@ -763,7 +770,7 @@ graph, while maintaining as much available parallelism as possible. Often
the partitioner can transform an input graph with millions of nodes into a
coarsened execution graph with a few dozen nodes, while maintaining enough
parallelism to take advantage of a modern multicore CPU. Runtime
synchronization cost is not prohibitive with so few nodes.
synchronization cost is reasonable with so few nodes.
Partitioning
@ -782,7 +789,7 @@ The available parallelism or "par-factor" of a DAG is the total cost to
execute all nodes, divided by the cost to execute the longest critical path
through the graph. This is the speedup you would get from running the graph
in parallel, if given infinite CPU cores available and communication and
synchronization are zero.
synchronization is zero.
Macro Task
@ -840,7 +847,7 @@ synchronization costs.
Verilator's cost estimates are assigned by ``InstrCountVisitor``. This
class is perhaps the most fragile piece of the multithread
implementation. It's easy to have a bug where you count something cheap
(eg. accessing one element of a huge array) as if it were expensive (eg.
(e.g. accessing one element of a huge array) as if it were expensive (eg.
by counting it as if it were an access to the entire array.) Even without
such gross bugs, the estimates this produce are only loosely predictive of
actual runtime cost. Multithread performance would be better with better
@ -872,13 +879,13 @@ fragmentation.
Locating Variables for Best Spatial Locality
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
After scheduling all code, we attempt to locate variables in memory such
After scheduling all code, we attempt to locate variables in memory, such
that variables accessed by a single macro-task are close together in
memory. This provides "spatial locality" - when we pull in a 64-byte cache
line to access a 2-byte variable, we want the other 62 bytes to be ones
we'll also likely access soon, for best cache performance.
This turns out to be critical for performance. It should allow Verilator
This is critical for performance. It should allow Verilator
to scale to very large models. We don't rely on our working set fitting
in any CPU cache; instead we essentially "stream" data into caches from
memory. It's not literally streaming, where the address increases
@ -897,7 +904,7 @@ The footprint ordering is literally the traveling salesman problem, and
we use a TSP-approximation algorithm to get close to an optimal sort.
This is an old idea. Simulators designed at DEC in the early 1990s used
similar techniques to optimize both single-thread and multi-thread
similar techniques to optimize both single-thread and multithread
modes. (Verilator does not optimize variable placement for spatial
locality in serial mode; that is a possible area for improvement.)
@ -911,7 +918,7 @@ Wave Scheduling
To allow the Verilated model to run in parallel with the testbench, it
might be nice to support "wave" scheduling, in which work on a cycle begins
before ``eval()`` is called or continues after ``eval()`` returns. For now
before ``eval()`` is called or continues after ``eval()`` returns. For now,
all work on a cycle happens during the ``eval()`` call, leaving Verilator's
threads idle while the testbench (everything outside ``eval()``) is
working. This would involve fundamental changes within the partitioner,
@ -922,7 +929,7 @@ Efficient Dynamic Scheduling
""""""""""""""""""""""""""""
To scale to more than a few threads, we may revisit a fully dynamic
scheduler. For large (>16 core) systems it might make sense to dedicate an
scheduler. For large (>16 core) systems, it might make sense to dedicate an
entire core to scheduling, so that scheduler data structures would fit in
its L1 cache and thus the cost of traversing priority-ordered ready lists
would not be prohibitive.
@ -976,7 +983,7 @@ Performance Regression
""""""""""""""""""""""
It would be nice if we had a regression of large designs, with some
diversity of design styles, to test on both single- and multi-threaded
diversity of design styles, to test on both single- and multithreaded
modes. This would help to avoid performance regressions, and also to
evaluate the optimizations while minimizing the impact of parasitic noise.
@ -985,9 +992,9 @@ Per-Instance Classes
""""""""""""""""""""
If we have multiple instances of the same module, and they partition
differently (likely; we make no attempt to partition them the same) then
differently (likely; we make no attempt to partition them the same), then
the variable sort will be suboptimal for either instance. A possible
improvement would be to emit a unique class for each instance of a module,
improvement would be to emit an unique class for each instance of a module,
and sort its variables optimally for that instance's code stream.
@ -1004,17 +1011,17 @@ until all signals are stable.
On other evaluations, the Verilated code detects what input signals have
changes. If any are clocks, it calls the appropriate sequential functions
(from ``always @ posedge`` statements). Interspersed with sequential
functions it calls combo functions (from ``always @*``). After this is
functions, it calls combo functions (from ``always @*``). After this is
complete, it detects any changes due to combo loops or internally generated
clocks, and if one is found must reevaluate the model again.
For SystemC code, the ``eval()`` function is wrapped in a SystemC
``SC_METHOD``, sensitive to all inputs. (Ideally it would only be sensitive
``SC_METHOD``, sensitive to all inputs. (Ideally, it would only be sensitive
to clocks and combo inputs, but tracing requires all signals to cause
evaluation, and the performance difference is small.)
If tracing is enabled, a callback examines all variables in the design for
changes, and writes the trace for each change. To accelerate this process
changes, and writes the trace for each change. To accelerate this process,
the evaluation process records a bitmask of variables that might have
changed; if clear, checking those signals for changes may be skipped.
@ -1038,7 +1045,7 @@ is appreciated if you could match our style:
- Use "mixedCapsSymbols" instead of "underlined_symbols".
- Uas a "p" suffix on variables that are pointers, e.g. "nodep".
- Use a "p" suffix on variables that are pointers, e.g., "nodep".
- Comment every member variable.
@ -1050,12 +1057,12 @@ using clang-format version 10.0.0, and yapf for python, and is
automatically corrected in the CI actions. For those manually formatting C
code:
- Use 4 spaces per level, and no tabs.
- Use four spaces per level, and no tabs.
- Use 2 spaces between the end of source and the beginning of a
- Use two spaces between the end of source and the beginning of a
comment.
- Use 1 space after if/for/switch/while and similar keywords.
- Use one space after if/for/switch/while and similar keywords.
- No spaces before semicolons, nor between a function's name and open
parenthesis (only applies to functions; if/else has a following space).
@ -1066,8 +1073,8 @@ The ``astgen`` Script
The ``astgen`` script is used to generate some of the repetitive C++ code
related to the ``AstNode`` type hierarchy. An example is the abstract ``visit``
methods in ``VNVisitor``. There are other uses, please see the ``*__gen*``
files in the bulid directories and the ``astgen`` script itself for details. A
methods in ``VNVisitor``. There are other uses; please see the ``*__gen*``
files in the bulid directories and the ``astgen`` script for details. A
description of the more advanced features of ``astgen`` are provided here.
@ -1092,7 +1099,7 @@ sub-class definitions are parsed and contribute to the code generated by
``astgen``. The general syntax is ``@astgen <keywords> := <description>``,
where ``<keywords>`` determines what is being defined, and ``<description>`` is
a ``<keywords>`` dependent description of the definition. The list of
``@astgen`` directives is as follows:
``@astgen`` directives are as follows:
``op<N>`` operand directives
@ -1117,11 +1124,11 @@ will be used as the base name of the generated operand accessors, and
An example of the full syntax of the directive is
``@astgen op1 := lhsp : AstNodeMath``.
``@astgen op1 := lhsp : AstNodeExpr``.
``astnode`` generates accessors for the child nodes based on these directives.
For non-list children, the names of the getter and setter both are that of the
given ``<identifier>``. For list type children, the getter is ``<identifier>``,
given ``<identifier>``. For list-type children, the getter is ``<identifier>``,
and instead of the setter, there an ``add<Identifier>`` method is generated
that appends new nodes (or lists of nodes) to the child list.
@ -1178,10 +1185,10 @@ and applies the visit method of the ``VNVisitor`` to the invoking AstNode
instance (i.e. ``this``).
One possible difficulty is that a call to ``accept`` may perform an edit
which destroys the node it receives as argument. The
which destroys the node it receives as an argument. The
``acceptSubtreeReturnEdits`` method of ``AstNode`` is provided to apply
``accept`` and return the resulting node, even if the original node is
destroyed (if it is not destroyed it will just return the original node).
destroyed (if it is not destroyed, it will just return the original node).
The behavior of the visitor classes is achieved by overloading the
``visit`` function for the different ``AstNode`` derived classes. If a
@ -1205,7 +1212,7 @@ There are three ways data is passed between visitor functions.
it's cleared. Children under an ``AstModule`` will see it set, while
nodes elsewhere will see it clear. If there can be nested items (for
example an ``AstFor`` under an ``AstFor``) the variable needs to be
save-set-restored in the ``AstFor`` visitor, otherwise exiting the
save-set-restored in the ``AstFor`` visitor; otherwise exiting the
lower for will lose the upper for's setting.
2. User attributes. Each ``AstNode`` (**Note.** The AST node, not the
@ -1236,14 +1243,14 @@ There are three ways data is passed between visitor functions.
These comments are important to make sure a ``user#()`` on a given
``AstNode`` type is never being used for two different purposes.
Note that calling ``user#ClearTree`` is fast, it doesn't walk the
Note that calling ``user#ClearTree`` is fast; it doesn't walk the
tree, so it's ok to call fairly often. For example, it's commonly
called on every module.
3. Parameters can be passed between the visitors in close to the
"normal" function caller to callee way. This is the second ``vup``
parameter of type ``AstNUser`` that is ignored on most of the visitor
functions. V3Width does this, but it proved more messy than the above
functions. V3Width does this, but it proved messier than the above
and is deprecated. (V3Width was nearly the first module written.
Someday this scheme may be removed, as it slows the program down to
have to pass vup everywhere.)
@ -1298,7 +1305,7 @@ change. For example:
iterateAndNextNull(nodep->lhsp());
Will work fine, as even if the first iterate causes a new node to take
the place of the ``lhsp()``, that edit will update ``nodep->lhsp()`` and
the place of the ``lhsp()``, that edit will update ``nodep->lhsp()``, and
the second call will correctly see the change. Alternatively:
::
@ -1311,8 +1318,8 @@ the second call will correctly see the change. Alternatively:
This will cause bugs or a core dump, as lp is a dangling pointer. Thus
it is advisable to set lhsp=NULL shown in the \*'s above to make sure
these dangles are avoided. Another alternative used in special cases
mostly in V3Width is to use acceptSubtreeReturnEdits, which operates on
these dangles are avoided. Another alternative used in special cases,
mostly in V3Width, is to use acceptSubtreeReturnEdits, which operates on
a single node and returns the new pointer if any. Note
acceptSubtreeReturnEdits does not follow ``nextp()`` links.
@ -1325,7 +1332,7 @@ Identifying Derived Classes
---------------------------
A common requirement is to identify the specific ``AstNode`` class we
are dealing with. For example a visitor might not implement separate
are dealing with. For example, a visitor might not implement separate
``visit`` methods for ``AstIf`` and ``AstGenIf``, but just a single
method for the base class:
@ -1348,7 +1355,7 @@ use:
Additionally the ``VN_CAST`` method converts pointers similar to C++
``dynamic_cast``. This either returns a pointer to the object cast to
that type (if it is of class ``SOMETYPE``, or a derived class of
``SOMETYPE``) or else NULL. (However, for true/false tests use ``VN_IS``
``SOMETYPE``) or else NULL. (However, for true/false tests, use ``VN_IS``
as that is faster.)
@ -1357,13 +1364,13 @@ as that is faster.)
Testing
=======
For an overview of how to write a test see the BUGS section of the
For an overview of how to write a test, see the BUGS section of the
`Verilator Manual <https://verilator.org/verilator_doc.html>`_.
It is important to add tests for failures as well as success (for
example to check that an error message is correctly triggered).
Tests that fail should by convention have the suffix ``_bad`` in their
Tests that fail should, by convention have the suffix ``_bad`` in their
name, and include ``fails = 1`` in either their ``compile`` or
``execute`` step as appropriate.
@ -1371,11 +1378,11 @@ name, and include ``fails = 1`` in either their ``compile`` or
Preparing to Run Tests
----------------------
For all tests to pass you must install the following packages:
For all tests to pass, you must install the following packages:
- SystemC to compile the SystemC outputs, see http://systemc.org
- Parallel::Forker from CPAN to run tests in parallel, you can install
- Parallel::Forker from CPAN to run tests in parallel; you can install
this with e.g. "sudo cpan install Parallel::Forker".
- vcddiff to find differences in VCD outputs. See the readme at
@ -1410,9 +1417,9 @@ This can be changed using the ``top_filename`` subroutine, for example
top_filename("t/t_myothertest.v");
By default all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim, etc) as well as Verilator, to allow results to be
compared. However if you wish a test only to be used with Verilator, you
By default, all tests will run with major simulators (Icarus Verilog, NC,
VCS, ModelSim, etc.) as well as Verilator, to allow results to be
compared. However, if you wish a test only to be used with Verilator, you
can use the following:
::
@ -1428,7 +1435,7 @@ Of the many options that can be set through arguments to ``compiler`` and
``fails``
Set to 1 to indicate that the compilation or execution is intended to fail.
For example the following would specify that compilation requires two
For example, the following would specify that compilation requires two
defines and is expected to fail.
::
@ -1445,15 +1452,15 @@ Regression Testing for Developers
Developers will also want to call ./configure with two extra flags:
``--enable-ccwarn``
Causes the build to stop on warnings as well as errors. A good way to
ensure no sloppy code gets added, however it can be painful when it
This causes the build to stop on warnings as well as errors. A good way
to ensure no sloppy code gets added; however it can be painful when it
comes to testing, since third party code used in the tests (e.g.
SystemC) may not be warning free.
``--enable-longtests``
In addition to the standard C, SystemC examples, also run the tests
in the ``test_regress`` directory when using *make test*'. This is
disabled by default as SystemC installation problems would otherwise
disabled by default, as SystemC installation problems would otherwise
falsely indicate a Verilator problem.
When enabling the long tests, some additional PERL modules are needed,
@ -1470,7 +1477,7 @@ There are some traps to avoid when running regression tests
- Not all Linux systems install Perldoc by default. This is needed for the
``--help`` option to Verilator, and also for regression testing. This
can be installed using cpan:
can be installed using CPAN:
::
@ -1482,8 +1489,8 @@ There are some traps to avoid when running regression tests
- Running regression may exhaust resources on some Linux systems,
particularly file handles and user processes. Increase these to
respectively 16,384 and 4,096. The method of doing this is system
dependent, but on Fedora Linux it would require editing the
respectively 16,384 and 4,096. The method of doing this is
system-dependent, but on Fedora Linux it would require editing the
``/etc/security/limits.conf`` file as root.
@ -1503,7 +1510,7 @@ Continuous Integration
Verilator uses GitHub Actions which automatically tests the master branch
for test failures on new commits. It also runs a daily cron job to validate
all of the tests against different OS and compiler versions.
all tests against different OS and compiler versions.
Developers can enable Actions on their GitHub repository so that the CI
environment can check their branches too by enabling the build workflow:
@ -1548,7 +1555,7 @@ debug level 5, with the V3Width.cpp file at level 9.
--debug
-------
When you run with ``--debug`` there are two primary output file types
When you run with ``--debug``, there are two primary output file types
placed into the obj_dir, .tree and .dot files.
@ -1565,7 +1572,7 @@ output, for example:
dot -Tps -o ~/a.ps obj_dir/Vtop_foo.dot
You can then print a.ps. You may prefer gif format, which doesn't get
scaled so can be more useful with large graphs.
scaled so it can be more useful with large graphs.
For interactive graph viewing consider `xdot
<https://github.com/jrfonseca/xdot.py>`__ or `ZGRViewer
@ -1610,21 +1617,21 @@ field in the section below.
+---------------+--------------------------------------------------------+
| ``w32`` | The data-type width() is 32 bits. |
+---------------+--------------------------------------------------------+
| ``out_wide`` | The name() of the node, in this case the name of the |
| ``out_wide`` | The name() of the node, in this case, the name of the |
| | variable. |
+---------------+--------------------------------------------------------+
| ``[O]`` | Flags which vary with the type of node, in this |
| | case it means the variable is an output. |
| | case, it means the variable is an output. |
+---------------+--------------------------------------------------------+
In more detail the following fields are dumped common to all nodes. They
In more detail, the following fields are dumped common to all nodes. They
are produced by the ``AstNode::dump()`` method:
Tree Hierarchy
The dump lines begin with numbers and colons to indicate the child
node hierarchy. As noted above, ``AstNode`` has lists of items at the
same level in the AST, connected by the ``nextp()`` and ``prevp()``
pointers. These appear as nodes at the same level. For example after
pointers. These appear as nodes at the same level. For example, after
inlining:
::
@ -1648,20 +1655,20 @@ Address of the node
with the debugger. If the actual address values are not important,
then using the ``--dump-tree-addrids`` option will convert address
values to short identifiers of the form ``([A-Z]*)``, which is
hopefully easier for the reader to cross reference throughout the
hopefully easier for the reader to cross-reference throughout the
dump.
Last edit number
Of the form ``<ennnn>`` or ``<ennnn#>`` , where ``nnnn`` is the
number of the last edit to modify this node. The trailing ``#``
indicates the node has been edited since the last tree dump (which
typically means in the last refinement or optimization pass). GDB can
watch for this, see << /Debugging >>.
indicates the node has been edited since the last tree dump
(typically in the last refinement or optimization pass). GDB can
watch for this; see << /Debugging >>.
Source file and line
Of the form ``{xxnnnn}``, where C{xx} is the filename letter (or
letters) and ``nnnn`` is the line number within that file. The first
file is ``a``, the 26th is ``z``, the 27th is ``aa`` and so on.
file is ``a``, the 26th is ``z``, the 27th is ``aa``, and so on.
User pointers
Shows the value of the node's user1p...user5p, if non-NULL.
@ -1676,7 +1683,7 @@ Data type
- ``s`` if the node is signed.
- ``d`` if the node is a double (i.e a floating point entity).
- ``d`` if the node is a double (i.e. a floating point entity).
- ``w`` always present, indicating this is the width field.
@ -1686,9 +1693,9 @@ Data type
width.
Name of the entity represented by the node if it exists
For example for a ``VAR`` it is the name of the variable.
For example, for a ``VAR`` is the name of the variable.
Many nodes follow these fields with additional node specific
Many nodes follow these fields with additional node-specific
information. Thus the ``VARREF`` node will print either ``[LV]`` or
``[RV]`` to indicate a left value or right value, followed by the node
of the variable being referred to. For example:
@ -1703,7 +1710,7 @@ type in question to determine additional fields that may be printed.
The ``MODULE`` has a list of ``CELLINLINE`` nodes referred to by its
``op1p()`` pointer, connected by ``nextp()`` and ``prevp()`` pointers.
Similarly the ``NETLIST`` has a list of modules referred to by its
Similarly, the ``NETLIST`` has a list of modules referred to by its
``op1p()`` pointer.
@ -1721,7 +1728,7 @@ Debugging with GDB
------------------
The test_regress/driver.pl script accepts ``--debug --gdb`` to start
Verilator under gdb and break when an error is hit or the program is about
Verilator under gdb and break when an error is hit, or the program is about
to exit. You can also use ``--debug --gdbbt`` to just backtrace and then
exit gdb. To debug the Verilated executable, use ``--gdbsim``.
@ -1798,7 +1805,7 @@ backtrace. You will typically see a frame sequence something like:
Adding a New Feature
====================
Generally what would you do to add a new feature?
Generally, what would you do to add a new feature?
1. File an issue (if there isn't already) so others know what you're
working on.
@ -1816,7 +1823,7 @@ Generally what would you do to add a new feature?
Ordering of definitions is enforced by ``astgen``.
5. Now you can run "test_regress/t/t_<newtestcase>.pl --debug" and it'll
probably fail but you'll see a
probably fail, but you'll see a
"test_regress/obj_dir/t_<newtestcase>/*.tree" file which you can examine
to see if the parsing worked. See also the sections above on debugging.
@ -1826,12 +1833,12 @@ Generally what would you do to add a new feature?
Adding a New Pass
-----------------
For more substantial changes you may need to add a new pass. The simplest
For more substantial changes, you may need to add a new pass. The simplest
way to do this is to copy the ``.cpp`` and ``.h`` files from an existing
pass. You'll need to add a call into your pass from the ``process()``
function in ``src/verilator.cpp``.
To get your pass to build you'll need to add its binary filename to the
To get your pass to build, you'll need to add its binary filename to the
list in ``src/Makefile_obj.in`` and reconfigure.
@ -1847,11 +1854,9 @@ IEEE 1800-2017 3.3 modules within modules
IEEE 1800-2017 6.12 "shortreal"
Little/no tool support, and easily promoted to real.
IEEE 1800-2017 11.11 Min, typ, max
No SDF support so will always use typical.
No SDF support, so will always use typical.
IEEE 1800-2017 11.12 "let"
Little/no tool support, makes difficult to implement parsers.
IEEE 1800-2017 20.15 Probabilistic functions
Little industry use.
Little/no tool support, makes it difficult to implement parsers.
IEEE 1800-2017 20.16 Stochastic analysis
Little industry use.
IEEE 1800-2017 20.17 PLA modeling

View File

@ -45,6 +45,7 @@ Cochrane
Cuan
Cygwin
DErrico
DFG
Da
Danilo
Dannoritzer
@ -225,6 +226,7 @@ Nalbantis
Narayan
Nauticus
Newgard
Nigam
Nikana
Niranjan
Nitza
@ -239,6 +241,7 @@ Patricio
Petr
Piechotka
Piersall
Platzer
Plunkett
Popolon
Popov
@ -253,6 +256,7 @@ Pullup
Pulver
Puri
Questa
Rachit
Ralf
Rapp
Redhat
@ -383,6 +387,7 @@ agrobman
ahouska
al
ala
alejandro
algrobman
andit
ar
@ -407,7 +412,6 @@ biguint
biops
bisonpre
bitOpTree
bitOpTree
bitop
bitstoreal
blackbox
@ -422,6 +426,7 @@ callValueCbs
casex
casez
casted
castro
cb
ccache
ccall
@ -462,6 +467,7 @@ cutable
cygwin
dM
da
danbone
dat
datadir
datafiles
@ -590,6 +596,7 @@ hierCMakeArgs
hierMkArgs
hierVer
hx
hyperthreading
hyperthreads
icecream
idmap
@ -600,6 +607,7 @@ ifndef
impot
incdir
includer
incrementing
inferfaces
inhibitSim
initarray
@ -640,6 +648,7 @@ localparams
localtime
logicals
longint
lossy
lsb
lvalue
lxt
@ -649,6 +658,7 @@ makefiles
manpages
metacomment
metacomments
miree
mis
misconnected
misconversion
@ -657,6 +667,7 @@ mk
mno
modport
modports
mpb
msg
msvc
mtask
@ -696,6 +707,7 @@ nullptr
onehot
ooo
oprofile
ortegon
oversubscription
parallelized
param
@ -748,6 +760,7 @@ pwd
qrq
radix
randc
randcase
rarr
rdtsc
reStructuredText

View File

@ -37,5 +37,4 @@ PREDEFINED = \
"VL_NOT_FINAL=" \
"VL_PURE=" \
"VL_REQUIRES()=" \
"VL_THREAD_LOCAL=" \
"__restrict=" \

View File

@ -11,19 +11,20 @@
// Include model header, generated from Verilating "top.v"
#include "Vtop.h"
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
// See a similar example walkthrough in the verilator manpage.
// This is intended to be a minimal example. Before copying this to start a
// real project, it is better to start with a more complete example,
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (false && argc && argv && env) {}
// Construct a VerilatedContext to hold simulation time, etc.
VerilatedContext* contextp = new VerilatedContext;
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
contextp->commandArgs(argc, argv);
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop{contextp};

View File

@ -22,12 +22,13 @@ int sc_main(int argc, char* argv[]) {
// real project, it is better to start with a more complete example,
// e.g. examples/c_tracing.
// Prevent unused variable warnings
if (false && argc && argv) {}
// Construct the Verilated model, from Vtop.h generated from Verilating "top.v"
Vtop* top = new Vtop{"top"};
// Pass arguments so Verilated code can see them, e.g. $value$plusargs
// This needs to be called before you create any model
Verilated::commandArgs(argc, argv);
// Initialize SC model
sc_start(1, SC_NS);

View File

@ -16,8 +16,8 @@
#include <verilated_vcd_c.h>
#endif
int main(int argc, char** argv, char** env) {
if (false && argc && argv && env) {}
int main(int argc, char** argv) {
if (false && argc && argv) {}
// Construct context to hold simulation time, etc
VerilatedContext* contextp = new VerilatedContext;

View File

@ -17,11 +17,11 @@
// Legacy function required only so linking works on Cygwin and MSVC++
double sc_time_stamp() { return 0; }
int main(int argc, char** argv, char** env) {
int main(int argc, char** argv) {
// This is a more complicated example, please also see the simpler examples/make_hello_c.
// Prevent unused variable warnings
if (false && argc && argv && env) {}
if (false && argc && argv) {}
// Create logs/ directory in case we have traces to put under it
Verilated::mkdir("logs");

View File

@ -90,7 +90,7 @@ int sc_main(int argc, char* argv[]) {
VerilatedVcdSc* tfp = nullptr;
const char* flag = Verilated::commandArgsPlusMatch("trace");
if (flag && 0 == std::strcmp(flag, "+trace")) {
cout << "Enabling waves into logs/vlt_dump.vcd...\n";
std::cout << "Enabling waves into logs/vlt_dump.vcd...\n";
tfp = new VerilatedVcdSc;
top->trace(tfp, 99); // Trace 99 levels of hierarchy
Verilated::mkdir("logs");

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- Python -*- See copyright, etc below
# pylint: disable=C0114,C0115,R0903
# pylint: disable=C0114,C0115,C0209,R0903
######################################################################
import argparse
@ -20,24 +20,22 @@ class VlFileCopy:
def __init__(
self,
verilator_args, # presently all verilator options are passed-thru
# ideally this script would check against options mentioned in help
debug=0,
debug=0,
output_dir='copied'): # directory name we output file uses
self.debug = debug
xml_temp = tempfile.NamedTemporaryFile()
vargs = [
'--xml-output',
xml_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
with tempfile.NamedTemporaryFile() as xml_temp:
vargs = [
'--xml-output',
xml_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
os.makedirs(output_dir, 0o777, True)

View File

@ -1,6 +1,6 @@
#!/usr/bin/env python3
# -*- Python -*- See copyright, etc below
# pylint: disable=C0103,C0114,C0115,C0115,C0116,R0914
# pylint: disable=C0103,C0114,C0115,C0115,C0116,C0209,R0914
######################################################################
import argparse
@ -18,27 +18,25 @@ class VlHierGraph:
def __init__(
self,
verilator_args, # presently all verilator options are passed-thru
# ideally this script would check against options mentioned in help
debug=0,
debug=0,
output_filename='graph.dot'): # output filename
self.debug = debug
self.next_vertex_number = 0
self.name_to_number = {}
xml_temp = tempfile.NamedTemporaryFile()
with tempfile.NamedTemporaryFile() as xml_temp:
vargs = [
'--xml-output',
xml_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
vargs = [
'--xml-output',
xml_temp.name,
'--bbox-sys', # Parse some stuff can't translate
'--bbox-unsup',
'--prefix vlxml'
] # So we know name of .xml output
vargs += verilator_args
self.run_verilator(vargs)
self.tree = ET.parse(xml_temp.name)
with open(output_filename, "w") as fh:
with open(output_filename, "w", encoding="utf8") as fh:
# For more serious purposes, use the python graphviz package instead
fh.write("digraph {\n")
fh.write(" dpi=300;\n")

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2009-2018 Tony Bybell.
* Copyright (c) 2009-2023 Tony Bybell.
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
@ -4130,26 +4130,35 @@ if(xc->do_rewind)
if(!(isfeof=feof(xc->fh)))
{
int tag = fgetc(xc->fh);
int cl;
switch(tag)
{
case FST_ST_VCD_SCOPE:
xc->hier.htyp = FST_HT_SCOPE;
xc->hier.u.scope.typ = fgetc(xc->fh);
xc->hier.u.scope.name = pnt = xc->str_scope_nam;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
}; /* scopename */
*pnt = 0;
xc->hier.u.scope.name_length = pnt - xc->hier.u.scope.name;
pnt[cl] = 0;
xc->hier.u.scope.name_length = cl;
xc->hier.u.scope.component = pnt = xc->str_scope_comp;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
}; /* scopecomp */
*pnt = 0;
xc->hier.u.scope.component_length = pnt - xc->hier.u.scope.component;
pnt[cl] = 0;
xc->hier.u.scope.component_length = cl;
break;
case FST_ST_VCD_UPSCOPE:
@ -4161,12 +4170,16 @@ if(!(isfeof=feof(xc->fh)))
xc->hier.u.attr.typ = fgetc(xc->fh);
xc->hier.u.attr.subtype = fgetc(xc->fh);
xc->hier.u.attr.name = pnt = xc->str_scope_nam;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
}; /* scopename */
*pnt = 0;
xc->hier.u.attr.name_length = pnt - xc->hier.u.scope.name;
pnt[cl] = 0;
xc->hier.u.attr.name_length = cl;
xc->hier.u.attr.arg = fstReaderVarint64(xc->fh);
@ -4221,12 +4234,16 @@ if(!(isfeof=feof(xc->fh)))
xc->hier.u.var.typ = tag;
xc->hier.u.var.direction = fgetc(xc->fh);
xc->hier.u.var.name = pnt = xc->str_scope_nam;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_SIZ)
{
pnt[cl++] = ch;
}
}; /* varname */
*pnt = 0;
xc->hier.u.var.name_length = pnt - xc->hier.u.var.name;
pnt[cl] = 0;
xc->hier.u.var.name_length = cl;
xc->hier.u.var.length = fstReaderVarint32(xc->fh);
if(tag == FST_VT_VCD_PORT)
{
@ -4273,6 +4290,7 @@ unsigned int num_signal_dyn = 65536;
int attrtype, subtype;
uint64_t attrarg;
fstHandle maxhandle_scanbuild;
int cl;
if(!xc) return(0);
@ -4355,11 +4373,15 @@ while(!feof(xc->fh))
scopetype = fgetc(xc->fh);
if((scopetype < FST_ST_MIN) || (scopetype > FST_ST_MAX)) scopetype = FST_ST_VCD_MODULE;
pnt = str;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
}; /* scopename */
*pnt = 0;
pnt[cl] = 0;
while(fgetc(xc->fh)) { }; /* scopecomp */
if(fv) fprintf(fv, "$scope %s %s $end\n", modtypes[scopetype], str);
@ -4373,11 +4395,15 @@ while(!feof(xc->fh))
attrtype = fgetc(xc->fh);
subtype = fgetc(xc->fh);
pnt = str;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
}; /* attrname */
*pnt = 0;
pnt[cl] = 0;
if(!str[0]) { strcpy(str, "\"\""); }
@ -4458,11 +4484,15 @@ while(!feof(xc->fh))
vartype = tag;
/* vardir = */ fgetc(xc->fh); /* unused in VCD reader, but need to advance read pointer */
pnt = str;
cl = 0;
while((ch = fgetc(xc->fh)))
{
*(pnt++) = ch;
if(cl <= FST_ID_NAM_ATTR_SIZ)
{
pnt[cl++] = ch;
}
}; /* varname */
*pnt = 0;
pnt[cl] = 0;
len = fstReaderVarint32(xc->fh);
alias = fstReaderVarint32(xc->fh);

View File

@ -27,7 +27,7 @@
//
// verilated.o may exist both in --lib-create (incrementally linked .a/.so)
// and the main module. Both refer the same instance of static
// variables/VL_THREAD_LOCAL in verilated.o such as Verilated, or
// variables/thread_local in verilated.o such as Verilated, or
// VerilatedImpData. This is important to share that state, but the
// sharing may cause a double-free error when shutting down because the
// loader will insert a constructor/destructor at each reference to
@ -67,10 +67,12 @@
#if defined(_WIN32) || defined(__MINGW32__)
# include <direct.h> // mkdir
#endif
#ifdef VL_THREADED
# include "verilated_threads.h"
#ifdef __linux__
# include <execinfo.h>
# define _VL_HAVE_STACKTRACE
#endif
#include "verilated_threads.h"
// clang-format on
#include "verilated_trace.h"
@ -96,7 +98,7 @@ VerilatedContext* Verilated::s_lastContextp = nullptr;
// Keep below together in one cache line
// Internal note: Globals may multi-construct, see verilated.cpp top.
VL_THREAD_LOCAL Verilated::ThreadLocal Verilated::t_s;
thread_local Verilated::ThreadLocal Verilated::t_s;
//===========================================================================
// User definable functions
@ -193,43 +195,27 @@ void vl_warn(const char* filename, int linenum, const char* hier, const char* ms
// Wrapper to call certain functions via messages when multithreaded
void VL_FINISH_MT(const char* filename, int linenum, const char* hier) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
vl_finish(filename, linenum, hier);
}});
#else
vl_finish(filename, linenum, hier);
#endif
}
void VL_STOP_MT(const char* filename, int linenum, const char* hier, bool maybe) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
vl_stop_maybe(filename, linenum, hier, maybe);
}});
#else
vl_stop_maybe(filename, linenum, hier, maybe);
#endif
}
void VL_FATAL_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
vl_fatal(filename, linenum, hier, msg);
}});
#else
vl_fatal(filename, linenum, hier, msg);
#endif
}
void VL_WARN_MT(const char* filename, int linenum, const char* hier, const char* msg) VL_MT_SAFE {
#ifdef VL_THREADED
VerilatedThreadMsgQueue::post(VerilatedMsg{[=]() { //
vl_warn(filename, linenum, hier, msg);
}});
#else
vl_warn(filename, linenum, hier, msg);
#endif
}
//===========================================================================
@ -252,24 +238,16 @@ std::string _vl_string_vprintf(const char* formatp, va_list ap) VL_MT_SAFE {
}
uint64_t _vl_dbg_sequence_number() VL_MT_SAFE {
#ifdef VL_THREADED
static std::atomic<uint64_t> sequence;
#else
static uint64_t sequence = 0;
#endif
return ++sequence;
}
uint32_t VL_THREAD_ID() VL_MT_SAFE {
#ifdef VL_THREADED
// Alternative is to use std::this_thread::get_id, but that returns a
// hard-to-read number and is very slow
static std::atomic<uint32_t> s_nextId(0);
static VL_THREAD_LOCAL uint32_t t_myId = ++s_nextId;
static thread_local uint32_t t_myId = ++s_nextId;
return t_myId;
#else
return 0;
#endif
}
void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
@ -288,7 +266,6 @@ void VL_DBG_MSGF(const char* formatp, ...) VL_MT_SAFE {
VL_PRINTF("-V{t%u,%" PRIu64 "}%s", VL_THREAD_ID(), _vl_dbg_sequence_number(), out.c_str());
}
#ifdef VL_THREADED
void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
va_list ap;
va_start(ap, formatp);
@ -298,14 +275,13 @@ void VL_PRINTF_MT(const char* formatp, ...) VL_MT_SAFE {
VL_PRINTF("%s", out.c_str());
}});
}
#endif
//===========================================================================
// Random -- Mostly called at init time, so not inline.
static uint32_t vl_sys_rand32() VL_MT_UNSAFE {
static uint32_t vl_sys_rand32() VL_MT_SAFE {
// Return random 32-bits using system library.
// Used only to construct seed for Verilator's PNRG.
// Used only to construct seed for Verilator's PRNG.
static VerilatedMutex s_mutex;
const VerilatedLockGuard lock{s_mutex}; // Otherwise rand is unsafe
#if defined(_WIN32) && !defined(__CYGWIN__)
@ -317,8 +293,8 @@ static uint32_t vl_sys_rand32() VL_MT_UNSAFE {
}
uint64_t vl_rand64() VL_MT_SAFE {
static VL_THREAD_LOCAL uint64_t t_state[2];
static VL_THREAD_LOCAL uint32_t t_seedEpoch = 0;
static thread_local uint64_t t_state[2];
static thread_local uint32_t t_seedEpoch = 0;
// For speed, we use a thread-local epoch number to know when to reseed
// A thread always belongs to a single context, so this works out ok
if (VL_UNLIKELY(t_seedEpoch != VerilatedContextImp::randSeedEpoch())) {
@ -395,7 +371,7 @@ void _vl_debug_print_w(int lbits, const WDataInP iwp) VL_MT_SAFE {
}
//===========================================================================
// Slow math
// Slow expressions
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, const WDataInP lwp, const WDataInP rwp,
bool is_modulus) VL_MT_SAFE {
@ -515,11 +491,11 @@ WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, const WDataInP lw
// obits==lbits, rbits can be different
owp[0] = 1;
for (int i = 1; i < VL_WORDS_I(obits); i++) owp[i] = 0;
// cppcheck-suppress variableScope
// cppcheck-has-bug-suppress variableScope
VlWide<VL_MULS_MAX_WORDS> powstore; // Fixed size, as MSVC++ doesn't allow [words] here
VlWide<VL_MULS_MAX_WORDS> lastpowstore; // Fixed size, as MSVC++ doesn't allow [words] here
VlWide<VL_MULS_MAX_WORDS> lastoutstore; // Fixed size, as MSVC++ doesn't allow [words] here
// cppcheck-suppress variableScope
// cppcheck-has-bug-suppress variableScope
VL_ASSIGN_W(obits, powstore, lwp);
for (int bit = 0; bit < rbits; bit++) {
if (bit > 0) { // power = power*power
@ -619,7 +595,7 @@ double VL_ITOR_D_W(int lbits, const WDataInP lwp) VL_PURE {
const double d = (hi + mid + lo) * std::exp2(VL_EDATASIZE * (ms_word - 2));
return d;
}
double VL_ISTOR_D_W(int lbits, const WDataInP lwp) VL_PURE {
double VL_ISTOR_D_W(int lbits, const WDataInP lwp) VL_MT_SAFE {
if (!VL_SIGN_W(lbits, lwp)) return VL_ITOR_D_W(lbits, lwp);
uint32_t pos[VL_MULS_MAX_WORDS + 1]; // Fixed size, as MSVC++ doesn't allow [words] here
VL_NEGATE_W(VL_WORDS_I(lbits), pos, lwp);
@ -762,7 +738,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 t_tmp[VL_VALUE_STRING_MAX_WIDTH];
static thread_local char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
const char* pctp = nullptr; // Most recent %##.##g format
bool inPct = false;
bool widthSet = false;
@ -1160,7 +1136,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 t_tmp[VL_VALUE_STRING_MAX_WIDTH];
static thread_local char t_tmp[VL_VALUE_STRING_MAX_WIDTH];
int floc = fbits - 1;
IData got = 0;
bool inPct = false;
@ -1251,7 +1227,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_skipspace(fp, floc, fromp, fstr);
_vl_vsss_read_str(fp, floc, fromp, fstr, t_tmp, "+-.0123456789eE");
if (!t_tmp[0]) goto done;
// cppcheck-suppress unusedStructMember // It's used
// cppcheck-has-bug-suppress unusedStructMember, unreadVariable
union {
double r;
int64_t ld;
@ -1453,7 +1429,7 @@ void VL_FCLOSE_I(IData fdi) VL_MT_SAFE {
}
void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1464,7 +1440,7 @@ void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE
}
void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1475,7 +1451,7 @@ void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE
}
void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1486,7 +1462,7 @@ void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE
}
void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1497,7 +1473,7 @@ void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE
}
void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1518,7 +1494,7 @@ 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 t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1529,7 +1505,7 @@ std::string VL_SFORMATF_NX(const char* formatp, ...) VL_MT_SAFE {
}
void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
static VL_THREAD_LOCAL std::string t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
va_start(ap, formatp);
@ -1541,7 +1517,7 @@ void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE {
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 t_output; // static only for speed
static thread_local std::string t_output; // static only for speed
t_output = "";
va_list ap;
@ -1651,6 +1627,34 @@ IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi
return read_count;
}
std::string VL_STACKTRACE_N() VL_MT_SAFE {
static VerilatedMutex s_stackTraceMutex;
const VerilatedLockGuard lock{s_stackTraceMutex};
constexpr int BT_BUF_SIZE = 100;
void* buffer[BT_BUF_SIZE];
int nptrs = 0;
char** strings = nullptr;
#ifdef _VL_HAVE_STACKTRACE
nptrs = backtrace(buffer, BT_BUF_SIZE);
strings = backtrace_symbols(buffer, nptrs);
#endif
// cppcheck-suppress knownConditionTrueFalse
if (!strings) return "Unable to backtrace\n";
std::string out = "Backtrace:\n";
for (int j = 0; j < nptrs; j++) out += std::string{strings[j]} + std::string{"\n"};
free(strings);
return out;
}
void VL_STACKTRACE() VL_MT_SAFE {
const std::string out = VL_STACKTRACE_N();
VL_PRINTF("%s", out.c_str());
}
IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE {
VlWide<VL_WQ_WORDS_E> lhsw;
VL_SET_WQ(lhsw, lhs);
@ -1678,7 +1682,7 @@ IData VL_VALUEPLUSARGS_INW(int rbits, const std::string& ld, WDataOutP rwp) VL_M
inPct = true;
} else if (!inPct) { // Normal text
prefix += *posp;
} else if (inPct && posp[0] == '0') { // %0
} else if (*posp == '0') { // %0
} else { // Format character
switch (std::tolower(*posp)) {
case '%':
@ -1771,7 +1775,7 @@ 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 = Verilated::threadContextp()->impp()->argPlusMatch(prefixp);
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
static thread_local char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
if (match.empty()) return nullptr;
char* dp = t_outstr;
for (const char* sp = match.c_str() + std::strlen(prefixp) + 1; // +1 to skip the "+"
@ -1792,12 +1796,12 @@ std::string VL_TO_STRING_W(int words, const WDataInP obj) {
return VL_SFORMATF_NX("'h%0x", words * VL_EDATASIZE, obj);
}
std::string VL_TOLOWER_NN(const std::string& ld) VL_MT_SAFE {
std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE {
std::string out = ld;
for (auto& cr : out) cr = std::tolower(cr);
return out;
}
std::string VL_TOUPPER_NN(const std::string& ld) VL_MT_SAFE {
std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE {
std::string out = ld;
for (auto& cr : out) cr = std::toupper(cr);
return out;
@ -1808,16 +1812,14 @@ std::string VL_CVT_PACK_STR_NW(int lwords, const WDataInP lwp) VL_MT_SAFE {
char destout[VL_VALUE_STRING_MAX_CHARS + 1];
const int obits = lwords * VL_EDATASIZE;
int lsb = obits - 1;
bool start = true;
char* destp = destout;
size_t len = 0;
for (; lsb >= 0; --lsb) {
lsb = (lsb / 8) * 8; // Next digit
const IData charval = VL_BITRSHIFT_W(lwp, lsb) & 0xff;
if (!start || charval) {
*destp++ = (charval == 0) ? ' ' : charval;
if (charval) {
*destp++ = static_cast<char>(charval);
++len;
start = false; // Drop leading 0s
}
}
return std::string{destout, len};
@ -1865,7 +1867,7 @@ IData VL_ATOI_N(const std::string& str, int base) VL_PURE {
static const char* memhFormat(int nBits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char t_buf[32];
static thread_local char t_buf[32];
switch ((nBits - 1) / 4) {
case 0: VL_SNPRINTF(t_buf, 32, "%%01x"); break;
case 1: VL_SNPRINTF(t_buf, 32, "%%02x"); break;
@ -1883,7 +1885,7 @@ static const char* memhFormat(int nBits) {
static const char* formatBinary(int nBits, uint32_t bits) {
assert((nBits >= 1) && (nBits <= 32));
static VL_THREAD_LOCAL char t_buf[64];
static thread_local char t_buf[64];
for (int i = 0; i < nBits; i++) {
const bool isOne = bits & (1 << (nBits - 1 - i));
t_buf[i] = (isOne ? '1' : '0');
@ -1902,7 +1904,7 @@ VlReadMem::VlReadMem(bool hex, int bits, const std::string& filename, QData star
if (VL_UNLIKELY(!m_fp)) {
// We don't report the Verilog source filename as it slow to have to pass it down
VL_WARN_MT(filename.c_str(), 0, "", "$readmem file not found");
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
// cppcheck-has-bug-suppress resourceLeak // m_fp is nullptr
return;
}
}
@ -2040,7 +2042,7 @@ VlWriteMem::VlWriteMem(bool hex, int bits, const std::string& filename, QData st
m_fp = std::fopen(filename.c_str(), "w");
if (VL_UNLIKELY(!m_fp)) {
VL_FATAL_MT(filename.c_str(), 0, "", "$writemem file not found");
// cppcheck-suppress resourceLeak // m_fp is nullptr - bug in cppcheck
// cppcheck-has-bug-suppress resourceLeak // m_fp is nullptr
return;
}
}
@ -2221,8 +2223,9 @@ static const char* vl_time_str(int scale) VL_PURE {
return names[2 - scale];
}
double vl_time_multiplier(int scale) VL_PURE {
// Return timescale multipler -18 to +18
// Return timescale multiplier -18 to +18
// For speed, this does not check for illegal values
// cppcheck-has-bug-suppress arrayIndexOutOfBoundsCond
if (scale < 0) {
static const double neg10[] = {1.0,
0.1,
@ -2243,6 +2246,7 @@ double vl_time_multiplier(int scale) VL_PURE {
0.0000000000000001,
0.00000000000000001,
0.000000000000000001};
// cppcheck-has-bug-suppress arrayIndexOutOfBoundsCond
return neg10[-scale];
} else {
static const double pow10[] = {1.0,
@ -2264,6 +2268,7 @@ double vl_time_multiplier(int scale) VL_PURE {
10000000000000000.0,
100000000000000000.0,
1000000000000000000.0};
// cppcheck-has-bug-suppress arrayIndexOutOfBoundsCond
return pow10[scale];
}
}
@ -2335,8 +2340,8 @@ void VerilatedContext::checkMagic(const VerilatedContext* contextp) {
VerilatedContext::Serialized::Serialized() {
constexpr int8_t picosecond = -12;
m_timeunit = picosecond; // Initial value until overriden by _Vconfigure
m_timeprecision = picosecond; // Initial value until overriden by _Vconfigure
m_timeunit = picosecond; // Initial value until overridden by _Vconfigure
m_timeprecision = picosecond; // Initial value until overridden by _Vconfigure
}
void VerilatedContext::assertOn(bool flag) VL_MT_SAFE {
@ -2424,42 +2429,6 @@ void VerilatedContext::timeunit(int value) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_s.m_timeunit = value;
}
void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
int sc_prec = 99;
{
const VerilatedLockGuard lock{m_mutex};
m_s.m_timeprecision = value;
#ifdef SYSTEMC_VERSION
const sc_time sc_res = sc_get_time_resolution();
if (sc_res == sc_time(1, SC_SEC)) {
sc_prec = 0;
} else if (sc_res == sc_time(1, SC_MS)) {
sc_prec = 3;
} else if (sc_res == sc_time(1, SC_US)) {
sc_prec = 6;
} else if (sc_res == sc_time(1, SC_NS)) {
sc_prec = 9;
} else if (sc_res == sc_time(1, SC_PS)) {
sc_prec = 12;
} else if (sc_res == sc_time(1, SC_FS)) {
sc_prec = 15;
}
}
if (value != sc_prec) {
std::ostringstream msg;
msg << "SystemC's sc_set_time_resolution is 10^-" << sc_prec
<< ", which does not match Verilog timeprecision 10^-" << value
<< ". Suggest use 'sc_set_time_resolution(" << vl_time_str(value)
<< ")', or Verilator '--timescale-override " << vl_time_str(sc_prec) << "/"
<< vl_time_str(sc_prec) << "'";
const std::string msgs = msg.str();
VL_FATAL_MT("", 0, "", msgs.c_str());
}
#else
}
#endif
}
const char* VerilatedContext::timeunitString() const VL_MT_SAFE { return vl_time_str(timeunit()); }
const char* VerilatedContext::timeprecisionString() const VL_MT_SAFE {
return vl_time_str(timeprecision());
@ -2474,7 +2443,6 @@ void VerilatedContext::threads(unsigned n) {
"%Error: Cannot set simulation threads after the thread pool has been created.");
}
#if VL_THREADED
if (m_threads == n) return; // To avoid unnecessary warnings
m_threads = n;
const unsigned hardwareThreadsAvailable = std::thread::hardware_concurrency();
@ -2483,29 +2451,25 @@ void VerilatedContext::threads(unsigned n) {
"to %u. This will likely cause significant slowdown.\n",
hardwareThreadsAvailable, m_threads);
}
#else
if (n > 1) {
VL_PRINTF_MT("%%Warning: Verilator run-time library built without VL_THREADS. Ignoring "
"call to 'VerilatedContext::threads' with argument %u.\n",
n);
}
#endif
}
void VerilatedContext::commandArgs(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex) {
const VerilatedLockGuard lock{m_argMutex};
m_args.m_argVec.clear(); // Empty first, then add
impp()->commandArgsAddGuts(argc, argv);
// Not locking m_argMutex here, it is done in impp()->commandArgsAddGuts
// m_argMutex here is the same as in impp()->commandArgsAddGuts;
// due to clang limitations, it doesn't properly check it
impp()->commandArgsGuts(argc, argv);
}
void VerilatedContext::commandArgsAdd(int argc, const char** argv)
VL_MT_SAFE_EXCLUDES(m_argMutex) {
const VerilatedLockGuard lock{m_argMutex};
impp()->commandArgsAddGuts(argc, argv);
// Not locking m_argMutex here, it is done in impp()->commandArgsAddGuts
// m_argMutex here is the same as in impp()->commandArgsAddGuts;
// due to clang limitations, it doesn't properly check it
impp()->commandArgsAddGutsLock(argc, argv);
}
const char* VerilatedContext::commandArgsPlusMatch(const char* prefixp)
VL_MT_SAFE_EXCLUDES(m_argMutex) {
const std::string& match = impp()->argPlusMatch(prefixp);
static VL_THREAD_LOCAL char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
static thread_local char t_outstr[VL_VALUE_STRING_MAX_WIDTH];
if (match.empty()) return "";
char* dp = t_outstr;
for (const char* sp = match.c_str(); *sp && (dp - t_outstr) < (VL_VALUE_STRING_MAX_WIDTH - 2);)
@ -2525,7 +2489,7 @@ void VerilatedContext::internalsDump() const VL_MT_SAFE {
void VerilatedContext::addModel(VerilatedModel* modelp) {
threadPoolp(); // Ensure thread pool is created, so m_threads cannot change any more
if (modelp->threads() > m_threads) {
if (VL_UNLIKELY(modelp->threads() > m_threads)) {
std::ostringstream msg;
msg << "VerilatedContext has " << m_threads << " threads but model '"
<< modelp->modelName() << "' (instantiated as '" << modelp->hierName()
@ -2537,9 +2501,7 @@ void VerilatedContext::addModel(VerilatedModel* modelp) {
VerilatedVirtualBase* VerilatedContext::threadPoolp() {
if (m_threads == 1) return nullptr;
#if VL_THREADED
if (!m_threadPool) m_threadPool.reset(new VlThreadPool{this, m_threads - 1});
#endif
return m_threadPool.get();
}
@ -2551,6 +2513,18 @@ VerilatedContext::enableExecutionProfiler(VerilatedVirtualBase* (*construct)(Ver
//======================================================================
// VerilatedContextImp:: Methods - command line
void VerilatedContextImp::commandArgsGuts(int argc, const char** argv)
VL_MT_SAFE_EXCLUDES(m_argMutex) {
const VerilatedLockGuard lock{m_argMutex};
m_args.m_argVec.clear(); // Empty first, then add
commandArgsAddGuts(argc, argv);
}
void VerilatedContextImp::commandArgsAddGutsLock(int argc, const char** argv)
VL_MT_SAFE_EXCLUDES(m_argMutex) {
const VerilatedLockGuard lock{m_argMutex};
commandArgsAddGuts(argc, argv);
}
void VerilatedContextImp::commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(m_argMutex) {
if (!m_args.m_argVecLoaded) m_args.m_argVec.clear();
@ -2700,10 +2674,8 @@ void VerilatedContext::randSeed(int val) VL_MT_SAFE {
const VerilatedLockGuard lock{VerilatedContextImp::s().s_randMutex};
m_s.m_randSeed = val;
const uint64_t newEpoch = VerilatedContextImp::s().s_randSeedEpoch + 1;
// Obververs must see new epoch AFTER seed updated
#ifdef VL_THREADED
// Observers must see new epoch AFTER seed updated
std::atomic_signal_fence(std::memory_order_release);
#endif
VerilatedContextImp::s().s_randSeedEpoch = newEpoch;
}
uint64_t VerilatedContextImp::randSeedDefault64() const VL_MT_SAFE {
@ -2760,16 +2732,13 @@ VerilatedSyms::VerilatedSyms(VerilatedContext* contextp)
: _vm_contextp__(contextp ? contextp : Verilated::threadContextp()) {
VerilatedContext::checkMagic(_vm_contextp__);
Verilated::threadContextp(_vm_contextp__);
#ifdef VL_THREADED
// cppcheck-has-bug-suppress noCopyConstructor
__Vm_evalMsgQp = new VerilatedEvalMsgQueue;
#endif
}
VerilatedSyms::~VerilatedSyms() {
VerilatedContext::checkMagic(_vm_contextp__);
#ifdef VL_THREADED
delete __Vm_evalMsgQp;
#endif
}
//===========================================================================
@ -2791,8 +2760,8 @@ void Verilated::debug(int level) VL_MT_SAFE {
const char* Verilated::catName(const char* n1, const char* n2, const char* delimiter) VL_MT_SAFE {
// Used by symbol table creation to make module names
static VL_THREAD_LOCAL char* t_strp = nullptr;
static VL_THREAD_LOCAL size_t t_len = 0;
static thread_local char* t_strp = nullptr;
static thread_local size_t t_len = 0;
const size_t newlen = std::strlen(n1) + std::strlen(n2) + std::strlen(delimiter) + 1;
if (VL_UNLIKELY(!t_strp || newlen > t_len)) {
if (t_strp) delete[] t_strp;
@ -2820,12 +2789,12 @@ static struct {
VoidPCbList s_exitCbs VL_GUARDED_BY(s_exitMutex);
} VlCbStatic;
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
static void addCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) VL_MT_UNSAFE {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair); // Just in case it's a duplicate
cbs.push_back(pair);
}
static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) {
static void removeCb(Verilated::VoidPCb cb, void* datap, VoidPCbList& cbs) VL_MT_UNSAFE {
std::pair<Verilated::VoidPCb, void*> pair(cb, datap);
cbs.remove(pair);
}
@ -2843,11 +2812,7 @@ void Verilated::removeFlushCb(VoidPCb cb, void* datap) VL_MT_SAFE {
}
void Verilated::runFlushCallbacks() VL_MT_SAFE {
// Flush routines may call flush, so avoid mutex deadlock
#ifdef VL_THREADED
static std::atomic<int> s_recursing;
#else
static int s_recursing = 0;
#endif
if (!s_recursing++) {
const VerilatedLockGuard lock{VlCbStatic.s_flushMutex};
runCallbacks(VlCbStatic.s_flushCbs);
@ -2870,11 +2835,7 @@ void Verilated::removeExitCb(VoidPCb cb, void* datap) VL_MT_SAFE {
removeCb(cb, datap, VlCbStatic.s_exitCbs);
}
void Verilated::runExitCallbacks() VL_MT_SAFE {
#ifdef VL_THREADED
static std::atomic<int> s_recursing;
#else
static int s_recursing = 0;
#endif
if (!s_recursing++) {
const VerilatedLockGuard lock{VlCbStatic.s_exitMutex};
runCallbacks(VlCbStatic.s_exitCbs);
@ -2899,6 +2860,26 @@ void Verilated::overWidthError(const char* signame) VL_MT_SAFE {
VL_UNREACHABLE;
}
void Verilated::scTimePrecisionError(int sc_prec, int vl_prec) VL_MT_SAFE {
std::ostringstream msg;
msg << "SystemC's sc_set_time_resolution is 10^-" << sc_prec
<< ", which does not match Verilog timeprecision 10^-" << vl_prec
<< ". Suggest use 'sc_set_time_resolution(" << vl_time_str(vl_prec)
<< ")', or Verilator '--timescale-override " << vl_time_str(sc_prec) << "/"
<< vl_time_str(sc_prec) << "'";
const std::string msgs = msg.str();
VL_FATAL_MT("", 0, "", msgs.c_str());
VL_UNREACHABLE;
}
void Verilated::scTraceBeforeElaborationError() VL_MT_SAFE {
// Slowpath - Called only when trace file opened before SystemC elaboration
VL_FATAL_MT("unknown", 0, "",
"%Error: Verilated*Sc::open(...) was called before sc_core::sc_start(). "
"Run sc_core::sc_start(sc_core::SC_ZERO_TIME) before opening a wave file.");
VL_UNREACHABLE;
}
void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE {
#if defined(_WIN32) || defined(__MINGW32__)
::mkdir(dirname);
@ -2908,17 +2889,14 @@ void Verilated::mkdir(const char* dirname) VL_MT_UNSAFE {
}
void Verilated::quiesce() VL_MT_SAFE {
#ifdef VL_THREADED
// Wait until all threads under this evaluation are quiet
// THREADED-TODO
#endif
}
int Verilated::exportFuncNum(const char* namep) VL_MT_SAFE {
return VerilatedImp::exportFind(namep);
}
#ifdef VL_THREADED
void Verilated::endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
VL_DEBUG_IF(VL_DBG_MSGF("End of thread mtask\n"););
VerilatedThreadMsgQueue::flush(evalMsgQp);
@ -2932,7 +2910,6 @@ void Verilated::endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE {
VL_DEBUG_IF(VL_DBG_MSGF("End-of-eval cleanup\n"););
evalMsgQp->process();
}
#endif
//===========================================================================
// VerilatedImp:: Methods
@ -3138,7 +3115,7 @@ void VerilatedHierarchy::remove(VerilatedScope* fromp, VerilatedScope* top) {
//===========================================================================
// VerilatedOneThreaded:: Methods
#if defined(VL_THREADED) && defined(VL_DEBUG)
#ifdef VL_DEBUG
void VerilatedAssertOneThread::fatal_different() VL_MT_SAFE {
VL_FATAL_MT(__FILE__, __LINE__, "",
"Routine called that is single threaded, but called from"
@ -3155,8 +3132,8 @@ void VlDeleter::deleteAll() {
if (m_newGarbage.empty()) break;
VerilatedLockGuard deleteLock{m_deleteMutex};
std::swap(m_newGarbage, m_toDelete);
lock.unlock(); // So destuctors can enqueue new objects
for (VlClass* const objp : m_toDelete) delete objp;
lock.unlock(); // So destructors can enqueue new objects
for (VlDeletable* const objp : m_toDelete) delete objp;
m_toDelete.clear();
}
}

View File

@ -54,11 +54,9 @@
#include <unordered_set>
#include <vector>
// <iostream> avoided to reduce compile time
#ifdef VL_THREADED
# include <atomic>
# include <mutex>
# include <thread>
#endif
#include <atomic>
#include <mutex>
#include <thread>
// Allow user to specify their own include file
#ifdef VL_VERILATED_INCLUDE
@ -149,8 +147,6 @@ enum VerilatedVarFlags {
// Return current thread ID (or 0), not super fast, cache if needed
extern uint32_t VL_THREAD_ID() VL_MT_SAFE;
#if VL_THREADED
#define VL_LOCK_SPINS 50000 /// Number of times to spin for a mutex before yielding
/// Mutex, wrapped to allow -fthread_safety checks
@ -202,34 +198,12 @@ public:
void unlock() VL_RELEASE() VL_MT_SAFE { m_mutexr.unlock(); }
};
#else // !VL_THREADED
// Empty non-threaded mutex to avoid #ifdefs in consuming code
class VerilatedMutex final {
public:
void lock() {} // LCOV_EXCL_LINE
void unlock() {} // LCOV_EXCL_LINE
};
// Empty non-threaded lock guard to avoid #ifdefs in consuming code
class VerilatedLockGuard final {
VL_UNCOPYABLE(VerilatedLockGuard);
public:
explicit VerilatedLockGuard(VerilatedMutex&) {}
~VerilatedLockGuard() = default;
void lock() {} // LCOV_EXCL_LINE
void unlock() {} // LCOV_EXCL_LINE
};
#endif // VL_THREADED
// Internals: Remember the calling thread at construction time, and make
// sure later calls use same thread
class VerilatedAssertOneThread final {
// MEMBERS
#if defined(VL_THREADED) && defined(VL_DEBUG)
#ifdef VL_DEBUG
uint32_t m_threadid; // Thread that is legal
public:
// CONSTRUCTORS
@ -250,7 +224,7 @@ public:
}
}
static void fatal_different() VL_MT_SAFE;
#else // !VL_THREADED || !VL_DEBUG
#else // !VL_DEBUG
public:
void check() {}
#endif
@ -274,7 +248,7 @@ protected:
public:
/// Returns the VerilatedContext this model is instantiated under
/// Used to get to e.g. simulation time via contextp()->time()
VerilatedContext* contextp() const { return &m_context; }
VerilatedContext* contextp() const VL_MT_SAFE { return &m_context; }
/// Returns the hierarchical name of this module instance.
virtual const char* hierName() const = 0;
/// Returns the name of this model (the name of the generated model class).
@ -301,7 +275,7 @@ private:
public:
explicit VerilatedModule(const char* namep); // Create module with given hierarchy name
~VerilatedModule();
const char* name() const { return m_namep; } ///< Return name of module
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; } ///< Return name of module
};
//=========================================================================
@ -343,7 +317,7 @@ class VerilatedContext VL_NOT_FINAL {
protected:
// MEMBERS
// Slow path variables
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members, when VL_THREADED
mutable VerilatedMutex m_mutex; // Mutex for most s_s/s_ns members
struct Serialized { // All these members serialized/deserialized
// No std::strings or pointers or will serialize badly!
@ -390,18 +364,14 @@ protected:
// assumption is that the restore is allowed to pass different arguments
struct NonSerializedCommandArgs {
// Medium speed
bool m_argVecLoaded = false; // Ever loaded argument list
std::vector<std::string> m_argVec; // Aargument list
bool m_argVecLoaded = false; // Ever loaded argument list
} m_args VL_GUARDED_BY(m_argMutex);
// Implementation details
const std::unique_ptr<VerilatedContextImpData> m_impdatap;
// Number of threads to use for simulation (size of m_threadPool + 1 for main thread)
#ifdef VL_THREADED
unsigned m_threads = std::thread::hardware_concurrency();
#else
const unsigned m_threads = 1;
#endif
// The thread pool shared by all models added to this context
std::unique_ptr<VerilatedVirtualBase> m_threadPool;
// The execution profiler shared by all models added to this context
@ -470,7 +440,7 @@ public:
void errorLimit(int val) VL_MT_SAFE;
/// Return number of errors/assertions before stop
int errorLimit() const VL_MT_SAFE { return m_s.m_errorLimit; }
/// Set to throw fatal error on $stop/non-fatal ettot
/// Set to throw fatal error on $stop/non-fatal error
void fatalOnError(bool flag) VL_MT_SAFE;
/// Return if to throw fatal error on $stop/non-fatal
bool fatalOnError() const VL_MT_SAFE { return m_s.m_fatalOnError; }
@ -535,7 +505,7 @@ public:
/// Get time precision as power-of-ten
int timeprecision() const VL_MT_SAFE { return -m_s.m_timeprecision; }
/// Return time precision as power-of-ten
void timeprecision(int value) VL_MT_SAFE;
inline void timeprecision(int value) VL_MT_SAFE;
/// Get time precision as IEEE-standard text
const char* timeprecisionString() const VL_MT_SAFE;
@ -563,8 +533,8 @@ public:
// METHODS - public but for internal use only
// Internal: access to implementation class
VerilatedContextImp* impp() { return reinterpret_cast<VerilatedContextImp*>(this); }
const VerilatedContextImp* impp() const {
VerilatedContextImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedContextImp*>(this); }
const VerilatedContextImp* impp() const VL_MT_SAFE {
return reinterpret_cast<const VerilatedContextImp*>(this);
}
@ -611,9 +581,7 @@ public: // But for internal use only
// MEMBERS
// Keep first so is at zero offset for fastest code
VerilatedContext* const _vm_contextp__; // Context for current model
#ifdef VL_THREADED
VerilatedEvalMsgQueue* __Vm_evalMsgQp;
#endif
explicit VerilatedSyms(VerilatedContext* contextp); // Pass null for default context
~VerilatedSyms();
};
@ -649,10 +617,10 @@ public: // But internals only - called from VerilatedModule's
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
// ACCESSORS
const char* name() const { return m_namep; }
const char* identifier() const { return m_identifierp; }
int8_t timeunit() const { return m_timeunit; }
VerilatedSyms* symsp() const { return m_symsp; }
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
int8_t timeunit() const VL_MT_SAFE_POSTINIT { return m_timeunit; }
VerilatedSyms* symsp() const VL_MT_SAFE_POSTINIT { return m_symsp; }
VerilatedVar* varFind(const char* namep) const VL_MT_SAFE_POSTINIT;
VerilatedVarNameMap* varsp() const VL_MT_SAFE_POSTINIT { return m_varsp; }
void scopeDump() const;
@ -694,17 +662,15 @@ class Verilated final {
static VerilatedContext* s_lastContextp; // Last context constructed/attached
// Not covered by mutex, as per-thread
static VL_THREAD_LOCAL struct ThreadLocal {
static thread_local struct ThreadLocal {
// No non-POD objects here due to this:
// Internal note: Globals may multi-construct, see verilated.cpp top.
// Fast path
VerilatedContext* t_contextp = nullptr; // Thread's context
#ifdef VL_THREADED
uint32_t t_mtaskId = 0; // mtask# executing on this thread
// Messages maybe pending on thread, needs end-of-eval calls
uint32_t t_endOfEvalReqd = 0;
#endif
const VerilatedScope* t_dpiScopep = nullptr; // DPI context scope
const char* t_dpiFilename = nullptr; // DPI context filename
int t_dpiLineno = 0; // DPI context line number
@ -752,7 +718,7 @@ public:
lastContextp(contextp);
}
/// Return the VerilatedContext for the current thread
static VerilatedContext* threadContextp() {
static VerilatedContext* threadContextp() VL_MT_SAFE {
if (VL_UNLIKELY(!t_s.t_contextp)) t_s.t_contextp = lastContextp();
return t_s.t_contextp;
}
@ -890,11 +856,14 @@ public:
// METHODS - INTERNAL USE ONLY (but public due to what uses it)
// Internal: Create a new module name by concatenating two strings
// Returns pointer to thread-local static data (overwritten on next call)
static const char* catName(const char* n1, const char* n2, const char* delimiter = ".");
static const char* catName(const char* n1, const char* n2,
const char* delimiter = ".") VL_MT_SAFE;
// Internal: Throw signal assertion
static void nullPointerError(const char* filename, int linenum) VL_ATTR_NORETURN VL_MT_SAFE;
static void overWidthError(const char* signame) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTimePrecisionError(int sc_prec, int vl_prec) VL_ATTR_NORETURN VL_MT_SAFE;
static void scTraceBeforeElaborationError() VL_ATTR_NORETURN VL_MT_SAFE;
// Internal: Get and set DPI context
static const VerilatedScope* dpiScope() VL_MT_SAFE { return t_s.t_dpiScopep; }
@ -911,7 +880,6 @@ public:
static int dpiLineno() VL_MT_SAFE { return t_s.t_dpiLineno; }
static int exportFuncNum(const char* namep) VL_MT_SAFE;
#ifdef VL_THREADED
// Internal: Set the mtaskId, called when an mtask starts
// Per thread, so no need to be in VerilatedContext
static void mtaskId(uint32_t id) VL_MT_SAFE { t_s.t_mtaskId = id; }
@ -925,12 +893,9 @@ public:
}
// Internal: Called at end of eval loop
static void endOfEval(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
#endif
private:
#ifdef VL_THREADED
static void endOfThreadMTaskGuts(VerilatedEvalMsgQueue* evalMsgQp) VL_MT_SAFE;
#endif
};
void VerilatedContext::debug(int val) VL_MT_SAFE { Verilated::debug(val); }
@ -948,5 +913,35 @@ int VerilatedContext::debug() VL_MT_SAFE { return Verilated::debug(); }
//======================================================================
void VerilatedContext::timeprecision(int value) VL_MT_SAFE {
if (value < 0) value = -value; // Stored as 0..15
#if VM_SC
int sc_prec = 99;
#endif
{
const VerilatedLockGuard lock{m_mutex};
m_s.m_timeprecision = value;
#if VM_SC
const sc_time sc_res = sc_get_time_resolution();
if (sc_res == sc_time(1, SC_SEC)) {
sc_prec = 0;
} else if (sc_res == sc_time(1, SC_MS)) {
sc_prec = 3;
} else if (sc_res == sc_time(1, SC_US)) {
sc_prec = 6;
} else if (sc_res == sc_time(1, SC_NS)) {
sc_prec = 9;
} else if (sc_res == sc_time(1, SC_PS)) {
sc_prec = 12;
} else if (sc_res == sc_time(1, SC_FS)) {
sc_prec = 15;
}
#endif
}
#if VM_SC
if (VL_UNLIKELY(value != sc_prec)) Verilated::scTimePrecisionError(sc_prec, value);
#endif
}
#undef VERILATOR_VERILATED_H_INTERNAL_
#endif // Guard

View File

@ -130,19 +130,8 @@ endif
#######################################################################
##### Threaded builds
ifneq ($(VM_C11),0)
ifneq ($(VM_C11),)
VK_C11=1
endif
endif
ifneq ($(VM_THREADS),0)
ifneq ($(VM_THREADS),)
CPPFLAGS += -DVL_THREADED
VK_C11=1
VK_LIBS_THREADED=1
endif
endif
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
LDLIBS += $(CFG_LDLIBS_THREADS)
ifneq ($(VM_TIMING),0)
ifneq ($(VM_TIMING),)
@ -150,18 +139,6 @@ ifneq ($(VM_TIMING),0)
endif
endif
ifneq ($(VK_C11),0)
ifneq ($(VK_C11),)
# Need C++11 at least, so always default to newest
CPPFLAGS += $(CFG_CXXFLAGS_STD_NEWEST)
endif
endif
ifneq ($(VK_LIBS_THREADED),0)
ifneq ($(VK_LIBS_THREADED),)
LDLIBS += $(CFG_LDLIBS_THREADS)
endif
endif
#######################################################################
### Aggregates

View File

@ -36,7 +36,7 @@
class VerilatedCovImp;
//=============================================================================
/// Insert a item for coverage analysis.
/// Insert an item for coverage analysis.
/// The first argument is a pointer to the count to be dumped.
/// The remaining arguments occur in pairs: A string key, and a value.
/// The value may be a string, or another type which will be auto-converted to a string.
@ -128,15 +128,15 @@ public:
#define K(n) const char* key##n
#define A(n) const char *key##n, const char *valp##n // Argument list
#define D(n) const char *key##n = nullptr, const char *valp##n = nullptr // Argument list
void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9));
void _insertp(D(0), D(1), D(2), D(3), D(4), D(5), D(6), D(7), D(8), D(9)) VL_MT_SAFE;
void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), D(11), D(12),
D(13), D(14), D(15), D(16), D(17), D(18), D(19));
D(13), D(14), D(15), D(16), D(17), D(18), D(19)) VL_MT_SAFE;
void _insertp(A(0), A(1), A(2), A(3), A(4), A(5), A(6), A(7), A(8), A(9), A(10), A(11), A(12),
A(13), A(14), A(15), A(16), A(17), A(18), A(19), A(20), D(21), D(22), D(23),
D(24), D(25), D(26), D(27), D(28), D(29));
D(24), D(25), D(26), D(27), D(28), D(29)) VL_MT_SAFE;
// Backward compatibility for Verilator
void _insertp(A(0), A(1), K(2), int val2, K(3), int val3, K(4), const std::string& val4, A(5),
A(6), A(7));
A(6), A(7)) VL_MT_SAFE;
#undef K
#undef A
@ -152,7 +152,7 @@ protected:
// METHODS
// Internal: access to implementation class
VerilatedCovImp* impp() { return reinterpret_cast<VerilatedCovImp*>(this); }
VerilatedCovImp* impp() VL_MT_SAFE { return reinterpret_cast<VerilatedCovImp*>(this); }
};
//=============================================================================

View File

@ -181,7 +181,7 @@ void svPutPartselLogic(svLogicVecVal* dp, const svLogicVecVal s, int lbit, int w
//======================================================================
// Open array internals
static const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) {
static const VerilatedDpiOpenVar* _vl_openhandle_varp(const svOpenArrayHandle h) VL_MT_SAFE {
if (VL_UNLIKELY(!h)) {
VL_FATAL_MT(__FILE__, __LINE__, "",
"%%Error: DPI svOpenArrayHandle function called with nullptr handle");
@ -223,7 +223,7 @@ int svSizeOfArray(const svOpenArrayHandle h) {
// Open array access internals
static void* _vl_sv_adjusted_datap(const VerilatedDpiOpenVar* varp, int nargs, int indx1,
int indx2, int indx3) {
int indx2, int indx3) VL_MT_SAFE {
void* datap = varp->datap();
if (VL_UNLIKELY(nargs != varp->udims())) {
VL_SVDPI_WARN_("%%Warning: DPI svOpenArrayHandle function called on"

View File

@ -28,10 +28,8 @@
#include "verilated_fst_c.h"
// GTKWave configuration
#ifdef VL_THREADED
# define HAVE_LIBPTHREAD
# define FST_WRITER_PARALLEL
#endif
#define HAVE_LIBPTHREAD
#define FST_WRITER_PARALLEL
// Include the GTKWave implementation directly
#define FST_CONFIG_INCLUDE "fst_config.h"
@ -97,7 +95,7 @@ VerilatedFst::VerilatedFst(void* /*fst*/) {}
VerilatedFst::~VerilatedFst() {
if (m_fst) fstWriterClose(m_fst);
if (m_symbolp) VL_DO_CLEAR(delete[] m_symbolp, m_symbolp = nullptr);
if (m_strbuf) VL_DO_CLEAR(delete[] m_strbuf, m_strbuf = nullptr);
if (m_strbufp) VL_DO_CLEAR(delete[] m_strbufp, m_strbufp = nullptr);
}
void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
@ -127,7 +125,7 @@ void VerilatedFst::open(const char* filename) VL_MT_SAFE_EXCLUDES(m_mutex) {
m_code2symbol.clear();
// Allocate string buffer for arrays
if (!m_strbuf) m_strbuf = new char[maxBits() + 32];
if (!m_strbufp) m_strbufp = new char[maxBits() + 32];
}
void VerilatedFst::close() VL_MT_SAFE_EXCLUDES(m_mutex) {
@ -223,6 +221,10 @@ void VerilatedFst::declare(uint32_t code, const char* name, int dtypenum, fstVar
}
}
void VerilatedFst::declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
}
void VerilatedFst::declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum) {
declare(code, name, dtypenum, vardir, vartype, array, arraynum, false, 0, 0);
@ -248,14 +250,11 @@ void VerilatedFst::declDouble(uint32_t code, const char* name, int dtypenum, fst
// Get/commit trace buffer
VerilatedFst::Buffer* VerilatedFst::getTraceBuffer() {
#ifdef VL_THREADED
if (offload()) return new OffloadBuffer{*this};
#endif
return new Buffer{*this};
}
void VerilatedFst::commitTraceBuffer(VerilatedFst::Buffer* bufp) {
#ifdef VL_THREADED
if (offload()) {
OffloadBuffer* const offloadBufferp = static_cast<OffloadBuffer*>(bufp);
if (offloadBufferp->m_offloadBufferWritep) {
@ -263,7 +262,6 @@ void VerilatedFst::commitTraceBuffer(VerilatedFst::Buffer* bufp) {
return; // Buffer will be deleted by the offload thread
}
}
#endif
delete bufp;
}
@ -285,6 +283,12 @@ void VerilatedFst::configure(const VerilatedTraceConfig& config) {
// verilated_trace_imp.h, which is included in this file at the top),
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitEvent(uint32_t code, VlEvent newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
fstWriterEmitValueChange(m_fst, m_symbolp[code], "1");
}
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitBit(uint32_t code, CData newval) {
VL_DEBUG_IFDEF(assert(m_symbolp[code]););
@ -326,7 +330,7 @@ void VerilatedFstBuffer::emitQData(uint32_t code, QData newval, int bits) {
VL_ATTR_ALWINLINE
void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits) {
int words = VL_WORDS_I(bits);
char* wp = m_strbuf;
char* wp = m_strbufp;
// Convert the most significant word
const int bitsInMSW = VL_BITBIT_E(bits) ? VL_BITBIT_E(bits) : VL_EDATASIZE;
cvtEDataToStr(wp, newvalp[--words] << (VL_EDATASIZE - bitsInMSW));
@ -336,7 +340,7 @@ void VerilatedFstBuffer::emitWData(uint32_t code, const WData* newvalp, int bits
cvtEDataToStr(wp, newvalp[--words]);
wp += VL_EDATASIZE;
}
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbuf);
fstWriterEmitValueChange(m_fst, m_symbolp[code], m_strbufp);
}
VL_ATTR_ALWINLINE

View File

@ -53,7 +53,7 @@ private:
std::map<int, fstEnumHandle> m_local2fstdtype;
std::list<std::string> m_curScope;
fstHandle* m_symbolp = nullptr; // same as m_code2symbol, but as an array
char* m_strbuf = nullptr; // String buffer long enough to hold maxBits() chars
char* m_strbufp = nullptr; // String buffer long enough to hold maxBits() chars
bool m_useFstWriterThread = false; // Whether to use the separate FST writer thread
@ -101,6 +101,8 @@ public:
//=========================================================================
// Internal interface to Verilator generated code
void declEvent(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declBit(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
fstVarType vartype, bool array, int arraynum);
void declBus(uint32_t code, const char* name, int dtypenum, fstVarDir vardir,
@ -149,7 +151,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// code to fstHande map, as an array
const fstHandle* const m_symbolp = m_owner.m_symbolp;
// String buffer long enough to hold maxBits() chars
char* const m_strbuf = m_owner.m_strbuf;
char* const m_strbufp = m_owner.m_strbufp;
// CONSTRUCTOR
explicit VerilatedFstBuffer(VerilatedFst& owner)
@ -161,6 +163,7 @@ class VerilatedFstBuffer VL_NOT_FINAL {
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);

View File

@ -14,80 +14,11 @@
/// \file
/// \brief Verilated tracing in FST for SystemC implementation code
///
/// This file must be compiled and linked against all Verilated objects
/// that use --sc --trace-fst.
///
/// Use "verilator --sc --trace-fst" to add this to the Makefile for the linker.
/// This file is deprecated, only verilated_fst_sc.h is needed.
/// It is provided only for backward compatibility with user's linker scripts.
///
//=============================================================================
#include "verilatedos.h"
#include "verilated_fst_sc.h"
//======================================================================
//======================================================================
void VerilatedFstSc::open(const char* filename) {
if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {
vl_fatal(__FILE__, __LINE__, "VerilatedFstSc",
("%Error: VerilatedFstSc::open(\"" + std::string{filename}
+ "\") is called before sc_core::sc_start(). "
"Run sc_core::sc_start(sc_core::SC_ZERO_TIME) before opening a wave file.")
.c_str());
}
VerilatedFstC::open(filename);
}
//--------------------------------------------------
// SystemC 2.1.v1
// cppcheck-suppress unusedFunction
void VerilatedFstSc::write_comment(const std::string&) {}
void VerilatedFstSc::trace(const unsigned int&, const std::string&, const char**) {}
#define DECL_TRACE_METHOD_A(tp) \
void VerilatedFstSc::trace(const tp& object, const std::string& name) {}
#define DECL_TRACE_METHOD_B(tp) \
void VerilatedFstSc::trace(const tp& object, const std::string& name, int width) {}
// clang-format off
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
#ifdef VL_NO_LEGACY
#error "verilated_fst_sc.cpp is deprecated; verilated_fst_sc.h is self-sufficient"
#endif
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long )
DECL_TRACE_METHOD_B( sc_dt::int64 )
DECL_TRACE_METHOD_B( sc_dt::uint64 )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
// clang-format on
#undef DECL_TRACE_METHOD_A
#undef DECL_TRACE_METHOD_B
//********************************************************************

View File

@ -10,7 +10,7 @@
//=============================================================================
///
/// \file
/// \brief Verilator tracing in FST format for SystemC header
/// \brief Verilated tracing in FST format for SystemC header
///
/// User wrapper code should use this header when creating FST SystemC
/// traces.
@ -19,8 +19,8 @@
///
//=============================================================================
#ifndef _VERILATED_FST_SC_H_
#define _VERILATED_FST_SC_H_ 1
#ifndef VERILATOR_VERILATED_VCD_SC_H_
#define VERILATOR_VERILATED_VCD_SC_H_
#include "verilatedos.h"
@ -32,40 +32,48 @@
//=============================================================================
// VerilatedFstSc
///
/// This class is passed to the SystemC simulation kernel, just like a
/// documented SystemC trace format.
/// Class representing a Verilator-friendly FST trace format registered
/// with the SystemC simulation kernel, just like a SystemC-documented
/// trace format.
class VerilatedFstSc final : sc_trace_file, public VerilatedFstC {
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedFstSc);
public:
/// Construct a SC trace object, and register with the SystemC kernel
VerilatedFstSc() {
sc_get_curr_simcontext()->add_trace_file(this);
// We want to avoid a depreciated warning, but still be back compatible.
// Turning off the message just for this still results in an
// annoying "to turn off" message.
const sc_time t1sec(1, SC_SEC);
const sc_time t1sec{1, SC_SEC};
if (t1sec.to_default_time_units() != 0) {
const sc_time tunits(1.0 / t1sec.to_default_time_units(), SC_SEC);
const sc_time tunits{1.0 / t1sec.to_default_time_units(), SC_SEC};
spTrace()->set_time_unit(tunits.to_string());
}
spTrace()->set_time_resolution(sc_get_time_resolution().to_string());
}
/// Destruct, flush, and close the dump
~VerilatedFstSc() override { close(); }
// METHODS
/// Called by SystemC simulate()
// METHODS - for SC kernel
// Called by SystemC simulate()
void cycle(bool delta_cycle) override {
if (!delta_cycle) { this->dump(sc_time_stamp().to_double()); }
if (!delta_cycle) this->dump(sc_time_stamp().to_double());
}
// Override VerilatedFstC. Must be called after starting simulation.
// Note: this is not a virtual function in the base class, so no 'override'
virtual void open(const char* filename) VL_MT_SAFE;
virtual void open(const char* filename) VL_MT_SAFE {
if (VL_UNLIKELY(!sc_core::sc_get_curr_simcontext()->elaboration_done())) {
Verilated::scTraceBeforeElaborationError();
}
VerilatedFstC::open(filename);
}
private:
/// Fake outs for linker
// METHODS - Fake outs for linker
#ifdef NC_SYSTEMC
// Cadence Incisive has these as abstract functions so we must create them
@ -73,14 +81,16 @@ private:
#endif
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
//--------------------------------------------------
// SystemC 2.1.v1
#define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override;
#define DECL_TRACE_METHOD_B(tp) \
void trace(const tp& object, const std::string& name, int width) override;
//--------------------------------------------------
// SystemC 2.1.v1
void write_comment(const std::string&) override;
void trace(const unsigned int&, const std::string&, const char**) override;
void write_comment(const std::string&) override {}
void trace(const unsigned int&, const std::string&, const char**) override {}
#define DECL_TRACE_METHOD_A(tp) \
void trace(const tp& object, const std::string& name) override {}
#define DECL_TRACE_METHOD_B(tp) \
void trace(const tp& object, const std::string& name, int width) override {}
// clang-format off
// Formatting matches that of sc_trace.h

View File

@ -37,24 +37,26 @@
/// User code may wish to replace this function, to do so, define VL_USER_FINISH.
/// This code does not have to be thread safe.
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
extern void vl_finish(const char* filename, int linenum, const char* hier);
extern void vl_finish(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
/// Routine to call for $stop and non-fatal error
/// User code may wish to replace this function, to do so, define VL_USER_STOP.
/// This code does not have to be thread safe.
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
extern void vl_stop(const char* filename, int linenum, const char* hier);
extern void vl_stop(const char* filename, int linenum, const char* hier) VL_MT_UNSAFE;
/// Routine to call for fatal messages
/// User code may wish to replace this function, to do so, define VL_USER_FATAL.
/// This code does not have to be thread safe.
/// Verilator internal code must call VL_FINISH_MT instead, which eventually calls this.
extern void vl_fatal(const char* filename, int linenum, const char* hier, const char* msg);
extern void vl_fatal(const char* filename, int linenum, const char* hier,
const char* msg) VL_MT_UNSAFE;
/// Routine to call for warning messages
/// User code may wish to replace this function, to do so, define VL_USER_WARN.
/// This code does not have to be thread safe.
extern void vl_warn(const char* filename, int linenum, const char* hier, const char* msg);
extern void vl_warn(const char* filename, int linenum, const char* hier,
const char* msg) VL_MT_UNSAFE;
//=========================================================================
// Extern functions -- Slow path
@ -73,11 +75,7 @@ extern void VL_WARN_MT(const char* filename, int linenum, const char* hier,
// clang-format off
/// Print a string, multithread safe. Eventually VL_PRINTF will get called.
#ifdef VL_THREADED
extern void VL_PRINTF_MT(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
#else
# define VL_PRINTF_MT VL_PRINTF // The following parens will take care of themselves
#endif
// clang-format on
/// Print a debug message from internals with standard prefix, with printf style format
@ -86,7 +84,7 @@ extern void VL_DBG_MSGF(const char* formatp, ...) VL_ATTR_PRINTF(1) VL_MT_SAFE;
// EMIT_RULE: VL_RANDOM: oclean=dirty
inline IData VL_RANDOM_I() VL_MT_SAFE { return vl_rand64(); }
inline QData VL_RANDOM_Q() VL_MT_SAFE { return vl_rand64(); }
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp);
extern WDataOutP VL_RANDOM_W(int obits, WDataOutP outwp) VL_MT_SAFE;
extern IData VL_RANDOM_SEEDED_II(IData& seedr) VL_MT_SAFE;
extern IData VL_URANDOM_SEEDED_II(IData seed) VL_MT_SAFE;
inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
@ -104,50 +102,52 @@ inline IData VL_URANDOM_RANGE_I(IData hi, IData lo) {
// These are init time only, so slow is fine
/// Random reset a signal of given width
extern IData VL_RAND_RESET_I(int obits);
extern IData VL_RAND_RESET_I(int obits) VL_MT_SAFE;
/// Random reset a signal of given width
extern QData VL_RAND_RESET_Q(int obits);
extern QData VL_RAND_RESET_Q(int obits) VL_MT_SAFE;
/// Random reset a signal of given width
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp);
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
/// Zero reset a signal (slow - else use VL_ZERO_W)
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp);
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) VL_MT_SAFE;
extern void VL_PRINTTIMESCALE(const char* namep, const char* timeunitp,
const VerilatedContext* contextp) VL_MT_SAFE;
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP const lwp, WDataInP const rwp,
bool is_modulus);
bool is_modulus) VL_MT_SAFE;
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi);
extern IData VL_FGETS_IXI(int obits, void* destp, IData fpi) VL_MT_SAFE;
extern void VL_FFLUSH_I(IData fdi);
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin);
extern IData VL_FTELL_I(IData fdi);
extern void VL_FCLOSE_I(IData fdi);
extern void VL_FFLUSH_I(IData fdi) VL_MT_SAFE;
extern IData VL_FSEEK_I(IData fdi, IData offset, IData origin) VL_MT_SAFE;
extern IData VL_FTELL_I(IData fdi) VL_MT_SAFE;
extern void VL_FCLOSE_I(IData fdi) VL_MT_SAFE;
extern IData VL_FREAD_I(int width, int array_lsb, int array_size, void* memp, IData fpi,
IData start, IData count);
IData start, IData count) VL_MT_SAFE;
extern void VL_WRITEF(const char* formatp, ...);
extern void VL_FWRITEF(IData fpi, const char* formatp, ...);
extern void VL_WRITEF(const char* formatp, ...) VL_MT_SAFE;
extern void VL_FWRITEF(IData fpi, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...);
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
extern IData VL_SSCANF_IWX(int lbits, WDataInP const lwp, const char* formatp, ...);
extern IData VL_FSCANF_IX(IData fpi, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SSCANF_IWX(int lbits, WDataInP const lwp, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) VL_MT_SAFE;
extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) VL_MT_SAFE;
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp);
extern IData VL_SYSTEM_IQ(QData lhs);
extern void VL_STACKTRACE() VL_MT_SAFE;
extern std::string VL_STACKTRACE_N() VL_MT_SAFE;
extern IData VL_SYSTEM_IW(int lhswords, WDataInP const lhsp) VL_MT_SAFE;
extern IData VL_SYSTEM_IQ(QData lhs) VL_MT_SAFE;
inline IData VL_SYSTEM_II(IData lhs) VL_MT_SAFE { return VL_SYSTEM_IQ(lhs); }
extern IData VL_TESTPLUSARGS_I(const std::string& format);
extern const char* vl_mc_scan_plusargs(const char* prefixp); // PLIish
extern IData VL_TESTPLUSARGS_I(const std::string& format) VL_MT_SAFE;
extern const char* vl_mc_scan_plusargs(const char* prefixp) VL_MT_SAFE; // PLIish
//=========================================================================
// Base macros
@ -216,14 +216,14 @@ static inline double VL_ITOR_D_Q(int, QData lhs) VL_PURE {
return static_cast<double>(static_cast<uint64_t>(lhs));
}
// Return double from lhs (numeric) signed
double VL_ISTOR_D_W(int lbits, WDataInP const lwp) VL_PURE;
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_PURE {
double VL_ISTOR_D_W(int lbits, WDataInP const lwp) VL_MT_SAFE;
static inline double VL_ISTOR_D_I(int lbits, IData lhs) VL_MT_SAFE {
if (lbits == 32) return static_cast<double>(static_cast<int32_t>(lhs));
VlWide<VL_WQ_WORDS_E> lwp;
VL_SET_WI(lwp, lhs);
return VL_ISTOR_D_W(lbits, lwp);
}
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_PURE {
static inline double VL_ISTOR_D_Q(int lbits, QData lhs) VL_MT_SAFE {
if (lbits == 64) return static_cast<double>(static_cast<int64_t>(lhs));
VlWide<VL_WQ_WORDS_E> lwp;
VL_SET_WQ(lwp, lhs);
@ -251,7 +251,7 @@ static inline QData VL_EXTENDSIGN_Q(int lbits, QData lhs) VL_PURE {
}
// Debugging prints
extern void _vl_debug_print_w(int lbits, WDataInP const iwp);
extern void _vl_debug_print_w(int lbits, WDataInP const iwp) VL_MT_SAFE;
//=========================================================================
// Pli macros
@ -261,21 +261,22 @@ extern void _vl_debug_print_w(int lbits, WDataInP const iwp);
#if defined(SYSTEMC_VERSION)
/// Return current simulation time
// Already defined: extern sc_time sc_time_stamp();
inline uint64_t vl_time_stamp64() { return sc_time_stamp().value(); }
inline uint64_t vl_time_stamp64() VL_MT_SAFE { return sc_time_stamp().value(); }
#else // Non-SystemC
# if !defined(VL_TIME_CONTEXT) && !defined(VL_NO_LEGACY)
# ifdef VL_TIME_STAMP64
// vl_time_stamp64() may be optionally defined by the user to return time.
// On MSVC++ weak symbols are not supported so must be declared, or define
// VL_TIME_CONTEXT.
extern uint64_t vl_time_stamp64() VL_ATTR_WEAK;
extern uint64_t vl_time_stamp64() VL_ATTR_WEAK VL_MT_SAFE;
# else
// sc_time_stamp() may be optionally defined by the user to return time.
// On MSVC++ weak symbols are not supported so must be declared, or define
// VL_TIME_CONTEXT.
extern double sc_time_stamp() VL_ATTR_WEAK; // Verilator 4.032 and newer
inline uint64_t vl_time_stamp64() {
extern double sc_time_stamp() VL_ATTR_WEAK VL_MT_SAFE; // Verilator 4.032 and newer
inline uint64_t vl_time_stamp64() VL_MT_SAFE {
// clang9.0.1 requires & although we really do want the weak symbol value
// cppcheck-suppress duplicateValueTernary
return VL_LIKELY(&sc_time_stamp) ? static_cast<uint64_t>(sc_time_stamp()) : 0;
}
# endif
@ -448,16 +449,16 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
{ \
const int words = VL_WORDS_I(obits); \
sc_biguint<(obits)> _butemp = (svar).read(); \
uint32_t* chunk = _butemp.get_raw(); \
uint32_t* chunkp = _butemp.get_raw(); \
int32_t lsb = 0; \
while (lsb < obits - BITS_PER_DIGIT) { \
const uint32_t data = *chunk; \
++chunk; \
const uint32_t data = *chunkp; \
++chunkp; \
_vl_insert_WI(owp.data(), data, lsb + BITS_PER_DIGIT - 1, lsb); \
lsb += BITS_PER_DIGIT; \
} \
if (lsb < obits) { \
const uint32_t msb_data = *chunk; \
const uint32_t msb_data = *chunkp; \
_vl_insert_WI(owp.data(), msb_data, obits - 1, lsb); \
} \
(owp)[words - 1] &= VL_MASK_E(obits); \
@ -504,18 +505,18 @@ static inline void VL_ASSIGNBIT_WO(int bit, WDataOutP owp) VL_MT_SAFE {
{ \
sc_biguint<(obits)> _butemp; \
int32_t lsb = 0; \
uint32_t* chunk = _butemp.get_raw(); \
uint32_t* chunkp = _butemp.get_raw(); \
while (lsb + VL_SC_BITS_PER_DIGIT < (obits)) { \
static_assert(std::is_same<IData, EData>::value, "IData and EData missmatch"); \
const uint32_t data = VL_SEL_IWII(lsb + VL_SC_BITS_PER_DIGIT + 1, (rwp).data(), lsb, \
VL_SC_BITS_PER_DIGIT); \
*chunk = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \
++chunk; \
*chunkp = data & VL_MASK_E(VL_SC_BITS_PER_DIGIT); \
++chunkp; \
lsb += VL_SC_BITS_PER_DIGIT; \
} \
if (lsb < (obits)) { \
const uint32_t msb_data = VL_SEL_IWII((obits) + 1, (rwp).data(), lsb, (obits)-lsb); \
*chunk = msb_data & VL_MASK_E((obits)-lsb); \
*chunkp = msb_data & VL_MASK_E((obits)-lsb); \
} \
(svar).write(_butemp); \
}
@ -590,18 +591,19 @@ static inline WDataOutP VL_EXTENDS_WW(int obits, int lbits, WDataOutP owp,
// EMIT_RULE: VL_REDAND: oclean=clean; lclean==clean; obits=1;
#define VL_REDAND_II(lbits, lhs) ((lhs) == VL_MASK_I(lbits))
#define VL_REDAND_IQ(lbits, lhs) ((lhs) == VL_MASK_Q(lbits))
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_REDAND_IW(int lbits, WDataInP const lwp) VL_PURE {
const int words = VL_WORDS_I(lbits);
EData combine = lwp[0];
for (int i = 1; i < words - 1; ++i) combine &= lwp[i];
combine &= ~VL_MASK_E(lbits) | lwp[words - 1];
// cppcheck-has-bug-suppress knownConditionTrueFalse
return ((~combine) == 0);
}
// EMIT_RULE: VL_REDOR: oclean=clean; lclean==clean; obits=1;
#define VL_REDOR_I(lhs) ((lhs) != 0)
#define VL_REDOR_Q(lhs) ((lhs) != 0)
static inline IData VL_REDOR_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_REDOR_W(int words, WDataInP const lwp) VL_PURE {
EData equal = 0;
for (int i = 0; i < words; ++i) equal |= lwp[i];
return (equal != 0);
@ -668,7 +670,7 @@ static inline IData VL_REDXOR_64(QData r) VL_PURE {
return static_cast<IData>(r);
#endif
}
static inline IData VL_REDXOR_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_REDXOR_W(int words, WDataInP const lwp) VL_PURE {
EData r = lwp[0];
for (int i = 1; i < words; ++i) r ^= lwp[i];
return VL_REDXOR_32(r);
@ -687,7 +689,7 @@ static inline IData VL_COUNTONES_Q(QData lhs) VL_PURE {
return VL_COUNTONES_I(static_cast<IData>(lhs)) + VL_COUNTONES_I(static_cast<IData>(lhs >> 32));
}
#define VL_COUNTONES_E VL_COUNTONES_I
static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_COUNTONES_W(int words, WDataInP const lwp) VL_PURE {
EData r = 0;
for (int i = 0; i < words; ++i) r += VL_COUNTONES_E(lwp[i]);
return r;
@ -729,7 +731,7 @@ static inline IData VL_ONEHOT_I(IData lhs) VL_PURE {
static inline IData VL_ONEHOT_Q(QData lhs) VL_PURE {
return (((lhs & (lhs - 1)) == 0) & (lhs != 0));
}
static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_PURE {
EData one = 0;
for (int i = 0; (i < words); ++i) {
if (lwp[i]) {
@ -743,7 +745,7 @@ static inline IData VL_ONEHOT_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_ONEHOT0_I(IData lhs) VL_PURE { return ((lhs & (lhs - 1)) == 0); }
static inline IData VL_ONEHOT0_Q(QData lhs) VL_PURE { return ((lhs & (lhs - 1)) == 0); }
static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_ONEHOT0_W(int words, WDataInP const lwp) VL_PURE {
bool one = false;
for (int i = 0; (i < words); ++i) {
if (lwp[i]) {
@ -770,7 +772,7 @@ static inline IData VL_CLOG2_Q(QData lhs) VL_PURE {
for (; lhs != 0; ++shifts) lhs = lhs >> 1ULL;
return shifts;
}
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_PURE {
const EData adjust = (VL_COUNTONES_W(words, lwp) == 1) ? 0 : 1;
for (int i = words - 1; i >= 0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
@ -785,7 +787,7 @@ static inline IData VL_CLOG2_W(int words, WDataInP const lwp) VL_MT_SAFE {
return 0;
}
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_MT_SAFE {
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP const lwp) VL_PURE {
// MSB set bit plus one; similar to FLS. 0=value is zero
for (int i = words - 1; i >= 0; --i) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
@ -814,7 +816,7 @@ static inline WDataOutP VL_OR_W(int words, WDataOutP owp, WDataInP const lwp,
return owp;
}
// EMIT_RULE: VL_CHANGEXOR: oclean=1; obits=32; lbits==rbits;
static inline IData VL_CHANGEXOR_W(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
static inline IData VL_CHANGEXOR_W(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
IData od = 0;
for (int i = 0; (i < words); ++i) od |= (lwp[i] ^ rwp[i]);
return od;
@ -847,14 +849,14 @@ static inline WDataOutP VL_NOT_W(int words, WDataOutP owp, WDataInP const lwp) V
#define VL_GTE_W(words, lwp, rwp) (_vl_cmp_w(words, lwp, rwp) >= 0)
// Output clean, <lhs> AND <rhs> MUST BE CLEAN
static inline IData VL_EQ_W(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
static inline IData VL_EQ_W(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
EData nequal = 0;
for (int i = 0; (i < words); ++i) nequal |= (lwp[i] ^ rwp[i]);
return (nequal == 0);
}
// Internal usage
static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
static inline int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE {
for (int i = words - 1; i >= 0; --i) {
if (lwp[i] > rwp[i]) return 1;
if (lwp[i] < rwp[i]) return -1;
@ -913,7 +915,7 @@ static inline IData VL_LTES_IQQ(int lbits, QData lhs, QData rhs) VL_PURE {
return lhs_signed <= rhs_signed;
}
static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE {
static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp) VL_PURE {
const int words = VL_WORDS_I(lbits);
int i = words - 1;
// We need to flip sense if negative comparison
@ -929,7 +931,7 @@ static inline int _vl_cmps_w(int lbits, WDataInP const lwp, WDataInP const rwp)
}
//=========================================================================
// Math
// Expressions
// Output NOT clean
static inline WDataOutP VL_NEGATE_W(int words, WDataOutP owp, WDataInP const lwp) VL_MT_SAFE {
@ -1026,12 +1028,14 @@ static inline WDataOutP VL_MULS_WWW(int lbits, WDataOutP owp, WDataInP const lwp
if (lneg) { // Negate lhs
lwusp = lwstore;
VL_NEGATE_W(words, lwstore, lwp);
// cppcheck-has-bug-suppress unreadVariable
lwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
}
const EData rneg = VL_SIGN_E(lbits, rwp[words - 1]);
if (rneg) { // Negate rhs
rwusp = rwstore;
VL_NEGATE_W(words, rwstore, rwp);
// cppcheck-has-bug-suppress unreadVariable
rwstore[words - 1] &= VL_MASK_E(lbits); // Clean it
}
VL_MUL_W(words, owp, lwusp, rwusp);
@ -1156,9 +1160,10 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) VL_PUR
return out;
}
WDataOutP VL_POW_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
WDataInP const rwp);
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp, QData rhs);
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp);
WDataInP const rwp) VL_MT_SAFE;
WDataOutP VL_POW_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
QData rhs) VL_MT_SAFE;
QData VL_POW_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp) VL_MT_SAFE;
#define VL_POWSS_IIQ(obits, lbits, rbits, lhs, rhs, lsign, rsign) \
VL_POWSS_QQQ(obits, lbits, rbits, lhs, rhs, lsign, rsign)
@ -1210,11 +1215,11 @@ static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs
return VL_POW_QQQ(obits, rbits, rbits, lhs, rhs);
}
WDataOutP VL_POWSS_WWW(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp,
WDataInP const rwp, bool lsign, bool rsign);
WDataInP const rwp, bool lsign, bool rsign) VL_MT_SAFE;
WDataOutP VL_POWSS_WWQ(int obits, int, int rbits, WDataOutP owp, WDataInP const lwp, QData rhs,
bool lsign, bool rsign);
bool lsign, bool rsign) VL_MT_SAFE;
QData VL_POWSS_QQW(int obits, int, int rbits, QData lhs, WDataInP const rwp, bool lsign,
bool rsign);
bool rsign) VL_MT_SAFE;
//===================================================================
// Concat/replication
@ -1392,7 +1397,7 @@ static inline IData VL_STREAML_FAST_III(int lbits, IData ld, IData rd_log2) VL_P
//
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
// then we end up with a "gap" in our reversed result. For example, if we
// have a 5-bit Verlilog signal (lbits=5) in an 8-bit C data type:
// have a 5-bit Verilog signal (lbits=5) in an 8-bit C data type:
//
// ld = ---43210
//
@ -1917,7 +1922,7 @@ static inline WDataOutP VL_SEL_WWII(int obits, int lbits, WDataOutP owp, WDataIn
}
//======================================================================
// Math needing insert/select
// Expressions needing insert/select
// Return QData from double (numeric)
// EMIT_RULE: VL_RTOIROUND_Q_D: oclean=dirty; lclean==clean/real
@ -1941,7 +1946,7 @@ static inline QData VL_RTOIROUND_Q_D(double lhs) VL_PURE {
static inline IData VL_RTOIROUND_I_D(double lhs) VL_PURE {
return static_cast<IData>(VL_RTOIROUND_Q_D(lhs));
}
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_PURE {
static inline WDataOutP VL_RTOIROUND_W_D(int obits, WDataOutP owp, double lhs) VL_MT_SAFE {
// IEEE format: [63]=sign [62:52]=exp+1023 [51:0]=mantissa
// This does not need to support subnormals as they are sub-integral
lhs = VL_ROUND(lhs);
@ -2151,7 +2156,18 @@ inline IData VL_CMP_NN(const std::string& lhs, const std::string& rhs, bool igno
extern IData VL_ATOI_N(const std::string& str, int base) VL_PURE;
extern IData VL_FGETS_NI(std::string& dest, IData fpi);
extern IData VL_FGETS_NI(std::string& dest, IData fpi) VL_MT_SAFE;
//======================================================================
// Dist functions
extern IData VL_DIST_CHI_SQUARE(IData& seedr, IData udeg_of_free) VL_MT_SAFE;
extern IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE;
extern IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE;
extern IData VL_DIST_NORMAL(IData& seedr, IData umean, IData udeviation) VL_MT_SAFE;
extern IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE;
extern IData VL_DIST_T(IData& seedr, IData udeg_of_free) VL_MT_SAFE;
extern IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE;
//======================================================================
// Conversion functions
@ -2183,8 +2199,8 @@ inline std::string VL_REPLICATEN_NNI(const std::string& lhs, IData rep) VL_PURE
}
inline IData VL_LEN_IN(const std::string& ld) { return ld.length(); }
extern std::string VL_TOLOWER_NN(const std::string& ld);
extern std::string VL_TOUPPER_NN(const std::string& ld);
extern std::string VL_TOLOWER_NN(const std::string& ld) VL_PURE;
extern std::string VL_TOUPPER_NN(const std::string& ld) VL_PURE;
extern IData VL_FERROR_IN(IData fpi, std::string& outputr) VL_MT_SAFE;
extern IData VL_FOPEN_NN(const std::string& filename, const std::string& mode) VL_MT_SAFE;

View File

@ -41,10 +41,8 @@
#include <string>
#include <utility>
#include <vector>
#ifdef VL_THREADED
# include <functional>
# include <queue>
#endif
#include <functional>
#include <queue>
// clang-format on
class VerilatedScope;
@ -52,7 +50,6 @@ class VerilatedScope;
//======================================================================
// Threaded message passing
#ifdef VL_THREADED
// Message, enqueued on an mtask, and consumed on the main eval thread
class VerilatedMsg final {
public:
@ -152,7 +149,7 @@ private:
VL_UNCOPYABLE(VerilatedThreadMsgQueue);
// METHODS
static VerilatedThreadMsgQueue& threadton() {
static VL_THREAD_LOCAL VerilatedThreadMsgQueue t_s;
static thread_local VerilatedThreadMsgQueue t_s;
return t_s;
}
@ -178,7 +175,6 @@ public:
}
}
};
#endif // VL_THREADED
// FILE* list constructed from a file-descriptor
class VerilatedFpList final {
@ -230,7 +226,7 @@ class VerilatedContextImp final : VerilatedContext {
// Number incrementing on each reseed, 0=illegal
int s_randSeedEpoch = 1; // Reads ok, wish had a VL_WRITE_GUARDED_BY(s_randMutex)
};
static Statics& s() {
static Statics& s() VL_MT_SAFE {
static Statics s_s;
return s_s;
}
@ -366,6 +362,7 @@ public: // But only for verilated*.cpp
private:
VerilatedFpList fdToFpList(IData fdi) VL_REQUIRES(m_fdMutex) {
VerilatedFpList fp;
// cppverilator-suppress integerOverflow shiftTooManyBitsSigned
if ((fdi & (1 << 31)) != 0) {
// Non-MCD case
const IData idx = fdi & VL_MASK_I(31);
@ -390,7 +387,9 @@ private:
protected:
// METHODS - protected
void commandArgsAddGuts(int argc, const char** argv);
void commandArgsGuts(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
void commandArgsAddGutsLock(int argc, const char** argv) VL_MT_SAFE_EXCLUDES(m_argMutex);
void commandArgsAddGuts(int argc, const char** argv) VL_REQUIRES(m_argMutex);
void commandArgVl(const std::string& arg);
bool commandArgVlString(const std::string& arg, const std::string& prefix,
std::string& valuer);
@ -444,7 +443,7 @@ protected:
friend class Verilated;
// MEMBERS
static VerilatedImpData& s() { // Singleton
static VerilatedImpData& s() VL_MT_SAFE { // Singleton
static VerilatedImpData s_s;
return s_s;
}

View File

@ -0,0 +1,240 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Code available from: https://verilator.org
//
// Copyright 2003-2022 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//=========================================================================
///
/// \file
/// \brief Verilated probability distribution implementation code
///
/// Verilator always adds this file to the Makefile for the linker.
///
/// Those macro/function/variable starting or ending in _ are internal,
/// however many of the other function/macros here are also internal.
///
//=========================================================================
#include "verilated_config.h"
#include "verilatedos.h"
#include "verilated.h"
//===========================================================================
// Dist
static double _vl_dbase_uniform(IData& seedr, int32_t start, int32_t end) VL_MT_SAFE {
union u_s {
float s;
unsigned stemp;
} u;
const double d = 0.00000011920928955078125;
if (VL_UNLIKELY(seedr == 0)) seedr = 259341593;
double a;
double b;
if (VL_UNCOVERABLE(start >= end)) { // With current usage shound't occur
a = 0.0; // LCOV_EXCL_LINE
b = 2147483647.0; // LCOV_EXCL_LINE
} else {
a = static_cast<double>(start);
b = static_cast<double>(end);
}
seedr = 69069 * seedr + 1;
u.stemp = seedr;
u.stemp = (u.stemp >> 9) | 0x3f800000;
double c = static_cast<double>(u.s);
c = c + (c * d);
c = ((b - a) * (c - 1.0)) + a;
return c;
}
static double _vl_dbase_normal(IData& seedr, int32_t mean, int32_t deviation) VL_MT_SAFE {
double v1 = 0.0;
double v2 = 0.0;
double s = 1.0;
while ((s >= 1.0) || (s == 0.0)) {
v1 = _vl_dbase_uniform(seedr, -1, 1);
v2 = _vl_dbase_uniform(seedr, -1, 1);
s = v1 * v1 + v2 * v2;
}
s = v1 * std::sqrt(-2.0 * log(s) / s);
v1 = static_cast<double>(deviation);
v2 = static_cast<double>(mean);
return (s * v1 + v2);
}
static double _vl_dbase_exponential(IData& seedr, int32_t mean) VL_MT_SAFE {
double n = _vl_dbase_uniform(seedr, 0, 1);
if (n != 0) n = -log(n) * mean;
return n;
}
static double _vl_dbase_chi_square(IData& seedr, int32_t deg_of_free) VL_MT_SAFE {
double x;
if (deg_of_free % 2) {
x = _vl_dbase_normal(seedr, 0, 1);
x = x * x;
} else {
x = 0.0;
}
for (int32_t k = 2; k <= deg_of_free; k += 2) x = x + 2 * _vl_dbase_exponential(seedr, 1);
return x;
}
IData VL_DIST_CHI_SQUARE(IData& seedr, IData udf) VL_MT_SAFE {
const int32_t df = static_cast<int32_t>(udf);
if (VL_UNLIKELY(df <= 0)) {
// Chi_square distribution must have positive degree of freedom
return 0;
}
double r = _vl_dbase_chi_square(seedr, df);
int32_t i;
if (r >= 0) {
i = static_cast<int32_t>(r + 0.5);
} else {
r = -r; // LCOV_EXCL_LINE
i = static_cast<int32_t>(r + 0.5); // LCOV_EXCL_LINE
i = -i; // LCOV_EXCL_LINE
}
return static_cast<IData>(i);
}
IData VL_DIST_ERLANG(IData& seedr, IData uk, IData umean) VL_MT_SAFE {
const int32_t k = static_cast<int32_t>(uk);
const int32_t mean = static_cast<int32_t>(umean);
if (VL_UNLIKELY(k <= 0)) {
// k-stage erlangian distribution must have positive k
return 0;
}
double x = 1.0;
for (int32_t i = 1; i <= k; i++) { x = x * _vl_dbase_uniform(seedr, 0, 1); }
const double a = static_cast<double>(mean);
const double b = static_cast<double>(k);
double r = -a * log(x) / b;
int32_t i;
if (r >= 0) {
i = static_cast<int32_t>(r + 0.5);
} else {
r = -r;
i = static_cast<int32_t>(r + 0.5);
i = -i;
}
return static_cast<IData>(i);
}
IData VL_DIST_EXPONENTIAL(IData& seedr, IData umean) VL_MT_SAFE {
const int32_t mean = static_cast<int32_t>(umean);
if (VL_UNLIKELY(mean <= 0)) {
// Exponential distribution must have a positive mean
return 0;
}
int32_t i;
double r = _vl_dbase_exponential(seedr, mean);
if (r >= 0) {
i = static_cast<int32_t>(r + 0.5);
} else {
r = -r; // LCOV_EXCL_LINE
i = static_cast<int32_t>(r + 0.5); // LCOV_EXCL_LINE
i = -i; // LCOV_EXCL_LINE
}
return static_cast<IData>(i);
}
IData VL_DIST_NORMAL(IData& seedr, IData umean, IData usd) VL_MT_SAFE {
const int32_t mean = static_cast<int32_t>(umean);
const int32_t sd = static_cast<int32_t>(usd);
double r = _vl_dbase_normal(seedr, mean, sd);
int32_t i;
if (r >= 0) {
i = static_cast<int32_t>(r + 0.5);
} else {
r = -r;
i = static_cast<int32_t>(r + 0.5);
i = -i;
}
return static_cast<IData>(i);
}
IData VL_DIST_POISSON(IData& seedr, IData umean) VL_MT_SAFE {
const int32_t mean = static_cast<int32_t>(umean);
if (VL_UNLIKELY(mean <= 0)) {
// Poisson distribution must have a positive mean
return 0;
}
int32_t i = 0;
double q = -static_cast<double>(mean);
double p = exp(q);
q = _vl_dbase_uniform(seedr, 0, 1);
while (p < q) {
++i;
q = _vl_dbase_uniform(seedr, 0, 1) * q;
}
return static_cast<IData>(i);
}
IData VL_DIST_T(IData& seedr, IData udf) VL_MT_SAFE {
const int32_t df = static_cast<int32_t>(udf);
if (VL_UNLIKELY(df <= 0)) {
// t distribution must have positive degree of freedom
return 0;
}
const double chi2 = _vl_dbase_chi_square(seedr, df);
const double div = chi2 / static_cast<double>(df);
const double root = std::sqrt(div);
double r = _vl_dbase_normal(seedr, 0, 1) / root;
int32_t i;
if (r >= 0) {
i = static_cast<int32_t>(r + 0.5);
} else {
r = -r;
i = static_cast<int32_t>(r + 0.5);
i = -i;
}
return static_cast<IData>(i);
}
IData VL_DIST_UNIFORM(IData& seedr, IData ustart, IData uend) VL_MT_SAFE {
int32_t start = static_cast<int32_t>(ustart);
int32_t end = static_cast<int32_t>(uend);
if (VL_UNLIKELY(start >= end)) return start;
int32_t i;
if (end != std::numeric_limits<int32_t>::max()) {
++end;
const double r = _vl_dbase_uniform(seedr, start, end);
if (r >= 0) {
i = static_cast<int32_t>(r);
} else {
i = static_cast<int32_t>(r - 1);
}
if (i < start) i = start;
if (i >= end) i = end - 1;
} else if (start != std::numeric_limits<int32_t>::min()) {
--start;
const double r = _vl_dbase_uniform(seedr, start, end) + 1.0;
if (r >= 0) {
i = static_cast<int32_t>(r);
} else {
i = static_cast<int32_t>(r - 1); // LCOV_EXCL_LINE
}
if (i <= start) i = start + 1;
if (i > end) i = end;
} else {
double r = (_vl_dbase_uniform(seedr, start, end) + 2147483648.0) / 4294967295.0;
r = r * 4294967296.0 - 2147483648.0;
if (r >= 0) {
i = static_cast<int32_t>(r);
} else {
i = static_cast<int32_t>(r - 1);
}
}
return static_cast<IData>(i);
}

View File

@ -20,9 +20,7 @@
#include "verilated_profiler.h"
#if VL_THREADED
#include "verilated_threads.h"
#endif
#include <fstream>
#include <string>
@ -32,7 +30,7 @@
// Internal note: Globals may multi-construct, see verilated.cpp top.
VL_THREAD_LOCAL VlExecutionProfiler::ExecutionTrace VlExecutionProfiler::t_trace;
thread_local VlExecutionProfiler::ExecutionTrace VlExecutionProfiler::t_trace;
constexpr const char* const VlExecutionRecord::s_ascii[];
@ -105,7 +103,6 @@ void VlExecutionProfiler::configure() {
VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context) {
VlExecutionProfiler* const selfp = new VlExecutionProfiler{context};
#if VL_THREADED
if (VlThreadPool* const threadPoolp = static_cast<VlThreadPool*>(context.threadPoolp())) {
for (int i = 0; i < threadPoolp->numThreads(); ++i) {
// Data to pass to worker thread initialization
@ -122,11 +119,10 @@ VerilatedVirtualBase* VlExecutionProfiler::construct(VerilatedContext& context)
},
&data);
// Wait until initializationis complete
// Wait until initialization is complete
threadPoolp->workerp(i)->wait();
}
}
#endif
return selfp;
}
@ -172,14 +168,12 @@ void VlExecutionProfiler::dump(const char* filenamep, uint64_t tickEnd)
Verilated::threadContextp()->profExecWindow());
const unsigned threads = static_cast<unsigned>(m_traceps.size());
fprintf(fp, "VLPROF stat threads %u\n", threads);
#ifdef VL_THREADED
fprintf(fp, "VLPROF stat yields %" PRIu64 "\n", VlMTaskVertex::yields());
#endif
// Copy /proc/cpuinfo into this output so verilator_gantt can be run on
// a different machine
{
const std::unique_ptr<std::ifstream> ifp{new std::ifstream("/proc/cpuinfo")};
const std::unique_ptr<std::ifstream> ifp{new std::ifstream{"/proc/cpuinfo"}};
if (!ifp->fail()) {
std::string line;
while (std::getline(*ifp, line)) { fprintf(fp, "VLPROFPROC %s\n", line.c_str()); }

View File

@ -151,7 +151,7 @@ class VlExecutionProfiler final : public VerilatedVirtualBase {
// STATE
VerilatedContext& m_context; // The context this profiler is under
static VL_THREAD_LOCAL ExecutionTrace t_trace; // thread-local trace buffers
static thread_local ExecutionTrace t_trace; // thread-local trace buffers
mutable VerilatedMutex m_mutex;
// Map from thread id to &t_trace of given thread
std::map<uint32_t, ExecutionTrace*> m_traceps VL_GUARDED_BY(m_mutex);

View File

@ -172,18 +172,18 @@ void VerilatedRestore::open(const char* filenamep) VL_MT_UNSAFE_ONE {
header();
}
void VerilatedSave::close() VL_MT_UNSAFE_ONE {
void VerilatedSave::closeImp() VL_MT_UNSAFE_ONE {
if (!isOpen()) return;
trailer();
flush();
flushImp();
m_isOpen = false;
::close(m_fd); // May get error, just ignore it
}
void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
void VerilatedRestore::closeImp() VL_MT_UNSAFE_ONE {
if (!isOpen()) return;
trailer();
flush();
flushImp();
m_isOpen = false;
::close(m_fd); // May get error, just ignore it
}
@ -191,7 +191,7 @@ void VerilatedRestore::close() VL_MT_UNSAFE_ONE {
//=============================================================================
// Buffer management
void VerilatedSave::flush() VL_MT_UNSAFE_ONE {
void VerilatedSave::flushImp() VL_MT_UNSAFE_ONE {
m_assertOne.check();
if (VL_UNLIKELY(!isOpen())) return;
const uint8_t* wp = m_bufp;

View File

@ -62,9 +62,9 @@ public:
m_bufp = new uint8_t[bufferSize()];
m_cp = m_bufp;
}
/// Flish, close, and destruct
/// Flush, close, and destruct
virtual ~VerilatedSerialize() {
close();
// Child classes will need to typically call closeImp() in destructors
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
}
// METHODS
@ -137,7 +137,7 @@ public:
}
/// Destruct
virtual ~VerilatedDeserialize() {
close();
// Child classes will need to typically call closeImp() in destructors
if (m_bufp) VL_DO_CLEAR(delete[] m_bufp, m_bufp = nullptr);
}
// METHODS
@ -190,21 +190,24 @@ class VerilatedSave final : public VerilatedSerialize {
private:
int m_fd = -1; // File descriptor we're writing to
void closeImp() VL_MT_UNSAFE_ONE;
void flushImp() VL_MT_UNSAFE_ONE;
public:
// CONSTRUCTORS
/// Construct new object
VerilatedSave() = default;
/// Flush, close and destruct
~VerilatedSave() override { close(); }
~VerilatedSave() override { closeImp(); }
// METHODS
/// Open the file; call isOpen() to see if errors
void open(const char* filenamep) VL_MT_UNSAFE_ONE;
/// Open the file; call isOpen() to see if errors
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
/// Flush and close the file
void close() override VL_MT_UNSAFE_ONE;
void close() override VL_MT_UNSAFE_ONE { closeImp(); }
/// Flush data to file
void flush() override VL_MT_UNSAFE_ONE;
void flush() override VL_MT_UNSAFE_ONE { flushImp(); }
};
//=============================================================================
@ -217,12 +220,15 @@ class VerilatedRestore final : public VerilatedDeserialize {
private:
int m_fd = -1; // File descriptor we're writing to
void closeImp() VL_MT_UNSAFE_ONE;
void flushImp() VL_MT_UNSAFE_ONE {}
public:
// CONSTRUCTORS
/// Construct new object
VerilatedRestore() = default;
/// Flush, close and destruct
~VerilatedRestore() override { close(); }
~VerilatedRestore() override { closeImp(); }
// METHODS
/// Open the file; call isOpen() to see if errors
@ -230,8 +236,8 @@ public:
/// Open the file; call isOpen() to see if errors
void open(const std::string& filename) VL_MT_UNSAFE_ONE { open(filename.c_str()); }
/// Close the file
void close() override VL_MT_UNSAFE_ONE;
void flush() override VL_MT_UNSAFE_ONE {}
void close() override VL_MT_UNSAFE_ONE { closeImp(); }
void flush() override VL_MT_UNSAFE_ONE { flushImp(); }
void fill() override VL_MT_UNSAFE_ONE;
};

117
include/verilated_std.sv Normal file
View File

@ -0,0 +1,117 @@
// DESCRIPTION: Verilator: built-in packages and classes
//
// Code available from: https://verilator.org
//
//*************************************************************************
//
// Copyright 2022 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU Lesser
// General Public License Version 3 or the Perl Artistic License Version 2.0.
// SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
//
//*************************************************************************
///
/// \file
/// \brief Verilated IEEE std:: header
///
/// This file is included automatically by Verilator when a std::mailbox or
/// std::semaphore is referenced.
///
/// This file is not part of the Verilated public-facing API.
/// It is only for internal use.
///
//*************************************************************************
// verilator lint_off DECLFILENAME
// verilator lint_off TIMESCALEMOD
// verilator lint_off UNUSEDSIGNAL
package std;
class mailbox #(type T);
protected int m_bound;
protected T m_queue[$];
function new(int bound = 0);
m_bound = bound;
endfunction
function int num();
return m_queue.size();
endfunction
task put(T message);
`ifdef VERILATOR_TIMING
if (m_bound != 0)
wait (m_queue.size() < m_bound);
m_queue.push_back(message);
`endif
endtask
function int try_put(T message);
if (num() < m_bound) begin
m_queue.push_back(message);
return 1;
end
return 0;
endfunction
task get(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue.pop_front();
`endif
endtask
function int try_get(ref T message);
if (num() > 0) begin
message = m_queue.pop_front();
return 1;
end
return 0;
endfunction
task peek(ref T message);
`ifdef VERILATOR_TIMING
wait (m_queue.size() > 0);
message = m_queue[0];
`endif
endtask
function int try_peek(ref T message);
if (num() > 0) begin
message = m_queue[0];
return 1;
end
return 0;
endfunction
endclass
class semaphore;
protected int m_keyCount;
function new(int keyCount = 0);
m_keyCount = keyCount;
endfunction
function void put(int keyCount = 1);
m_keyCount += keyCount;
endfunction
task get(int keyCount = 1);
`ifdef VERILATOR_TIMING
wait (m_keyCount >= keyCount);
m_keyCount -= keyCount;
`endif
endtask
function int try_get(int keyCount = 1);
if (m_keyCount >= keyCount) begin
m_keyCount -= keyCount;
return 1;
end
return 0;
endfunction
endclass
endpackage
// verilator lint_off IMPORTSTAR
import std::*;

View File

@ -53,14 +53,14 @@ public:
: m_left{left}
, m_right{right} {}
~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; }
int high() const { return (m_left > m_right) ? m_left : m_right; }
int elements() const {
int left() const VL_PURE { return m_left; }
int right() const VL_PURE { return m_right; }
int low() const VL_PURE { return (m_left < m_right) ? m_left : m_right; }
int high() const VL_PURE { return (m_left > m_right) ? m_left : m_right; }
int elements() const VL_PURE {
return (VL_LIKELY(m_left >= m_right) ? (m_left - m_right + 1) : (m_right - m_left + 1));
}
int increment() const { return (m_left >= m_right) ? 1 : -1; }
int increment() const VL_PURE { return (m_left >= m_right) ? 1 : -1; }
};
//===========================================================================

View File

@ -27,15 +27,6 @@
#include "verilated.h" // for VerilatedMutex and clang annotations
#ifndef VL_THREADED
// Hitting this likely means verilated_threads.cpp is being compiled when
// 'verilator --threads' was not used. 'verilator --threads' sets
// VL_THREADED.
// Alternatively it is always safe but may harm performance to always
// define VL_THREADED for all compiles.
#error "verilated_threads.h/cpp expected VL_THREADED (from verilator --threads)"
#endif
#include <atomic>
#include <condition_variable>
#include <set>
@ -226,7 +217,7 @@ public:
int numThreads() const { return m_workers.size(); }
VlWorkerThread* workerp(int index) {
assert(index >= 0);
assert(index < m_workers.size());
assert(static_cast<size_t>(index) < m_workers.size());
return m_workers[index];
}

View File

@ -194,7 +194,7 @@ public:
//=============================================================================
// VlTriggerScheduler stores coroutines to be resumed by a trigger. It does not keep track of its
// trigger, relying on calling code to resume when appropriate. Coroutines are kept in two stages
// - 'uncommitted' and 'ready'. Whenever a coroutine is suspended, it lands in the 'uncommited'
// - 'uncommitted' and 'ready'. Whenever a coroutine is suspended, it lands in the 'uncommitted'
// stage. Only when commit() is called, these coroutines get moved to the 'ready' stage. That's
// when they can be resumed. This is done to avoid resuming processes before they start waiting.
@ -404,11 +404,13 @@ public:
// CONSTRUCTORS
// Construct
// cppcheck-suppress noExplicitConstructor
VlCoroutine(VlPromise* promisep)
: m_promisep{promisep} {
m_promisep->m_corop = this;
}
// Move. Update the pointers each time the return object is moved
// cppcheck-suppress noExplicitConstructor
VlCoroutine(VlCoroutine&& other)
: m_promisep{std::exchange(other.m_promisep, nullptr)} {
if (m_promisep) m_promisep->m_corop = this;

View File

@ -35,10 +35,8 @@
#include <unordered_set>
#include <vector>
#ifdef VL_THREADED
# include <deque>
# include <thread>
#endif
#include <deque>
#include <thread>
// clang-format on
@ -48,7 +46,6 @@ class VerilatedTraceBuffer;
template <class T_Buffer>
class VerilatedTraceOffloadBuffer;
#ifdef VL_THREADED
//=============================================================================
// Offloaded tracing
@ -110,6 +107,7 @@ public:
CHG_QDATA = 0x5,
CHG_WDATA = 0x6,
CHG_DOUBLE = 0x8,
CHG_EVENT = 0x9,
// TODO: full..
TIME_CHANGE = 0xc,
TRACE_BUFFER = 0xd,
@ -117,7 +115,6 @@ public:
SHUTDOWN = 0xf // Shutdown worker thread, also marks end of buffer
};
};
#endif
//=============================================================================
// VerilatedTraceConfig
@ -186,10 +183,9 @@ private:
, m_userp{userp} {}
};
bool m_offload = false; // Use the offload thread (ignored if !VL_THREADED)
bool m_parallel = false; // Use parallel tracing (ignored if !VL_THREADED)
bool m_offload = false; // Use the offload thread
bool m_parallel = false; // Use parallel tracing
#ifdef VL_THREADED
struct ParallelWorkerData {
const dumpCb_t m_cb; // The callback
void* const m_userp; // The use pointer to pass to the callback
@ -209,7 +205,6 @@ private:
// Passed a ParallelWorkerData*, second argument is ignored
static void parallelWorkerTask(void*, bool);
#endif
protected:
uint32_t* m_sigs_oldvalp = nullptr; // Previous value store
@ -251,7 +246,6 @@ private:
// Close the file on termination
static void onExit(void* selfp) VL_MT_UNSAFE_ONE;
#ifdef VL_THREADED
// Number of total offload buffers that have been allocated
uint32_t m_numOffloadBuffers = 0;
// Size of offload buffers
@ -282,7 +276,6 @@ private:
// Shut down and join worker, if it's running, otherwise do nothing
void shutdownOffloadWorker();
#endif
// CONSTRUCTORS
VL_UNCOPYABLE(VerilatedTrace);
@ -317,13 +310,8 @@ protected:
void closeBase();
void flushBase();
#ifdef VL_THREADED
bool offload() const { return m_offload; }
bool parallel() const { return m_parallel; }
#else
static constexpr bool offload() { return false; }
static constexpr bool parallel() { return false; }
#endif
//=========================================================================
// Virtual functions to be provided by the format specific implementation
@ -435,6 +423,7 @@ public:
void fullQData(uint32_t* oldp, QData newval, int bits);
void fullWData(uint32_t* oldp, const WData* newvalp, int bits);
void fullDouble(uint32_t* oldp, double newval);
void fullEvent(uint32_t* oldp, VlEvent newval);
// In non-offload mode, these are called directly by the trace callbacks,
// and are called chg*. In offload mode, they are called by the worker
@ -469,13 +458,13 @@ public:
}
}
}
VL_ATTR_ALWINLINE void chgEvent(uint32_t* oldp, VlEvent newval) { fullEvent(oldp, newval); }
VL_ATTR_ALWINLINE void chgDouble(uint32_t* oldp, double newval) {
// cppcheck-suppress invalidPointerCast
if (VL_UNLIKELY(*reinterpret_cast<double*>(oldp) != newval)) fullDouble(oldp, newval);
}
};
#ifdef VL_THREADED
//=============================================================================
// VerilatedTraceOffloadBuffer
@ -547,7 +536,12 @@ public:
m_offloadBufferWritep += 4;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
}
void chgEvent(uint32_t code, VlEvent newval) {
m_offloadBufferWritep[0] = VerilatedTraceOffloadCommand::CHG_EVENT;
m_offloadBufferWritep[1] = code;
m_offloadBufferWritep += 2;
VL_DEBUG_IF(assert(m_offloadBufferWritep <= m_offloadBufferEndp););
}
};
#endif
#endif // guard

View File

@ -26,10 +26,8 @@
#include "verilated_intrinsics.h"
#include "verilated_trace.h"
#ifdef VL_THREADED
# include "verilated_threads.h"
# include <list>
#endif
#include "verilated_threads.h"
#include <list>
#if 0
# include <iostream>
@ -43,7 +41,7 @@
//=============================================================================
// Static utility functions
static double timescaleToDouble(const char* unitp) {
static double timescaleToDouble(const char* unitp) VL_PURE {
char* endp = nullptr;
double value = std::strtod(unitp, &endp);
// On error so we allow just "ns" to return 1e-9.
@ -62,7 +60,7 @@ static double timescaleToDouble(const char* unitp) {
return value;
}
static std::string doubleToTimescale(double value) {
static std::string doubleToTimescale(double value) VL_PURE {
const char* suffixp = "s";
// clang-format off
if (value >= 1e0) { suffixp = "s"; value *= 1e0; }
@ -78,14 +76,13 @@ static std::string doubleToTimescale(double value) {
return valuestr; // Gets converted to string, so no ref to stack
}
#ifdef VL_THREADED
//=========================================================================
// Buffer management
template <>
uint32_t* VerilatedTrace<VL_SUB_T, VL_BUF_T>::getOffloadBuffer() {
uint32_t* bufferp;
// Some jitter is expected, so some number of alternative offlaod buffers are
// Some jitter is expected, so some number of alternative offload buffers are
// required, but don't allocate more than 8 buffers.
if (m_numOffloadBuffers < 8) {
// Allocate a new buffer if none is available
@ -186,6 +183,10 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain() {
traceBufp->chgDouble(oldp, *reinterpret_cast<const double*>(readp));
readp += 2;
continue;
case VerilatedTraceOffloadCommand::CHG_EVENT:
VL_TRACE_OFFLOAD_DEBUG("Command CHG_EVENT " << top);
traceBufp->chgEvent(oldp, *reinterpret_cast<const VlEvent*>(readp));
continue;
//===
// Rare commands
@ -250,14 +251,11 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::shutdownOffloadWorker() {
m_workerThread.reset(nullptr);
}
#endif
//=============================================================================
// Life cycle
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::closeBase() {
#ifdef VL_THREADED
if (offload()) {
shutdownOffloadWorker();
while (m_numOffloadBuffers) {
@ -265,12 +263,10 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::closeBase() {
--m_numOffloadBuffers;
}
}
#endif
}
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::flushBase() {
#ifdef VL_THREADED
if (offload()) {
// Hand an empty buffer to the worker thread
uint32_t* const bufferp = getOffloadBuffer();
@ -280,7 +276,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::flushBase() {
// this ensures all previous buffers have been processed.
waitForOffloadBuffer(bufferp);
}
#endif
}
//=============================================================================
@ -353,7 +348,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
// Else if was empty, m_sigs_enabledp = nullptr to short circuit tests
// But it isn't, so alloc one bit for each code to indicate enablement
// We don't want to still use m_signs_enabledVec as std::vector<bool> is not
// guarenteed to be fast
// guaranteed to be fast
m_sigs_enabledp = new uint32_t[1 + VL_WORDS_I(nextCode())]{0};
m_sigs_enabledVec.reserve(nextCode());
for (size_t code = 0; code < nextCode(); ++code) {
@ -368,7 +363,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
Verilated::addFlushCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onFlush, this);
Verilated::addExitCb(VerilatedTrace<VL_SUB_T, VL_BUF_T>::onExit, this);
#ifdef VL_THREADED
if (offload()) {
// Compute offload buffer size. we need to be able to store a new value for
// each signal, which is 'nextCode()' entries after the init callbacks
@ -381,7 +375,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::traceInit() VL_MT_UNSAFE {
m_workerThread.reset(
new std::thread{&VerilatedTrace<VL_SUB_T, VL_BUF_T>::offloadWorkerThreadMain, this});
}
#endif
}
template <>
@ -468,7 +461,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dumpvars(int level, const std::string&
}
}
#ifdef VL_THREADED
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::parallelWorkerTask(void* datap, bool) {
ParallelWorkerData* const wdp = reinterpret_cast<ParallelWorkerData*>(datap);
@ -493,11 +485,9 @@ VL_ATTR_NOINLINE void VerilatedTrace<VL_SUB_T, VL_BUF_T>::ParallelWorkerData::wa
m_cv.wait(lock, [this] { return m_ready.load(std::memory_order_relaxed); });
m_waiting = false;
}
#endif
template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<CallbackRecord>& cbVec) {
#ifdef VL_THREADED
if (parallel()) {
// If tracing in parallel, dispatch to the thread pool
VlThreadPool* threadPoolp = static_cast<VlThreadPool*>(m_contextp->threadPoolp());
@ -523,7 +513,7 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
mainThreadWorkerData.push_back(itemp);
}
}
// Execute main thead jobs
// Execute main thread jobs
for (ParallelWorkerData* const itemp : mainThreadWorkerData) {
parallelWorkerTask(itemp, false);
}
@ -538,7 +528,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runCallbacks(const std::vector<Callback
// Done
return;
}
#endif
// Fall back on sequential execution
for (const CallbackRecord& cbr : cbVec) {
Buffer* const traceBufferp = getTraceBuffer();
@ -551,15 +540,11 @@ template <>
void VerilatedTrace<VL_SUB_T, VL_BUF_T>::runOffloadedCallbacks(
const std::vector<CallbackRecord>& cbVec) {
// Fall back on sequential execution
#ifdef VL_THREADED
for (const CallbackRecord& cbr : cbVec) {
Buffer* traceBufferp = getTraceBuffer();
cbr.m_dumpOffloadCb(cbr.m_userp, static_cast<OffloadBuffer*>(traceBufferp));
commitTraceBuffer(traceBufferp);
}
#else
if (!cbVec.empty()) VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
}
template <>
@ -586,11 +571,8 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
if (!preChangeDump()) return;
}
#ifdef VL_THREADED
uint32_t* bufferp = nullptr;
#endif
if (offload()) {
#ifdef VL_THREADED
// Currently only incremental dumps run on the worker thread
if (VL_LIKELY(!m_fullDump)) {
// Get the offload buffer we are about to fill
@ -607,9 +589,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
flushBase();
emitTimeChange(timeui);
}
#else
VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
} else {
// Update time point
emitTimeChange(timeui);
@ -636,13 +615,12 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
cbr.m_cleanupCb(cbr.m_userp, self());
}
#ifdef VL_THREADED
if (offload() && VL_LIKELY(bufferp)) {
// Mark end of the offload buffer we just filled
*m_offloadBufferWritep++ = VerilatedTraceOffloadCommand::END;
// Assert no buffer overflow
assert(m_offloadBufferWritep - bufferp <= m_offloadBufferSize);
assert(static_cast<size_t>(m_offloadBufferWritep - bufferp) <= m_offloadBufferSize);
// Reset our pointers as we are giving up the buffer
m_offloadBufferWritep = nullptr;
@ -651,7 +629,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::dump(uint64_t timeui) VL_MT_SAFE_EXCLUD
// Pass it to the worker thread
m_offloadBuffersToWorker.put(bufferp);
}
#endif
}
//=============================================================================
@ -685,11 +662,6 @@ void VerilatedTrace<VL_SUB_T, VL_BUF_T>::addModel(VerilatedModel* modelp)
// Get the desired trace config from the model
const std::unique_ptr<VerilatedTraceConfig> configp = modelp->traceConfig();
#ifndef VL_THREADED
if (configp->m_useOffloading) {
VL_FATAL_MT(__FILE__, __LINE__, "", "Cannot use trace offloading without VL_THREADED");
}
#endif
// Configure trace base class
if (!firstModel) {
@ -866,6 +838,13 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullBit(uint32_t* oldp, CData newval) {
emitBit(code, newval);
}
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullEvent(uint32_t* oldp, VlEvent newval) {
const uint32_t code = oldp - m_sigs_oldvalp;
*oldp = 1; // Do we really store an "event" ?
emitEvent(code, newval);
}
template <>
void VerilatedTraceBuffer<VL_BUF_T>::fullCData(uint32_t* oldp, CData newval, int bits) {
const uint32_t code = oldp - m_sigs_oldvalp;
@ -915,7 +894,6 @@ void VerilatedTraceBuffer<VL_BUF_T>::fullDouble(uint32_t* oldp, double newval) {
emitDouble(code, newval);
}
#ifdef VL_THREADED
//=========================================================================
// VerilatedTraceOffloadBuffer
@ -934,6 +912,5 @@ VerilatedTraceOffloadBuffer<VL_BUF_T>::VerilatedTraceOffloadBuffer(VL_SUB_T& own
m_offloadBufferWritep += 2;
}
}
#endif
#endif // VL_CPPCHECK

View File

@ -197,7 +197,7 @@ public:
/// zero in memory, but during intermediate operations in the Verilated
/// internals is unpredictable.
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_MT_SAFE;
static int _vl_cmp_w(int words, WDataInP const lwp, WDataInP const rwp) VL_PURE;
template <std::size_t T_Words>
struct VlWide final {
@ -367,7 +367,7 @@ public:
// Can't just overload operator[] or provide a "at" reference to set,
// because we need to be able to insert only when the value is set
T_Value& at(int32_t index) {
static VL_THREAD_LOCAL T_Value s_throwAway;
static thread_local T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
s_throwAway = atDefault();
@ -378,7 +378,7 @@ public:
}
// Accessing. Verilog: v = assoc[index]
const T_Value& at(int32_t index) const {
static VL_THREAD_LOCAL T_Value s_throwAway;
static thread_local T_Value s_throwAway;
// Needs to work for dynamic arrays, so does not use T_MaxSize
if (VL_UNLIKELY(index < 0 || index >= m_deque.size())) {
return atDefault();
@ -412,7 +412,7 @@ public:
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) {
// index number is meaninless with sort, as it changes
// index number is meaningless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
@ -421,7 +421,7 @@ public:
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) {
// index number is meaninless with sort, as it changes
// index number is meaningless with sort, as it changes
return with_func(0, a) < with_func(0, b);
});
}
@ -429,9 +429,9 @@ public:
void shuffle() { std::shuffle(m_deque.begin(), m_deque.end(), VlURNG{}); }
VlQueue unique() const {
VlQueue out;
std::unordered_set<T_Value> saw;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(i);
@ -439,12 +439,26 @@ public:
}
return out;
}
template <typename Func>
VlQueue unique(Func with_func) const {
VlQueue out;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(0, i);
const auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(i);
}
}
return out;
}
VlQueue<IData> unique_index() const {
VlQueue<IData> out;
IData index = 0;
std::unordered_set<T_Value> saw;
std::set<T_Value> saw;
for (const auto& i : m_deque) {
auto it = saw.find(i);
const auto it = saw.find(i);
if (it == saw.end()) {
saw.insert(it, i);
out.push_back(index);
@ -454,6 +468,22 @@ public:
return out;
}
template <typename Func>
VlQueue<IData> unique_index(Func with_func) const {
VlQueue<IData> out;
IData index = 0;
std::unordered_set<T_Value> saw;
for (const auto& i : m_deque) {
const auto i_mapped = with_func(index, i);
auto it = saw.find(i_mapped);
if (it == saw.end()) {
saw.insert(it, i_mapped);
out.push_back(index);
}
++index;
}
return out;
}
template <typename Func>
VlQueue find(Func with_func) const {
VlQueue out;
IData index = 0;
@ -517,11 +547,29 @@ public:
const auto it = std::min_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
template <typename Func>
VlQueue min(Func with_func) const {
if (m_deque.empty()) return VlQueue{};
const auto it = std::min_element(m_deque.begin(), m_deque.end(),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue::cons(*it);
}
VlQueue max() const {
if (m_deque.empty()) return VlQueue{};
const auto it = std::max_element(m_deque.begin(), m_deque.end());
return VlQueue::cons(*it);
}
template <typename Func>
VlQueue max(Func with_func) const {
if (m_deque.empty()) return VlQueue{};
const auto it = std::max_element(m_deque.begin(), m_deque.end(),
[&with_func](const IData& a, const IData& b) {
return with_func(0, a) < with_func(0, b);
});
return VlQueue::cons(*it);
}
T_Value r_sum() const {
T_Value out(0); // Type must have assignment operator
@ -1004,7 +1052,14 @@ std::string VL_TO_STRING(const VlUnpacked<T_Value, T_Depth>& obj) {
return obj.to_string();
}
class VlClass; // See below
//===================================================================
// Object that VlDeleter is capable of deleting
class VlDeletable VL_NOT_FINAL {
public:
VlDeletable() = default;
virtual ~VlDeletable() = default;
};
//===================================================================
// Class providing delayed deletion of garbage objects. Objects get deleted only when 'deleteAll()'
@ -1013,9 +1068,9 @@ class VlClass; // See below
class VlDeleter final {
// MEMBERS
// Queue of new objects that should be deleted
std::vector<VlClass*> m_newGarbage VL_GUARDED_BY(m_mutex);
std::vector<VlDeletable*> m_newGarbage VL_GUARDED_BY(m_mutex);
// Queue of objects currently being deleted (only for deleteAll())
std::vector<VlClass*> m_toDelete VL_GUARDED_BY(m_deleteMutex);
std::vector<VlDeletable*> m_toDelete VL_GUARDED_BY(m_deleteMutex);
mutable VerilatedMutex m_mutex; // Mutex protecting the 'new garbage' queue
mutable VerilatedMutex m_deleteMutex; // Mutex protecting the delete queue
@ -1030,7 +1085,7 @@ private:
public:
// METHODS
// Adds a new object to the 'new garbage' queue.
void put(VlClass* const objp) VL_MT_SAFE {
void put(VlDeletable* const objp) VL_MT_SAFE {
const VerilatedLockGuard lock{m_mutex};
m_newGarbage.push_back(objp);
}
@ -1042,17 +1097,16 @@ public:
//===================================================================
// Base class for all verilated classes. Includes a reference counter, and a pointer to the deleter
// object that should destroy it after the counter reaches 0. This allows for easy construction of
// VlClassRefs from 'this'. Also declares a virtual constructor, so that the object can be deleted
// using a base pointer.
// VlClassRefs from 'this'.
class VlClass VL_NOT_FINAL {
class VlClass VL_NOT_FINAL : public VlDeletable {
// TYPES
template <typename T_Class>
friend class VlClassRef; // Needed for access to the ref counter and deleter
// MEMBERS
std::atomic<size_t> m_counter{0}; // Reference count for this object
VlDeleter* m_deleter = nullptr; // The deleter that will delete this object
VlDeleter* m_deleterp = nullptr; // The deleter that will delete this object
// METHODS
// Atomically increments the reference counter
@ -1060,19 +1114,20 @@ class VlClass VL_NOT_FINAL {
// Atomically decrements the reference counter. Assuming VlClassRef semantics are sound, it
// should never get called at m_counter == 0.
void refCountDec() VL_MT_SAFE {
if (!--m_counter) m_deleter->put(this);
if (!--m_counter) m_deleterp->put(this);
}
public:
// CONSTRUCTORS
VlClass() = default;
VlClass(const VlClass& copied) {}
virtual ~VlClass() {}
~VlClass() override = default;
};
//===================================================================
// Represents the null pointer. Used for setting VlClassRef to null instead of
// via nullptr_t, to prevent the implicit conversion of 0 to nullptr.
struct VlNull {
operator bool() const { return false; }
};
@ -1106,11 +1161,11 @@ public:
// CONSTRUCTORS
VlClassRef() = default;
// Init with nullptr
VlClassRef(VlNull){};
explicit VlClassRef(VlNull){};
template <typename... T_Args>
VlClassRef(VlDeleter& deleter, T_Args&&... args)
: m_objp{new T_Class{std::forward<T_Args>(args)...}} {
m_objp->m_deleter = &deleter;
m_objp->m_deleterp = &deleter;
refCountInc();
}
// Explicit to avoid implicit conversion from 0
@ -1172,18 +1227,6 @@ public:
operator bool() const { return m_objp; }
};
#define VL_NEW(Class, ...) \
VlClassRef<Class> { vlSymsp->__Vm_deleter, __VA_ARGS__ }
#define VL_KEEP_THIS \
VlClassRef<std::remove_pointer<decltype(this)>::type> __Vthisref { this }
template <class T> // T typically of type VlClassRef<x>
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
return t;
}
template <typename T, typename U>
static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
VlClassRef<U> casted = in.template dynamicCast<U>();
@ -1197,4 +1240,18 @@ static inline bool VL_CAST_DYNAMIC(VlClassRef<T> in, VlClassRef<U>& outr) {
//======================================================================
#define VL_NEW(Class, ...) \
VlClassRef<Class> { vlSymsp->__Vm_deleter, __VA_ARGS__ }
#define VL_KEEP_THIS \
VlClassRef<std::remove_pointer<decltype(this)>::type> __Vthisref { this }
template <class T> // T typically of type VlClassRef<x>
inline T VL_NULL_CHECK(T t, const char* filename, int linenum) {
if (VL_UNLIKELY(!t)) Verilated::nullPointerError(filename, linenum);
return t;
}
//======================================================================
#endif // Guard

View File

@ -29,7 +29,6 @@
#include <algorithm>
#include <cerrno>
#include <ctime>
#include <fcntl.h>
#if defined(_WIN32) && !defined(__MINGW32__) && !defined(__CYGWIN__)
@ -230,12 +229,10 @@ VerilatedVcd::~VerilatedVcd() {
if (m_wrBufp) VL_DO_CLEAR(delete[] m_wrBufp, m_wrBufp = nullptr);
deleteNameMap();
if (m_filep && m_fileNewed) VL_DO_CLEAR(delete m_filep, m_filep = nullptr);
#ifdef VL_THREADED
if (parallel()) {
assert(m_numBuffers == m_freeBuffers.size());
for (auto& pair : m_freeBuffers) VL_DO_CLEAR(delete[] pair.first, pair.first = nullptr);
}
#endif
}
void VerilatedVcd::closePrev() {
@ -364,17 +361,13 @@ void VerilatedVcd::printIndent(int level_change) {
void VerilatedVcd::dumpHeader() {
printStr("$version Generated by VerilatedVcd $end\n");
printStr("$date ");
{
const time_t tick = time(nullptr);
tm ticktm;
VL_LOCALTIME_R(&tick, &ticktm);
constexpr size_t LEN_BUF = 50;
char buf[LEN_BUF];
std::strftime(buf, LEN_BUF, "%c", &ticktm);
printStr(buf);
}
printStr(" $end\n");
// Verilator used to put in a $date here. Although $date is shown in
// IEEE examples, and it is common in VCD writers, VCD readers don't
// seem to care about it. Thus, we omit the $date so artifacts are
// more likely to be reproducible. If use cases show up that require
// the $date command to be present, it could be re-added with support
// for the SOURCE_DATE_EPOCH hook.
printStr("$timescale ");
printStr(timeResStr().c_str()); // lintok-begin-on-ref
@ -482,7 +475,7 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
m_suffixes.resize(nextCode() * VL_TRACE_SUFFIX_ENTRY_SIZE * 2, 0);
}
// Keep upper bound on bytes a single signal cna emit into the buffer
// Keep upper bound on bytes a single signal can emit into the buffer
m_maxSignalBytes = std::max<size_t>(m_maxSignalBytes, bits + 32);
// Make sure write buffer is large enough, plus header
bufferResize(m_maxSignalBytes + 1024);
@ -550,6 +543,9 @@ void VerilatedVcd::declare(uint32_t code, const char* name, const char* wirep, b
m_namemapp->emplace(hiername, decl);
}
void VerilatedVcd::declEvent(uint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "event", array, arraynum, false, false, 0, 0);
}
void VerilatedVcd::declBit(uint32_t code, const char* name, bool array, int arraynum) {
declare(code, name, "wire", array, arraynum, false, false, 0, 0);
}
@ -574,9 +570,8 @@ void VerilatedVcd::declDouble(uint32_t code, const char* name, bool array, int a
VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() {
VerilatedVcd::Buffer* const bufp = new Buffer{*this};
#ifdef VL_THREADED
if (parallel()) {
// Note: This is called from VeriltedVcd::dump, which already holds the lock
// Note: This is called from VerilatedVcd::dump, which already holds the lock
// If no buffer available, allocate a new one
if (m_freeBuffers.empty()) {
constexpr size_t pageSize = 4096;
@ -593,15 +588,13 @@ VerilatedVcd::Buffer* VerilatedVcd::getTraceBuffer() {
bufp->m_size = pair.second;
bufp->adjustGrowp();
}
#endif
// Return the buffer
return bufp;
}
void VerilatedVcd::commitTraceBuffer(VerilatedVcd::Buffer* bufp) {
if (parallel()) {
#if VL_THREADED
// Note: This is called from VeriltedVcd::dump, which already holds the lock
// Note: This is called from VerilatedVcd::dump, which already holds the lock
// Resize output buffer. Note, we use the full size of the trace buffer, as
// this is a lot more stable than the actual occupancy of the trace buffer.
// This helps us to avoid re-allocations due to small size changes.
@ -616,9 +609,6 @@ void VerilatedVcd::commitTraceBuffer(VerilatedVcd::Buffer* bufp) {
bufferCheck();
// Put buffer back on free list
m_freeBuffers.emplace_back(bufp->m_bufp, bufp->m_size);
#else
VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
} else {
// Needs adjusting for emitTimeChange
m_writep = bufp->m_writep;
@ -665,7 +655,6 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
m_writep = writep + suffixp[VL_TRACE_SUFFIX_ENTRY_SIZE - 1];
if (m_owner.parallel()) {
#ifdef VL_THREADED
// Double the size of the buffer if necessary
if (VL_UNLIKELY(m_writep >= m_growp)) {
// Compute occupied size of current buffer
@ -685,9 +674,6 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
// Adjust resize limit
adjustGrowp();
}
#else
VL_FATAL_MT(__FILE__, __LINE__, "", "Unreachable");
#endif
} else {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
@ -706,6 +692,19 @@ void VerilatedVcdBuffer::finishLine(uint32_t code, char* writep) {
// verilated_trace_imp.h, which is included in this file at the top),
// so always inline them.
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitEvent(uint32_t code, VlEvent newval) {
const bool triggered = newval.isTriggered();
// TODO : It seems that untriggered events are not filtered
// should be tested before this last step
if (triggered) {
// Don't prefetch suffix as it's a bit too late;
char* wp = m_writep;
*wp++ = '1';
finishLine(code, wp);
}
}
VL_ATTR_ALWINLINE
void VerilatedVcdBuffer::emitBit(uint32_t code, CData newval) {
// Don't prefetch suffix as it's a bit too late;

View File

@ -65,11 +65,9 @@ private:
using NameMap = std::map<const std::string, const std::string>;
NameMap* m_namemapp = nullptr; // List of names for the header
#ifdef VL_THREADED
// Vector of free trace buffers as (pointer, size) pairs.
std::vector<std::pair<char*, size_t>> m_freeBuffers;
size_t m_numBuffers = 0; // Number of trace buffers allocated
#endif
void bufferResize(size_t minsize);
void bufferFlush() VL_MT_UNSAFE_ONE;
@ -125,7 +123,7 @@ public:
// ACCESSORS
// Set size in bytes after which new file should be created.
void rolloverSize(uint64_t size) { m_rolloverSize = size; }
void rolloverSize(uint64_t size) VL_MT_SAFE { m_rolloverSize = size; }
// METHODS - All must be thread safe
// Open the file; call isOpen() to see if errors
@ -142,6 +140,7 @@ public:
//=========================================================================
// Internal interface to Verilator generated code
void declEvent(uint32_t code, const char* name, bool array, int arraynum);
void declBit(uint32_t code, const char* name, bool array, int arraynum);
void declBus(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
void declQuad(uint32_t code, const char* name, bool array, int arraynum, int msb, int lsb);
@ -169,7 +168,7 @@ void VerilatedVcd::Super::dumpvars(int level, const std::string& hier);
// VerilatedVcdBuffer
class VerilatedVcdBuffer VL_NOT_FINAL {
// Give the trace file ans sub-classes access to the private bits
// Give the trace file and sub-classes access to the private bits
friend VerilatedVcd;
friend VerilatedVcd::Super;
friend VerilatedVcd::Buffer;
@ -187,7 +186,6 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// The maximum number of bytes a single signal can emit
const size_t m_maxSignalBytes = m_owner.m_maxSignalBytes;
#ifdef VL_THREADED
// Additional data for parallel tracing only
char* m_bufp = nullptr; // The beginning of the trace buffer
size_t m_size = 0; // The size of the buffer at m_bufp
@ -197,7 +195,6 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
m_growp = (m_bufp + m_size) - (2 * m_maxSignalBytes);
assert(m_growp >= m_bufp + m_maxSignalBytes);
}
#endif
void finishLine(uint32_t code, char* writep);
@ -210,6 +207,7 @@ class VerilatedVcdBuffer VL_NOT_FINAL {
// Implementation of VerilatedTraceBuffer interface
// Implementations of duck-typed methods for VerilatedTraceBuffer. These are
// called from only one place (the full* methods), so always inline them.
VL_ATTR_ALWINLINE void emitEvent(uint32_t code, VlEvent newval);
VL_ATTR_ALWINLINE void emitBit(uint32_t code, CData newval);
VL_ATTR_ALWINLINE void emitCData(uint32_t code, CData newval, int bits);
VL_ATTR_ALWINLINE void emitSData(uint32_t code, SData newval, int bits);

View File

@ -14,80 +14,11 @@
/// \file
/// \brief Verilated tracing in VCD Format implementation code
///
/// This file must be compiled and linked against all Verilated objects
/// that use --trace.
///
/// Use "verilator --trace" to add this to the Makefile for the linker.
/// This file is deprecated, only verilated_vcd_sc.h is needed.
/// It is provided only for backward compatibility with user's linker scripts.
///
//=============================================================================
#include "verilatedos.h"
#include "verilated_vcd_sc.h"
//======================================================================
//======================================================================
void VerilatedVcdSc::open(const char* filename) {
if (!sc_core::sc_get_curr_simcontext()->elaboration_done()) {
vl_fatal(__FILE__, __LINE__, "VerilatedVcdSc",
("%Error: VerilatedVcdSc::open(\"" + std::string{filename}
+ "\") is called before sc_core::sc_start(). "
"Run sc_core::sc_start(sc_core::SC_ZERO_TIME) before opening a wave file.")
.c_str());
}
VerilatedVcdC::open(filename);
}
//--------------------------------------------------
// SystemC 2.1.v1
// cppcheck-suppress unusedFunction
void VerilatedVcdSc::write_comment(const std::string&) {}
void VerilatedVcdSc::trace(const unsigned int&, const std::string&, const char**) {}
#define DECL_TRACE_METHOD_A(tp) \
void VerilatedVcdSc::trace(const tp& object, const std::string& name) {}
#define DECL_TRACE_METHOD_B(tp) \
void VerilatedVcdSc::trace(const tp& object, const std::string& name, int width) {}
// clang-format off
#if (SYSTEMC_VERSION >= 20171012)
DECL_TRACE_METHOD_A( sc_event )
DECL_TRACE_METHOD_A( sc_time )
#ifdef VL_NO_LEGACY
#error "verilated_vcd_sc.cpp is deprecated; verilated_vcd_sc.h is self-sufficient"
#endif
DECL_TRACE_METHOD_A( bool )
DECL_TRACE_METHOD_A( sc_dt::sc_bit )
DECL_TRACE_METHOD_A( sc_dt::sc_logic )
DECL_TRACE_METHOD_B( unsigned char )
DECL_TRACE_METHOD_B( unsigned short )
DECL_TRACE_METHOD_B( unsigned int )
DECL_TRACE_METHOD_B( unsigned long )
DECL_TRACE_METHOD_B( char )
DECL_TRACE_METHOD_B( short )
DECL_TRACE_METHOD_B( int )
DECL_TRACE_METHOD_B( long )
DECL_TRACE_METHOD_B( sc_dt::int64 )
DECL_TRACE_METHOD_B( sc_dt::uint64 )
DECL_TRACE_METHOD_A( float )
DECL_TRACE_METHOD_A( double )
DECL_TRACE_METHOD_A( sc_dt::sc_int_base )
DECL_TRACE_METHOD_A( sc_dt::sc_uint_base )
DECL_TRACE_METHOD_A( sc_dt::sc_signed )
DECL_TRACE_METHOD_A( sc_dt::sc_unsigned )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval )
DECL_TRACE_METHOD_A( sc_dt::sc_fxval_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum )
DECL_TRACE_METHOD_A( sc_dt::sc_fxnum_fast )
DECL_TRACE_METHOD_A( sc_dt::sc_bv_base )
DECL_TRACE_METHOD_A( sc_dt::sc_lv_base )
// clang-format on
#undef DECL_TRACE_METHOD_A
#undef DECL_TRACE_METHOD_B
//********************************************************************

View File

@ -64,7 +64,12 @@ public:
}
// Override VerilatedVcdC. Must be called after starting simulation.
void open(const char* filename) override VL_MT_SAFE;
void open(const char* filename) override VL_MT_SAFE {
if (VL_UNLIKELY(!sc_core::sc_get_curr_simcontext()->elaboration_done())) {
Verilated::scTraceBeforeElaborationError();
}
VerilatedVcdC::open(filename);
}
private:
// METHODS - Fake outs for linker
@ -75,14 +80,16 @@ private:
#endif
void set_time_unit(double v, sc_time_unit tu) override {} // LCOV_EXCL_LINE
//--------------------------------------------------
// SystemC 2.1.v1
#define DECL_TRACE_METHOD_A(tp) void trace(const tp& object, const std::string& name) override;
#define DECL_TRACE_METHOD_B(tp) \
void trace(const tp& object, const std::string& name, int width) override;
//--------------------------------------------------
// SystemC 2.1.v1
void write_comment(const std::string&) override;
void trace(const unsigned int&, const std::string&, const char**) override;
void write_comment(const std::string&) override {}
void trace(const unsigned int&, const std::string&, const char**) override {}
#define DECL_TRACE_METHOD_A(tp) \
void trace(const tp& object, const std::string& name) override {}
#define DECL_TRACE_METHOD_B(tp) \
void trace(const tp& object, const std::string& name, int width) override {}
// clang-format off
// Formatting matches that of sc_trace.h

View File

@ -67,11 +67,11 @@ class VerilatedVpio VL_NOT_FINAL {
// CONSTANTS
// Magic value stored in front of object to detect double free etc
// Must be odd, as aligned pointer can never be odd
static constexpr uint32_t activeMagic() { return 0xfeed100f; }
static constexpr uint32_t activeMagic() VL_PURE { return 0xfeed100f; }
// MEM MANGLEMENT
// Internal note: Globals may multi-construct, see verilated.cpp top.
static VL_THREAD_LOCAL uint8_t* t_freeHead;
static thread_local uint8_t* t_freeHeadp;
public:
// CONSTRUCTORS
@ -85,9 +85,9 @@ public:
static constexpr size_t CHUNK_SIZE = 96;
if (VL_UNCOVERABLE(size > CHUNK_SIZE))
VL_FATAL_MT(__FILE__, __LINE__, "", "increase CHUNK_SIZE");
if (VL_LIKELY(t_freeHead)) {
uint8_t* const newp = t_freeHead;
t_freeHead = *(reinterpret_cast<uint8_t**>(newp));
if (VL_LIKELY(t_freeHeadp)) {
uint8_t* const newp = t_freeHeadp;
t_freeHeadp = *(reinterpret_cast<uint8_t**>(newp));
*(reinterpret_cast<uint32_t*>(newp)) = activeMagic();
return newp + 8;
}
@ -106,8 +106,8 @@ public:
#ifdef VL_VPI_IMMEDIATE_FREE // Define to aid in finding leaky handles
::operator delete(oldp);
#else
*(reinterpret_cast<void**>(oldp)) = t_freeHead;
t_freeHead = oldp;
*(reinterpret_cast<void**>(oldp)) = t_freeHeadp;
t_freeHeadp = oldp;
#endif
}
// MEMBERS
@ -205,7 +205,7 @@ public:
const VerilatedRange* rangep() const override { return &get_range(); }
const char* name() const override { return m_varp->name(); }
const char* fullname() const override {
static VL_THREAD_LOCAL std::string t_out;
static thread_local std::string t_out;
t_out = std::string{m_scopep->name()} + "." + name();
return t_out.c_str();
}
@ -225,28 +225,28 @@ public:
};
class VerilatedVpioRange final : public VerilatedVpio {
const VerilatedRange* const m_range;
const VerilatedRange* const m_rangep;
public:
explicit VerilatedVpioRange(const VerilatedRange* range)
: m_range{range} {}
explicit VerilatedVpioRange(const VerilatedRange* rangep)
: m_rangep{rangep} {}
~VerilatedVpioRange() override = default;
static VerilatedVpioRange* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioRange*>(reinterpret_cast<VerilatedVpio*>(h));
}
uint32_t type() const override { return vpiRange; }
uint32_t size() const override { return m_range->elements(); }
const VerilatedRange* rangep() const override { return m_range; }
uint32_t size() const override { return m_rangep->elements(); }
const VerilatedRange* rangep() const override { return m_rangep; }
};
class VerilatedVpioRangeIter final : public VerilatedVpio {
// Only supports 1 dimension
const VerilatedRange* const m_range;
const VerilatedRange* const m_rangep;
bool m_done = false;
public:
explicit VerilatedVpioRangeIter(const VerilatedRange* range)
: m_range{range} {}
explicit VerilatedVpioRangeIter(const VerilatedRange* rangep)
: m_rangep{rangep} {}
~VerilatedVpioRangeIter() override = default;
static VerilatedVpioRangeIter* castp(vpiHandle h) {
return dynamic_cast<VerilatedVpioRangeIter*>(reinterpret_cast<VerilatedVpio*>(h));
@ -258,7 +258,7 @@ public:
return nullptr;
}
m_done = true;
return ((new VerilatedVpioRange{m_range})->castVpiHandle());
return ((new VerilatedVpioRange{m_rangep})->castVpiHandle());
}
};
@ -348,7 +348,7 @@ public:
uint32_t size() const override { return varp()->packed().elements(); }
const VerilatedRange* rangep() const override { return &(varp()->packed()); }
const char* fullname() const override {
static VL_THREAD_LOCAL std::string t_out;
static thread_local std::string t_out;
constexpr size_t LEN_MAX_INDEX = 25;
char num[LEN_MAX_INDEX];
VL_SNPRINTF(num, LEN_MAX_INDEX, "%d", m_index);
@ -666,7 +666,7 @@ public:
// Statics
// Internal note: Globals may multi-construct, see verilated.cpp top.
VL_THREAD_LOCAL uint8_t* VerilatedVpio::t_freeHead = nullptr;
thread_local uint8_t* VerilatedVpio::t_freeHeadp = nullptr;
//======================================================================
// VerilatedVpiError
@ -708,7 +708,7 @@ 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 t_filehold;
static thread_local std::string t_filehold;
va_list args;
va_start(args, message);
VL_VSNPRINTF(m_buff, sizeof(m_buff), message, args);
@ -732,11 +732,11 @@ public:
}
VL_FATAL_MT(__FILE__, __LINE__, "", "vpi_unsupported called without error info set");
}
static const char* strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE;
static const char* strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE;
static const char* strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE;
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE;
static const char* strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE;
static const char* strFromVpiVal(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_PURE;
static const char* strFromVpiProp(PLI_INT32 vpiVal) VL_PURE;
};
//======================================================================
@ -775,7 +775,7 @@ VerilatedVpiError* VerilatedVpiImp::error_info() VL_MT_UNSAFE_ONE {
//======================================================================
// VerilatedVpiError Methods
const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
static const char* const names[] = {
"*undefined*",
@ -802,7 +802,7 @@ const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) VL_MT_SAFE {
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiRawFourStateVal) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
static const char* const names[] = {
"*undefined*",
@ -947,7 +947,7 @@ const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) VL_MT_SAFE {
if (VL_UNCOVERABLE(vpiVal < 0)) return names[0];
return names[(vpiVal <= vpiAutomatics) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
static const char* const names[] = {
"vpiCondition",
@ -990,7 +990,7 @@ const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) VL_MT_SAFE {
return names[vpiVal - vpiCondition];
}
const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_SAFE {
const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
static const char* const names[] = {
"*undefined*",
@ -1031,7 +1031,7 @@ const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) VL_MT_
return names[(vpiVal <= cbAtEndOfSimTime) ? vpiVal : 0];
}
const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_MT_SAFE {
const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) VL_PURE {
// clang-format off
static const char* const names[] = {
"*undefined or other*",
@ -1701,15 +1701,15 @@ 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 t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
static thread_local char t_outStr[VL_VALUE_STRING_MAX_WORDS * VL_EDATASIZE + 1];
// cppcheck-suppress variableScope
static const VL_THREAD_LOCAL int t_outStrSz = sizeof(t_outStr) - 1;
static const 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 t_out[VL_VALUE_STRING_MAX_WORDS * 2];
static thread_local t_vpi_vecval t_out[VL_VALUE_STRING_MAX_WORDS * 2];
valuep->value.vector = t_out;
if (varp->vltype() == VLVT_UINT8) {
t_out[0].aval = *(reinterpret_cast<CData*>(varDatap));
@ -1792,11 +1792,11 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
// align so least significant 3 bits represent octal char
val >>= idx.rem;
if (i == (chars - 1)) {
// most signifcant char, mask off non existant bits when vector
// most significant char, mask off nonexistent bits when vector
// size is not a multiple of 3
const unsigned int rem = varp->packed().elements() % 3;
if (rem) {
// generate bit mask & zero non existant bits
// generate bit mask & zero nonexistent bits
val &= (1 << rem) - 1;
}
}
@ -1842,11 +1842,11 @@ void vl_get_value(const VerilatedVar* varp, void* varDatap, p_vpi_value valuep,
for (i = 0; i < chars; ++i) {
char val = (datap[i >> 1] >> ((i & 1) << 2)) & 15;
if (i == (chars - 1)) {
// most signifcant char, mask off non existant bits when vector
// most significant char, mask off nonexistent bits when vector
// size is not a multiple of 4
const unsigned int rem = varp->packed().elements() & 3;
if (rem) {
// generate bit mask & zero non existant bits
// generate bit mask & zero nonexistent bits
val &= (1 << rem) - 1;
}
}
@ -2269,7 +2269,7 @@ PLI_INT32 vpi_chk_error(p_vpi_error_info error_info_p) {
VerilatedVpiImp::assertOneCheck();
p_vpi_error_info const _error_info_p = VerilatedVpiImp::error_info()->getError();
if (error_info_p && _error_info_p) *error_info_p = *_error_info_p;
if (!_error_info_p) return 0; // no error occured
if (!_error_info_p) return 0; // no error occurred
return _error_info_p->level; // return error severity level
}
@ -2290,7 +2290,8 @@ PLI_INT32 vpi_release_handle(vpiHandle object) {
return 1;
}
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) VL_MT_SAFE {
PLI_INT32 vpi_get_vlog_info(p_vpi_vlog_info vlog_info_p) {
// This is VL_MT_SAFE, but not marked as can't indicate it in the standardized header file
VerilatedVpiImp::assertOneCheck();
VL_VPI_ERROR_RESET_();
const auto argc_argv = Verilated::threadContextp()->impp()->argc_argv();

View File

@ -36,7 +36,7 @@
//======================================================================
/// Class for namespace-like groupng of Verilator VPI functions.
/// Class for namespace-like grouping of Verilator VPI functions.
class VerilatedVpi final {
public:

View File

@ -56,7 +56,7 @@
# if !defined(_WIN32) && !defined(__MINGW32__)
# define VL_ATTR_WEAK __attribute__((weak))
# endif
# if defined(__clang__) && defined(VL_THREADED)
# if defined(__clang__)
# define VL_ACQUIRE(...) __attribute__((acquire_capability(__VA_ARGS__)))
# define VL_ACQUIRE_SHARED(...) __attribute__((acquire_shared_capability(__VA_ARGS__)))
# define VL_RELEASE(...) __attribute__((release_capability(__VA_ARGS__)))
@ -111,12 +111,12 @@
# define VL_ATTR_WEAK ///< Attribute that function external that is optionally defined
#endif
#ifndef VL_CAPABILITY
# define VL_ACQUIRE(...) ///< Function requires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function aquires a shared capability/lock (-fthread-safety)
# define VL_ACQUIRE(...) ///< Function acquires a capability/lock (-fthread-safety)
# define VL_ACQUIRE_SHARED(...) ///< Function acquires a shared capability/lock (-fthread-safety)
# define VL_RELEASE(...) ///< Function releases a capability/lock (-fthread-safety)
# define VL_RELEASE_SHARED(...) ///< Function releases a shared capability/lock (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if aquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if aquired shared (-fthread-safety)
# define VL_TRY_ACQUIRE(...) ///< Function returns bool if acquired a capability (-fthread-safety)
# define VL_TRY_ACQUIRE_SHARED(...) ///< Function returns bool if acquired shared (-fthread-safety)
# define VL_REQUIRES(x) ///< Function requires a capability inbound (-fthread-safety)
# define VL_EXCLUDES(x) ///< Function requires not having a capability inbound (-fthread-safety)
# define VL_CAPABILITY(x) ///< Name of capability/lock (-fthread-safety)
@ -139,49 +139,58 @@
# define VL_PREFETCH_RW(p) ///< Prefetch pointer argument with read/write intent
#endif
#if defined(VL_THREADED) && !defined(VL_CPPCHECK)
# if defined(_MSC_VER) && _MSC_VER >= 1900
# define VL_THREAD_LOCAL thread_local
# elif defined(__GNUC__)
# if (__cplusplus < 201103L)
# error "VL_THREADED/--threads support requires C++-11 or newer only; use newer compiler"
# endif
# else
# error "Unsupported compiler for VL_THREADED: No thread-local declarator"
# endif
# define VL_THREAD_LOCAL thread_local // "thread_local" when supported
#else
# define VL_THREAD_LOCAL // "thread_local" when supported
#endif
#ifndef VL_NO_LEGACY
# define VL_FUNC __func__ // Deprecated
# define VL_THREAD // Deprecated
# define VL_THREAD_LOCAL thread_local // Deprecated
# define VL_STATIC_OR_THREAD static // Deprecated
#endif
// Comment tag that Function is pure (and thus also VL_MT_SAFE)
#define VL_PURE
// Comment tag that function is threadsafe when VL_THREADED
#if defined(__clang__)
# define VL_PURE __attribute__((annotate("PURE")))
#else
# define VL_PURE
#endif
// Comment tag that function is threadsafe
#if defined(__clang__)
# define VL_MT_SAFE __attribute__((annotate("MT_SAFE")))
#else
# define VL_MT_SAFE
#endif
// Comment tag that function is threadsafe when VL_THREADED, only
// Comment tag that function is threadsafe, only
// during normal operation (post-init)
#define VL_MT_SAFE_POSTINIT
#if defined(__clang__)
# define VL_MT_SAFE_POSTINIT __attribute__((annotate("MT_SAFE_POSTINIT")))
#else
# define VL_MT_SAFE_POSTINIT
#endif
// Attribute that function is clang threadsafe and uses given mutex
#define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex)
// Comment tag that function is not threadsafe when VL_THREADED
#if defined(__clang__)
# define VL_MT_SAFE_EXCLUDES(mutex) __attribute__((annotate("MT_SAFE_EXCLUDES"))) VL_EXCLUDES(mutex)
#else
# define VL_MT_SAFE_EXCLUDES(mutex) VL_EXCLUDES(mutex)
#endif
// Comment tag that function is not threadsafe
#if defined(__clang__)
# define VL_MT_UNSAFE __attribute__((annotate("MT_UNSAFE")))
#else
# define VL_MT_UNSAFE
#endif
// Comment tag that function is not threadsafe when VL_THREADED,
// Comment tag that function is not threadsafe
// protected to make sure single-caller
#define VL_MT_UNSAFE_ONE
#if defined(__clang__)
# define VL_MT_UNSAFE_ONE __attribute__((annotate("MT_UNSAFE_ONE")))
#else
# define VL_MT_UNSAFE_ONE
#endif
// Comment tag that function is entry point of parallelization
#if defined(__clang__)
# define VL_MT_START __attribute__((annotate("MT_START")))
#else
# define VL_MT_START
#endif
#ifndef VL_NO_LEGACY
# define VL_ULL(c) (c##ULL) // Add appropriate suffix to 64-bit constant (deprecated)
@ -222,10 +231,16 @@
} while (false); \
} while (false)
#ifdef _MSC_VER
# if _MSC_VER < 1929
# error "Verilator requires at least Visual Studio 2019 version 16.11.2"
# endif
#endif
//=========================================================================
// C++-2011
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK)
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__) || defined(VL_CPPCHECK) || defined(_MSC_VER)
#else
# error "Verilator requires a C++11 or newer compiler"
#endif
@ -378,9 +393,9 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#define VL_BYTESIZE 8 ///< Bits in a CData / byte
#define VL_SHORTSIZE 16 ///< Bits in a SData / short
#define VL_IDATASIZE 32 ///< Bits in a IData / word
#define VL_IDATASIZE 32 ///< Bits in an IData / word
#define VL_QUADSIZE 64 ///< Bits in a QData / quadword
#define VL_EDATASIZE 32 ///< Bits in a EData (WData entry)
#define VL_EDATASIZE 32 ///< Bits in an EData (WData entry)
#define VL_EDATASIZE_LOG2 5 ///< log2(VL_EDATASIZE)
#define VL_CACHE_LINE_BYTES 64 ///< Bytes in a cache line (for alignment)
@ -434,7 +449,7 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
#define VL_BITWORD_E(bit) ((bit) >> VL_EDATASIZE_LOG2) ///< Word number for a wide quantity
#define VL_BITBIT_I(bit) ((bit) & VL_SIZEBITS_I) ///< Bit number for a bit in a long
#define VL_BITBIT_Q(bit) ((bit) & VL_SIZEBITS_Q) ///< Bit number for a bit in a quad
#define VL_BITBIT_E(bit) ((bit) & VL_SIZEBITS_E) ///< Bit number for a bit in a EData
#define VL_BITBIT_E(bit) ((bit) & VL_SIZEBITS_E) ///< Bit number for a bit in an EData
// Return true if data[bit] set; not 0/1 return, but 0/non-zero return.
#define VL_BITISSET_I(data, bit) ((data) & (VL_UL(1) << VL_BITBIT_I(bit)))
@ -482,28 +497,28 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
//=========================================================================
// Threading related OS-specific functions
#if VL_THREADED
# ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
#ifdef _WIN32
# define WIN32_LEAN_AND_MEAN
# ifndef NOMINMAX
# define NOMINMAX
# include "Windows.h"
# define VL_CPU_RELAX() YieldProcessor()
# elif defined(__i386__) || defined(__x86_64__) || defined(VL_CPPCHECK)
# endif
# include "windows.h"
# define VL_CPU_RELAX() YieldProcessor()
#elif defined(__i386__) || defined(__x86_64__) || defined(VL_CPPCHECK)
// For more efficient busy waiting on SMT CPUs, let the processor know
// we're just waiting so it can let another thread run
# define VL_CPU_RELAX() asm volatile("rep; nop" ::: "memory")
# elif defined(__ia64__)
# define VL_CPU_RELAX() asm volatile("hint @pause" ::: "memory")
# elif defined(__aarch64__)
# define VL_CPU_RELAX() asm volatile("yield" ::: "memory")
# elif defined(__powerpc64__)
# define VL_CPU_RELAX() asm volatile("or 1, 1, 1; or 2, 2, 2;" ::: "memory")
# elif defined(__loongarch__)
# define VL_CPU_RELAX() asm volatile("rep; nop" ::: "memory")
#elif defined(__ia64__)
# define VL_CPU_RELAX() asm volatile("hint @pause" ::: "memory")
#elif defined(__aarch64__) || defined(__arm__)
# define VL_CPU_RELAX() asm volatile("yield" ::: "memory")
#elif defined(__powerpc64__)
# define VL_CPU_RELAX() asm volatile("or 1, 1, 1; or 2, 2, 2;" ::: "memory")
#elif defined(__loongarch__) || defined(__riscv)
// LoongArch does not currently have a yield/pause instruction
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
# else
# error "Missing VL_CPU_RELAX() definition. Or, don't use VL_THREADED"
# endif
# define VL_CPU_RELAX() asm volatile("nop" ::: "memory")
#else
# error "Missing VL_CPU_RELAX() definition."
#endif
//=========================================================================
@ -515,12 +530,6 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
# define VL_STRCASECMP strcasecmp
#endif
#if defined(__MINGW32__) || defined(_MSC_VER)
# define VL_LOCALTIME_R(timep, tmp) localtime_s((tmp), (timep))
#else
# define VL_LOCALTIME_R(timep, tmp) localtime_r((timep), (tmp))
#endif
//=========================================================================
// Macros controlling target specific optimizations

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0115,C0116,R0912,R0914,R0915,W0125,W0621,exec-used
# pylint: disable=C0103,C0114,C0115,C0116,C0209,R0912,R0914,R0915,W0125,W0621,exec-used
######################################################################
import argparse
@ -26,7 +26,7 @@ if 'VERILATOR_ROOT' not in os.environ:
def test():
if not os.path.exists("nodist/code_coverage.dat"):
sys.exit("%Error: Run code_coverage from the top of the verilator kit")
exec(open("./nodist/code_coverage.dat").read())
exec(open("./nodist/code_coverage.dat", "r", encoding="utf8").read()) # pylint: disable=consider-using-with
if Args.stage_enabled[0]:
ci_fold_start("distclean")
@ -78,10 +78,11 @@ def test():
os.makedirs(cc_dir, exist_ok=True)
os.makedirs(cc_dir + "/info", exist_ok=True)
sp = subprocess.Popen("find . -print | grep .gcda",
with subprocess.Popen("find . -print | grep .gcda",
shell=True,
stdout=subprocess.PIPE)
datout = sp.stdout.read()
stdout=subprocess.PIPE) as sp:
datout = sp.stdout.read()
dats = {}
for dat in datout.splitlines():
dat = dat.decode('utf-8')
@ -97,10 +98,11 @@ def test():
del dats[dat]
break
sp = subprocess.Popen("find . -print | grep .gcno",
with subprocess.Popen("find . -print | grep .gcno",
shell=True,
stdout=subprocess.PIPE)
datout = sp.stdout.read()
stdout=subprocess.PIPE) as sp:
datout = sp.stdout.read()
gcnos = {}
for gcno in datout.splitlines():
gcno = gcno.decode('utf-8')
@ -204,8 +206,8 @@ def clone_sources(cc_dir):
outfile = cc_dir + "/" + infile
outpath = re.sub(r'/[^/]*$', '', outfile, count=1)
os.makedirs(outpath, exist_ok=True)
with open(infile) as fh:
with open(outfile, "w") as ofh:
with open(infile, "r", encoding="utf8") as fh:
with open(outfile, "w", encoding="utf8") as ofh:
lineno = 0
for line in fh:
lineno += 1
@ -249,7 +251,7 @@ def clone_sources(cc_dir):
def cleanup_abs_paths_info(cc_dir, infile, outfile):
lines = []
with open(infile) as fh:
with open(infile, "r", encoding="utf8") as fh:
for line in fh:
if re.search(r'^SF:', line):
line = re.sub(os.environ['VERILATOR_ROOT'] + '/',
@ -261,7 +263,7 @@ def cleanup_abs_paths_info(cc_dir, infile, outfile):
# print("Remaining SF: "+line)
lines.append(line)
with open(outfile, "w") as ofh:
with open(outfile, "w", encoding="utf8") as ofh:
for line in lines:
ofh.write(line)
@ -270,14 +272,14 @@ def cleanup_abs_paths_json(cc_dir, infile, outfile):
# Handcrafted cleanup, alternative would be to deserialize/serialize JSON,
# but this is much faster
lines = []
with open(infile) as fh:
with open(infile, "r", encoding="utf8") as fh:
for line in fh:
line = re.sub('"' + os.environ['VERILATOR_ROOT'] + '/', '"', line)
line = re.sub('"' + cc_dir + '/', '"', line)
line = re.sub(r'obj_dbg/verilog.y$', 'verilog.y', line)
lines.append(line)
with open(outfile, "w") as ofh:
with open(outfile, "w", encoding="utf8") as ofh:
for line in lines:
ofh.write(line)

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0115,C0116,C0301
# pylint: disable=C0103,C0114,C0115,C0116,C0209,C0301
######################################################################
import argparse
@ -15,7 +15,7 @@ Edges = []
def dotread(filename):
with open(filename) as fh:
with open(filename, "r", encoding="utf8") as fh:
header = True
vnum = 0
@ -61,7 +61,7 @@ def dotread(filename):
def cwrite(filename):
with open(filename, "w") as fh:
with open(filename, "w", encoding="utf8") as fh:
fh.write("void V3GraphTestImport::dotImport() {\n")
fh.write(" auto* gp = &m_graph;\n")
for ver in sorted(Vertexes, key=lambda ver: ver['num']):

View File

@ -45,8 +45,8 @@ def print_lines(a):
def write_file(filename, contents):
# str->str->void
f = open(filename, 'w')
f.write(contents)
with open(filename, "w", encoding="utf8") as fh:
fh.write(contents)
def parse_line(s):

View File

@ -1,5 +1,5 @@
#!/usr/bin/env python3
# pylint: disable=C0103,C0114,C0115,C0116,R0801,R0915
# pylint: disable=C0103,C0114,C0115,C0116,C0209,R0801,R0915
######################################################################
import argparse

View File

@ -31,5 +31,5 @@ define watchedit
watch AstNode::s_editCntGbl==$arg0
end
document watchedit
Verilator: Create watch on where a edit number is made
Verilator: Create watch on where an edit number is made
end

View File

@ -157,7 +157,7 @@ RAW_OBJS = \
V3Assert.o \
V3AssertPre.o \
V3Ast.o \
V3AstNodes.o \
V3AstNodes.o \
V3Begin.o \
V3Branch.o \
V3Broken.o \
@ -188,7 +188,6 @@ RAW_OBJS = \
V3DfgPasses.o \
V3DfgPeephole.o \
V3DupFinder.o \
V3Timing.o \
V3EmitCBase.o \
V3EmitCConstPool.o \
V3EmitCFunc.o \
@ -210,8 +209,8 @@ RAW_OBJS = \
V3Gate.o \
V3Global.o \
V3Graph.o \
V3GraphAlg.o \
V3GraphAcyc.o \
V3GraphAlg.o \
V3GraphPathChecker.o \
V3GraphTest.o \
V3Hash.o \
@ -224,8 +223,8 @@ RAW_OBJS = \
V3LifePost.o \
V3LinkCells.o \
V3LinkDot.o \
V3LinkJump.o \
V3LinkInc.o \
V3LinkJump.o \
V3LinkLValue.o \
V3LinkLevel.o \
V3LinkParse.o \
@ -239,7 +238,11 @@ RAW_OBJS = \
V3Order.o \
V3Os.o \
V3Param.o \
V3ParseGrammar.o \
V3ParseImp.o \
V3ParseLex.o \
V3Partition.o \
V3PreProc.o \
V3PreShell.o \
V3Premit.o \
V3ProtectLib.o \
@ -260,12 +263,13 @@ RAW_OBJS = \
V3StatsReport.o \
V3String.o \
V3Subst.o \
V3TSP.o \
V3Table.o \
V3Task.o \
V3Timing.o \
V3Trace.o \
V3TraceDecl.o \
V3Tristate.o \
V3TSP.o \
V3Undriven.o \
V3Unknown.o \
V3Unroll.o \
@ -274,13 +278,6 @@ RAW_OBJS = \
V3Width.o \
V3WidthSel.o \
# Non-concatable
NC_OBJS += \
V3ParseImp.o \
V3ParseGrammar.o \
V3ParseLex.o \
V3PreProc.o \
# verilator_coverage
VLCOV_OBJS = \
VlcMain.o \
@ -288,14 +285,14 @@ VLCOV_OBJS = \
NON_STANDALONE_HEADERS = \
V3AstInlines.h \
V3AstNodeDType.h \
V3AstNodeMath.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
V3DfgVertices.h \
V3WidthCommit.h \
AST_DEFS := \
V3AstNodeDType.h \
V3AstNodeMath.h \
V3AstNodeExpr.h \
V3AstNodeOther.h \
DFG_DEFS := \
@ -311,15 +308,12 @@ ASTGENFLAGS += $(foreach f,$(DFG_DEFS),--dfgdef $f)
ifeq ($(VL_VLCOV),)
PREDEP_H = V3Ast__gen_forward_class_decls.h
OBJS += $(RAW_OBJS) $(NC_OBJS)
OBJS += $(RAW_OBJS)
else
PREDEP_H =
OBJS += $(VLCOV_OBJS)
endif
V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
$(PERL) $(srcdir)/../bin/verilator_includer $^ > $@
$(TGT): $(PREDEP_H) $(OBJS)
@echo " Linking $@..."
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}

View File

@ -88,7 +88,7 @@ protected:
// Recursively traverse the graph to determine whether every control 'BLOCK' has an assignment
// to the output we are currently analysing (the output whose 'user() is set), if so return
// true. Where a BLOCK contains a BRANCH, both the if and else sides of the branch must return
// true for the BRANCH to evalute to true. A BLOCK however needs only a single one of its
// true for the BRANCH to evaluate to true. A BLOCK however needs only a single one of its
// siblings to evaluate true in order to evaluate true itself. On output vertex only evaluates
// true if it is the vertex we are analyzing on this check

View File

@ -129,7 +129,7 @@ class ActiveTopVisitor final : public VNVisitor {
nodep->v3fatalSrc("Node should have been under ACTIVE");
}
//--------------------
void visit(AstNodeMath*) override {} // Accelerate
void visit(AstNodeExpr*) override {} // Accelerate
void visit(AstVarScope*) override {} // Accelerate
void visit(AstNode* nodep) override { iterateChildren(nodep); }

View File

@ -59,8 +59,8 @@ private:
nodep->displayType(VDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
// cppcheck-suppress nullPointer
AstNode* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
if (AstNode* const timesp = nodep->fmtp()->exprsp()) {
AstNodeExpr* const timenewp = new AstTime{nodep->fileline(), m_modp->timeunit()};
if (AstNodeExpr* const timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
@ -69,7 +69,7 @@ private:
nodep->fmtp()->scopeNamep(new AstScopeName{nodep->fileline(), true});
}
}
AstSampled* newSampledExpr(AstNode* nodep) {
AstSampled* newSampledExpr(AstNodeExpr* nodep) {
const auto sampledp = new AstSampled{nodep->fileline(), nodep};
sampledp->dtypeFrom(nodep);
return sampledp;
@ -98,16 +98,16 @@ private:
// 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.
FileLine* const fl = nodep->fileline();
AstNodeIf* const newp = new AstIf{
fl,
(force ? new AstConst{fl, AstConst::BitTrue{}}
: // If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn()
? static_cast<AstNode*>(
new AstCMath{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
: static_cast<AstNode*>(new AstConst{fl, AstConst::BitFalse{}}))),
nodep};
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
AstNodeExpr* const condp
= force ? static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitTrue{}})
: v3Global.opt.assertOn()
? static_cast<AstNodeExpr*>(
new AstCExpr{fl, "vlSymsp->_vm_contextp__->assertOn()", 1})
: static_cast<AstNodeExpr*>(new AstConst{fl, AstConst::BitFalse{}});
AstNodeIf* const newp = new AstIf{fl, condp, nodep};
newp->isBoundsCheck(true); // To avoid LATCH warning
newp->user1(true); // Don't assert/cover this if
return newp;
@ -133,7 +133,7 @@ private:
void newPslAssertion(AstNodeCoverOrAssert* nodep, AstNode* failsp) {
if (m_beginp && nodep->name() == "") nodep->name(m_beginp->name());
AstNode* const propp = nodep->propp()->unlinkFrBackWithNext();
AstNodeExpr* const propp = VN_AS(nodep->propp()->unlinkFrBackWithNext(), NodeExpr);
AstSenTree* const sentreep = nodep->sentreep();
const string& message = nodep->name();
AstNode* passsp = nodep->passsp();
@ -211,7 +211,7 @@ private:
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
const AstNodeIf* ifp = nodep;
AstNode* propp = nullptr;
AstNodeExpr* propp = nullptr;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
@ -228,7 +228,7 @@ private:
}
// Build a bitmask of the true predicates
AstNode* const predp = ifp->condp()->cloneTree(false);
AstNodeExpr* const predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat{nodep->fileline(), predp, propp};
} else {
@ -249,10 +249,10 @@ private:
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* const ohot
AstNodeExpr* const ohot
= ((allow_none || hasDefaultElse)
? static_cast<AstNode*>(new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNode*>(new AstOneHot{nodep->fileline(), propp}));
? static_cast<AstNodeExpr*>(new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNodeExpr*>(new AstOneHot{nodep->fileline(), propp}));
AstIf* const checkifp
= new AstIf{nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
newFireAssert(nodep, "'unique if' statement violated"), newifp};
@ -290,11 +290,12 @@ private:
if (!has_default && !nodep->itemsp()) {
// Not parallel, but harmlessly so.
} else {
AstNode* propp = nullptr;
AstNodeExpr* propp = nullptr;
for (AstCaseItem* itemp = nodep->itemsp(); itemp;
itemp = VN_AS(itemp->nextp(), CaseItem)) {
for (AstNode* icondp = itemp->condsp(); icondp; icondp = icondp->nextp()) {
AstNode* onep;
for (AstNodeExpr* icondp = itemp->condsp(); icondp;
icondp = VN_AS(icondp->nextp(), NodeExpr)) {
AstNodeExpr* onep;
if (AstInsideRange* const rcondp = VN_CAST(icondp, InsideRange)) {
onep = rcondp->newAndFromInside(nodep->exprp(),
rcondp->lhsp()->cloneTree(true),
@ -319,10 +320,11 @@ private:
if (!propp) propp = new AstConst{nodep->fileline(), AstConst::BitFalse{}};
const bool allow_none = has_default || nodep->unique0Pragma();
AstNode* const ohot
= (allow_none
? static_cast<AstNode*>(new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNode*>(new AstOneHot{nodep->fileline(), propp}));
AstNodeExpr* const ohot
= (allow_none ? static_cast<AstNodeExpr*>(
new AstOneHot0{nodep->fileline(), propp})
: static_cast<AstNodeExpr*>(
new AstOneHot{nodep->fileline(), propp}));
AstIf* const ifp = new AstIf{
nodep->fileline(), new AstLogNot{nodep->fileline(), ohot},
newFireAssert(nodep,
@ -345,8 +347,8 @@ private:
ticks = VN_AS(nodep->ticksp(), Const)->toUInt();
}
UASSERT_OBJ(ticks >= 1, nodep, "0 tick should have been checked in V3Width");
AstNode* const exprp = nodep->exprp()->unlinkFrBack();
AstNode* inp = newSampledExpr(exprp);
AstNodeExpr* const exprp = nodep->exprp()->unlinkFrBack();
AstNodeExpr* inp = newSampledExpr(exprp);
AstVar* invarp = nullptr;
AstSenTree* const sentreep = nodep->sentreep();
sentreep->unlinkFrBack();
@ -361,7 +363,7 @@ private:
AstNode* const assp = new AstAssignDly{
nodep->fileline(), new AstVarRef{nodep->fileline(), outvarp, VAccess::WRITE}, inp};
alwaysp->addStmtsp(assp);
// if (debug() >= 9) assp->dumpTree(cout, "-ass: ");
// if (debug() >= 9) assp->dumpTree("- ass: ");
invarp = outvarp;
inp = new AstVarRef{nodep->fileline(), invarp, VAccess::READ};
}

View File

@ -15,6 +15,7 @@
//*************************************************************************
// Pre steps:
// Attach clocks to each assertion
// Substitute property references by property body (IEEE Std 1800-2012, section 16.12.1).
//*************************************************************************
#include "config_build.h"
@ -24,6 +25,7 @@
#include "V3Ast.h"
#include "V3Global.h"
#include "V3Task.h"
VL_DEFINE_DEBUG_FUNCTIONS;
@ -44,7 +46,7 @@ private:
// Reset each always:
AstSenItem* m_seniAlwaysp = nullptr; // Last sensitivity in always
// Reset each assertion:
AstNode* m_disablep = nullptr; // Last disable
AstNodeExpr* m_disablep = nullptr; // Last disable
// METHODS
@ -57,9 +59,9 @@ private:
if (!senip) senip = m_seniAlwaysp;
if (!senip) {
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Unclocked assertion");
newp = new AstSenTree(nodep->fileline(), nullptr);
newp = new AstSenTree{nodep->fileline(), nullptr};
} else {
newp = new AstSenTree(nodep->fileline(), senip->cloneTree(true));
newp = new AstSenTree{nodep->fileline(), senip->cloneTree(true)};
}
return newp;
}
@ -67,6 +69,73 @@ private:
m_senip = nullptr;
m_disablep = nullptr;
}
AstPropSpec* getPropertyExprp(const AstProperty* const propp) {
// The only statements possible in AstProperty are AstPropSpec (body)
// and AstVar (arguments).
AstNode* propExprp = propp->stmtsp();
while (VN_IS(propExprp, Var)) propExprp = propExprp->nextp();
return VN_CAST(propExprp, PropSpec);
}
void replaceVarRefsWithExprRecurse(AstNode* const nodep, const AstVar* varp,
AstNode* const exprp) {
if (!nodep) return;
if (const AstVarRef* varrefp = VN_CAST(nodep, VarRef)) {
if (varp == varrefp->varp()) nodep->replaceWith(exprp->cloneTree(false));
}
replaceVarRefsWithExprRecurse(nodep->op1p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op2p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op3p(), varp, exprp);
replaceVarRefsWithExprRecurse(nodep->op4p(), varp, exprp);
}
AstPropSpec* substitutePropertyCall(AstPropSpec* nodep) {
if (AstFuncRef* const funcrefp = VN_CAST(nodep->propp(), FuncRef)) {
if (AstProperty* const propp = VN_CAST(funcrefp->taskp(), Property)) {
AstPropSpec* propExprp = getPropertyExprp(propp);
// Substitute inner property call before copying in order to not doing the same for
// each call of outer property call.
propExprp = substitutePropertyCall(propExprp);
// Clone subtree after substitution. It is needed, because property might be called
// multiple times with different arguments.
propExprp = propExprp->cloneTree(false);
// Substitute formal arguments with actual arguments
const V3TaskConnects tconnects = V3Task::taskConnects(funcrefp, propp->stmtsp());
for (const auto& tconnect : tconnects) {
const AstVar* const portp = tconnect.first;
AstArg* const argp = tconnect.second;
AstNode* const pinp = argp->exprp()->unlinkFrBack();
replaceVarRefsWithExprRecurse(propExprp, portp, pinp);
}
// Handle case with 2 disable iff statement (IEEE 1800-2017 16.12.1)
if (nodep->disablep() && propExprp->disablep()) {
nodep->v3error("disable iff expression before property call and in its "
"body is not legal");
pushDeletep(propExprp->disablep()->unlinkFrBack());
}
// If disable iff is in outer property, move it to inner
if (nodep->disablep()) {
AstNodeExpr* const disablep = nodep->disablep()->unlinkFrBack();
propExprp->disablep(disablep);
}
if (nodep->sensesp() && propExprp->sensesp()) {
nodep->v3warn(E_UNSUPPORTED,
"Unsupported: Clock event before property call and in its body");
pushDeletep(propExprp->sensesp()->unlinkFrBack());
}
// If clock event is in outer property, move it to inner
if (nodep->sensesp()) {
AstSenItem* const sensesp = nodep->sensesp();
sensesp->unlinkFrBack();
propExprp->sensesp(sensesp);
}
// Now substitute property reference with property body
nodep->replaceWith(propExprp);
return propExprp;
}
}
return nodep;
}
// VISITORS
//========== Statements
@ -101,11 +170,11 @@ private:
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* const past = new AstPast(fl, exprp, nullptr);
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, past, new AstNot(fl, exprp->cloneTree(false)));
exprp = new AstAnd{fl, past, new AstNot{fl, exprp->cloneTree(false)}};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@ -120,11 +189,11 @@ private:
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel(fl, exprp, 0, 1);
AstNode* const past = new AstPast(fl, exprp, nullptr);
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
if (exprp->width() > 1) exprp = new AstSel{fl, exprp, 0, 1};
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstAnd(fl, new AstNot(fl, past), exprp->cloneTree(false));
exprp = new AstAnd{fl, new AstNot{fl, past}, exprp->cloneTree(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@ -134,10 +203,10 @@ private:
if (nodep->sentreep()) return; // Already processed
iterateChildren(nodep);
FileLine* const fl = nodep->fileline();
AstNode* exprp = nodep->exprp()->unlinkFrBack();
AstNode* const past = new AstPast(fl, exprp, nullptr);
AstNodeExpr* exprp = nodep->exprp()->unlinkFrBack();
AstNodeExpr* const past = new AstPast{fl, exprp, nullptr};
past->dtypeFrom(exprp);
exprp = new AstEq(fl, past, exprp->cloneTree(false));
exprp = new AstEq{fl, past, exprp->cloneTree(false)};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
@ -148,35 +217,36 @@ private:
if (nodep->sentreep()) return; // Already processed
FileLine* const fl = nodep->fileline();
AstNode* const rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNodeExpr* const rhsp = nodep->rhsp()->unlinkFrBack();
AstNodeExpr* lhsp = nodep->lhsp()->unlinkFrBack();
if (m_disablep) lhsp = new AstAnd(fl, new AstNot(fl, m_disablep), lhsp);
if (m_disablep) lhsp = new AstAnd{fl, new AstNot{fl, m_disablep}, lhsp};
AstNode* const past = new AstPast(fl, lhsp, nullptr);
AstNodeExpr* const past = new AstPast{fl, lhsp, nullptr};
past->dtypeFrom(lhsp);
AstNode* const exprp = new AstOr(fl, new AstNot(fl, past), rhsp);
AstNodeExpr* const exprp = new AstOr{fl, new AstNot{fl, past}, rhsp};
exprp->dtypeSetBit();
nodep->replaceWith(exprp);
nodep->sentreep(newSenTree(nodep));
VL_DO_DANGLING(pushDeletep(nodep), nodep);
}
void visit(AstPropClocked* nodep) override {
void visit(AstPropSpec* nodep) override {
nodep = substitutePropertyCall(nodep);
// No need to iterate the body, once replace will get iterated
iterateAndNextNull(nodep->sensesp());
if (m_senip)
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Only one PSL clock allowed per assertion");
// Block is the new expression to evaluate
AstNode* blockp = nodep->propp()->unlinkFrBack();
if (AstNode* const disablep = nodep->disablep()) {
AstNodeExpr* blockp = VN_AS(nodep->propp()->unlinkFrBack(), NodeExpr);
if (AstNodeExpr* const disablep = nodep->disablep()) {
m_disablep = disablep->cloneTree(false);
if (VN_IS(nodep->backp(), Cover)) {
blockp = new AstAnd(disablep->fileline(),
new AstNot(disablep->fileline(), disablep->unlinkFrBack()),
blockp);
blockp = new AstAnd{disablep->fileline(),
new AstNot{disablep->fileline(), disablep->unlinkFrBack()},
blockp};
} else {
blockp = new AstOr(disablep->fileline(), disablep->unlinkFrBack(), blockp);
blockp = new AstOr{disablep->fileline(), disablep->unlinkFrBack(), blockp};
}
}
// Unlink and just keep a pointer to it, convert to sentree as needed
@ -189,6 +259,11 @@ private:
// Reset defaults
m_seniDefaultp = nullptr;
}
void visit(AstProperty* nodep) override {
// The body will be visited when will be substituted in place of property reference
// (AstFuncRef)
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
}
void visit(AstNode* nodep) override { iterateChildren(nodep); }
public:

View File

@ -112,7 +112,7 @@ string AstNode::encodeName(const string& namein) {
}
// Shorten names
// TODO long term use VName in place of "string name"
// Then we also won't need to save the table of hased values
// Then we also won't need to save the table of hashed values
VName vname{out};
return vname.hashedName();
}
@ -226,9 +226,9 @@ void AstNode::debugTreeChange(const AstNode* nodep, const char* prefix, int line
// // Commenting out the section below may crash, as the tree state
// // between edits is not always consistent for printing
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
// v3Global.rootp()->dumpTree(cout, "-treeChange: ");
// v3Global.rootp()->dumpTree("- treeChange: ");
// if (next||1) this->dumpTreeAndNext(cout, prefix);
// else this->dumpTree(cout, prefix);
// else this->dumpTree(prefix);
// this->checkTree();
// v3Global.rootp()->checkTree();
//}
@ -852,6 +852,7 @@ void AstNode::iterateAndNext(VNVisitor& v) {
#ifdef VL_DEBUG // Otherwise too hot of a function for debug
UASSERT_OBJ(!(nodep && !nodep->m_backp), nodep, "iterateAndNext node has no back");
#endif
// cppcheck-suppress knownConditionTrueFalse
if (nodep) ASTNODE_PREFETCH(nodep->m_nextp);
while (nodep) { // effectively: if (!this) return; // Callers rely on this
if (nodep->m_nextp) ASTNODE_PREFETCH(nodep->m_nextp->m_nextp);
@ -1001,9 +1002,9 @@ bool AstNode::sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ig
//======================================================================
// Debugging
void AstNode::checkTreeIter(const AstNode* backp) const {
void AstNode::checkTreeIter(const AstNode* prevBackp) const {
// private: Check a tree and children
UASSERT_OBJ(backp == this->backp(), this, "Back node inconsistent");
UASSERT_OBJ(prevBackp == this->backp(), this, "Back node inconsistent");
switch (this->type()) {
#include "V3Ast__gen_op_checks.h"
default: VL_UNREACHABLE; // LCOV_EXCL_LINE

View File

@ -453,6 +453,8 @@ public:
TIME,
// Closer to a class type, but limited usage
STRING,
// Property / Sequence argument type
UNTYPED,
// Internal types for mid-steps
SCOPEPTR,
CHARPTR,
@ -485,6 +487,7 @@ public:
"shortint",
"time",
"string",
"untyped",
"VerilatedScope*",
"char*",
"VlMTaskState",
@ -501,11 +504,12 @@ public:
}
const char* dpiType() const {
static const char* const names[]
= {"%E-unk", "svBit", "char", "void*", "char",
"int", "%E-integer", "svLogic", "long long", "double",
"short", "%E-time", "const char*", "dpiScope", "const char*",
"%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched", "%E-dyn-sched",
"%E-fork", "IData", "QData", "%E-logic-implct", " MAX"};
= {"%E-unk", "svBit", "char", "void*", "char",
"int", "%E-integer", "svLogic", "long long", "double",
"short", "%E-time", "const char*", "%E-untyped", "dpiScope",
"const char*", "%E-mtaskstate", "%E-triggervec", "%E-dly-sched", "%E-trig-sched",
"%E-dyn-sched", "%E-fork", "IData", "QData", "%E-logic-implct",
" MAX"};
return names[m_e];
}
static void selfTest() {
@ -582,7 +586,7 @@ public:
return (m_e == EVENT || m_e == STRING || m_e == SCOPEPTR || m_e == CHARPTR
|| m_e == MTASKSTATE || m_e == TRIGGERVEC || m_e == DELAY_SCHEDULER
|| m_e == TRIGGER_SCHEDULER || m_e == DYNAMIC_TRIGGER_SCHEDULER || m_e == FORK_SYNC
|| m_e == DOUBLE);
|| m_e == DOUBLE || m_e == UNTYPED);
}
bool isDouble() const VL_MT_SAFE { return m_e == DOUBLE; }
bool isEvent() const { return m_e == EVENT; }
@ -1175,9 +1179,9 @@ class VBasicTypeKey final {
public:
const int m_width; // From AstNodeDType: Bit width of operation
const int m_widthMin; // From AstNodeDType: If unsized, bitwidth of minimum implementation
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
const VSigning m_numeric; // From AstNodeDType: Node is signed
const VBasicDTypeKwd m_keyword; // From AstBasicDType: What keyword created basic type
const VNumRange m_nrange; // From AstBasicDType: Numeric msb/lsb (if non-opaque keyword)
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;
@ -1199,9 +1203,9 @@ public:
const VNumRange& nrange)
: m_width{width}
, m_widthMin{widthMin}
, m_nrange{nrange}
, m_numeric{numeric}
, m_keyword{kwd}
, m_nrange{nrange} {}
, m_keyword{kwd} {}
~VBasicTypeKey() = default;
};
@ -1415,8 +1419,8 @@ protected:
};
AstNode* m_oldp = nullptr; // The old node that was linked to this point in the tree
AstNode* m_backp = nullptr;
RelinkWhatEn m_chg = RELINK_BAD;
AstNode** m_iterpp = nullptr;
RelinkWhatEn m_chg = RELINK_BAD;
public:
VNRelinker() = default;
@ -1539,7 +1543,7 @@ class AstNode VL_NOT_FINAL {
private:
AstNode* cloneTreeIter();
AstNode* cloneTreeIterList();
void checkTreeIter(const AstNode* backp) const VL_MT_SAFE;
void checkTreeIter(const AstNode* prevBackp) const VL_MT_SAFE;
bool gateTreeIter() const;
static bool sameTreeIter(const AstNode* node1p, const AstNode* node2p, bool ignNext,
bool gateOnly);
@ -1870,12 +1874,11 @@ public:
return static_cast<T_NodeResult*>(addNext<AstNode, AstNode>(nodep, newp));
}
inline AstNode* addNext(AstNode* newp);
inline void addPrev(AstNode* newp);
void addNextHere(AstNode* newp); // Insert newp at this->nextp
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
void replaceWith(AstNode* newp); // Replace current node in tree with new node
AstNode* unlinkFrBack(VNRelinker* linkerp
= nullptr); // Unlink this from whoever points to it.
// Unlink this from whoever points to it.
AstNode* unlinkFrBack(VNRelinker* linkerp = nullptr);
// Unlink this from whoever points to it, keep entire next list with unlinked node
AstNode* unlinkFrBackWithNext(VNRelinker* linkerp = nullptr);
void swapWith(AstNode* bp);
@ -1906,7 +1909,7 @@ public:
void dumpTree(std::ostream& os = std::cout, const string& indent = " ",
int maxDepth = 0) const;
void dumpTree(const string& indent, int maxDepth = 0) const {
dumpTree(cout, indent, maxDepth);
dumpTree(std::cout, indent, maxDepth);
}
static void dumpTreeGdb(const AstNode* nodep); // For GDB only
void dumpTreeAndNext(std::ostream& os = std::cout, const string& indent = " ",
@ -2203,10 +2206,6 @@ AstNode* AstNode::addNext<AstNode, AstNode>(AstNode* nodep, AstNode* newp);
// Inline method implementations
AstNode* AstNode::addNext(AstNode* newp) { return addNext(this, newp); }
void AstNode::addPrev(AstNode* newp) {
replaceWith(newp);
newp->addNext(this);
}
// Specialisations of privateTypeTest
#include "V3Ast__gen_type_tests.h" // From ./astgen
@ -2214,11 +2213,11 @@ void AstNode::addPrev(AstNode* newp) {
// Specializations of AstNode::mayBeUnder
template <>
inline bool AstNode::mayBeUnder<AstCell>(const AstNode* nodep) {
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeMath);
return !VN_IS(nodep, NodeStmt) && !VN_IS(nodep, NodeExpr);
}
template <>
inline bool AstNode::mayBeUnder<AstNodeAssign>(const AstNode* nodep) {
return !VN_IS(nodep, NodeMath);
return !VN_IS(nodep, NodeExpr);
}
template <>
inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) {
@ -2226,7 +2225,7 @@ inline bool AstNode::mayBeUnder<AstVarScope>(const AstNode* nodep) {
if (VN_IS(nodep, Var)) return false;
if (VN_IS(nodep, Active)) return false;
if (VN_IS(nodep, NodeStmt)) return false;
if (VN_IS(nodep, NodeMath)) return false;
if (VN_IS(nodep, NodeExpr)) return false;
return true;
}
template <>
@ -2440,9 +2439,10 @@ class VNRef final : public std::reference_wrapper<T_Node> {
public:
template <typename U>
// cppcheck-suppress noExplicitConstructor
VNRef(U&& x)
: std::reference_wrapper<T_Node>{x} {}
// cppcheck-suppress noExplicitConstructor
VNRef(const std::reference_wrapper<T_Node>& other)
: std::reference_wrapper<T_Node>{other} {}
};
@ -2508,7 +2508,7 @@ AstNode* VNVisitor::iterateSubtreeReturnEdits(AstNode* nodep) {
// AstNode subclasses
#include "V3AstNodeDType.h"
#include "V3AstNodeMath.h"
#include "V3AstNodeExpr.h"
#include "V3AstNodeOther.h"
// Inline function definitions need to go last

View File

@ -130,9 +130,9 @@ bool AstBasicDType::littleEndian() const {
bool AstActive::hasClocked() const { return m_sensesp->hasClocked(); }
bool AstActive::hasCombo() const { return m_sensesp->hasCombo(); }
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNode* exprsp)
AstElabDisplay::AstElabDisplay(FileLine* fl, VDisplayType dispType, AstNodeExpr* exprsp)
: ASTGEN_SUPER_ElabDisplay(fl) {
addFmtp(new AstSFormatF{fl, AstSFormatF::NoFormat(), exprsp});
addFmtp(new AstSFormatF{fl, AstSFormatF::NoFormat{}, exprsp});
m_displayType = dispType;
}
@ -141,8 +141,8 @@ AstCStmt::AstCStmt(FileLine* fl, const string& textStmt)
addExprsp(new AstText{fl, textStmt, true});
}
AstCMath::AstCMath(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut)
: ASTGEN_SUPER_CMath(fl)
AstCExpr::AstCExpr(FileLine* fl, const string& textStmt, int setwidth, bool cleanOut)
: ASTGEN_SUPER_CExpr(fl)
, m_cleanOut{cleanOut}
, m_pure{true} {
addExprsp(new AstText{fl, textStmt, true});
@ -180,4 +180,6 @@ AstVarXRef::AstVarXRef(FileLine* fl, AstVar* varp, const string& dotted, const V
dtypeFrom(varp);
}
AstStmtExpr* AstNodeExpr::makeStmt() { return new AstStmtExpr{fileline(), this}; }
#endif // Guard

View File

@ -82,7 +82,7 @@ public:
// Iff has second dtype, set as generic node function
virtual void virtRefDType2p(AstNodeDType* nodep) {}
// Assignable equivalence. Call skipRefp() on this and samep before calling
virtual bool similarDType(AstNodeDType* samep) const = 0;
virtual bool similarDType(const AstNodeDType* samep) const = 0;
// Iff has a non-null subDTypep(), as generic node function
virtual AstNodeDType* subDTypep() const { return nullptr; }
virtual bool isFourstate() const;
@ -161,7 +161,7 @@ public:
return (hi() == asamep->hi() && subDTypep() == asamep->subDTypep()
&& rangenp()->sameTree(asamep->rangenp()));
} // HashedDT doesn't recurse, so need to check children
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return (asamep && type() == samep->type() && hi() == asamep->hi()
&& rangenp()->sameTree(asamep->rangenp())
@ -200,10 +200,10 @@ private:
using MemberNameMap = std::map<const std::string, AstMemberDType*>;
// MEMBERS
string m_name; // Name from upper typedef, if any
bool m_packed;
bool m_isFourstate = false; // V3Width computes
MemberNameMap m_members;
const int m_uniqueNum;
bool m_packed;
bool m_isFourstate = false; // V3Width computes
protected:
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
@ -235,7 +235,7 @@ public:
int widthAlignBytes() const override;
// (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
int widthTotalBytes() const override;
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return this == samep; // We don't compare members, require exact equivalence
}
string name() const override { return m_name; }
@ -261,13 +261,13 @@ public:
// === AstNode ===
class AstEnumItem final : public AstNode {
// @astgen op1 := rangep : Optional[AstRange] // Range for name appending
// @astgen op2 := valuep : Optional[AstNode]
// @astgen op2 := valuep : Optional[AstNodeExpr]
private:
string m_name;
public:
// Parents: ENUM
AstEnumItem(FileLine* fl, const string& name, AstRange* rangep, AstNode* valuep)
AstEnumItem(FileLine* fl, const string& name, AstRange* rangep, AstNodeExpr* valuep)
: ASTGEN_SUPER_EnumItem(fl)
, m_name{name} {
this->rangep(rangep);
@ -321,7 +321,7 @@ public:
if (!asamep->keyDTypep()) return false;
return (subDTypep() == asamep->subDTypep() && keyDTypep() == asamep->keyDTypep());
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
@ -399,7 +399,7 @@ public:
const AstBasicDType* const sp = static_cast<const AstBasicDType*>(samep);
return m == sp->m;
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return type() == samep->type() && same(samep);
}
string name() const override { return m.m_keyword.ascii(); }
@ -465,6 +465,7 @@ public:
int right() const { return littleEndian() ? hi() : lo(); }
inline bool littleEndian() const;
bool implicit() const { return keyword() == VBasicDTypeKwd::LOGIC_IMPLICIT; }
bool untyped() const { return keyword() == VBasicDTypeKwd::UNTYPED; }
VNumRange declRange() const { return isRanged() ? VNumRange{left(), right()} : VNumRange{}; }
void cvtRangeConst(); // Convert to smaller representation
bool isCompound() const override { return isString(); }
@ -482,7 +483,7 @@ public:
this->elementsp(elementsp);
}
ASTGEN_MEMBERS_AstBracketArrayDType;
bool similarDType(AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
bool similarDType(const AstNodeDType* samep) const override { V3ERROR_NA_RETURN(false); }
AstNodeDType* subDTypep() const override { return childDTypep(); }
// METHODS
// Will be removed in V3Width, which relies on this
@ -517,7 +518,7 @@ public:
const AstClassRefDType* const asamep = static_cast<const AstClassRefDType*>(samep);
return (m_classp == asamep->m_classp && m_classOrPackagep == asamep->m_classOrPackagep);
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return this == samep || (type() == samep->type() && same(samep));
}
void dump(std::ostream& str = std::cout) const override;
@ -566,7 +567,7 @@ public:
const AstConstDType* const sp = static_cast<const AstConstDType*>(samep);
return (m_refDTypep == sp->m_refDTypep);
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return skipRefp()->similarDType(samep->skipRefp());
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
@ -613,7 +614,7 @@ public:
const AstDefImplicitDType* const sp = static_cast<const AstDefImplicitDType*>(samep);
return uniqueNum() == sp->uniqueNum();
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return type() == samep->type() && same(samep);
}
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
@ -663,7 +664,7 @@ public:
if (!asamep->subDTypep()) return false;
return subDTypep() == asamep->subDTypep();
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
const AstAssocArrayDType* const asamep = static_cast<const AstAssocArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
@ -701,7 +702,7 @@ public:
AstNodeDType* subDTypep() const override { return nullptr; }
AstNodeDType* virtRefDTypep() const override { return nullptr; }
void virtRefDTypep(AstNodeDType* nodep) override {}
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
@ -746,7 +747,7 @@ public:
const AstEnumDType* const sp = static_cast<const AstEnumDType*>(samep);
return uniqueNum() == sp->uniqueNum();
}
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
@ -754,6 +755,8 @@ public:
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
string name() const override { return m_name; }
void name(const string& flag) override { m_name = flag; }
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
// METHODS
AstBasicDType* basicp() const override VL_MT_SAFE { return subDTypep()->basicp(); }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
@ -812,7 +815,7 @@ public:
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
AstNodeDType* skipRefToConstp() const override { return (AstNodeDType*)this; }
AstNodeDType* skipRefToEnump() const override { return (AstNodeDType*)this; }
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
int widthAlignBytes() const override { return 1; }
int widthTotalBytes() const override { return 1; }
FileLine* modportFileline() const { return m_modportFileline; }
@ -873,7 +876,7 @@ public:
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
AstNodeDType* virtRefDTypep() const override { return m_refDTypep; }
void virtRefDTypep(AstNodeDType* nodep) override { refDTypep(nodep); }
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
//
// (Slow) recurse down to find basic data type (Note don't need virtual -
// AstVar isn't a NodeDType)
@ -922,7 +925,7 @@ public:
AstNodeDType* skipRefp() const override VL_MT_SAFE { return subDTypep()->skipRefp(); }
AstNodeDType* skipRefToConstp() const override { return subDTypep()->skipRefToConstp(); }
AstNodeDType* skipRefToEnump() const override { return subDTypep()->skipRefToEnump(); }
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
const AstParamTypeDType* const sp = static_cast<const AstParamTypeDType*>(samep);
return type() == samep->type() && sp
&& this->subDTypep()->skipRefp()->similarDType(sp->subDTypep()->skipRefp());
@ -952,7 +955,7 @@ public:
ASTGEN_MEMBERS_AstParseTypeDType;
AstNodeDType* dtypep() const { return nullptr; }
// METHODS
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
AstNodeDType* skipRefp() const override VL_MT_SAFE { return nullptr; }
// cppcheck-suppress csyleCast
@ -969,18 +972,18 @@ public:
class AstQueueDType final : public AstNodeDType {
// Queue array data type, ie "[ $ ]"
// @astgen op1 := childDTypep : Optional[AstNodeDType] // moved to refDTypep() in V3Width
// @astgen op2 := boundp : Optional[AstNode]
// @astgen op2 := boundp : Optional[AstNodeExpr]
private:
AstNodeDType* m_refDTypep = nullptr; // Elements of this type (after widthing)
public:
AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNode* boundp)
AstQueueDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstNodeExpr* boundp)
: ASTGEN_SUPER_QueueDType(fl) {
this->childDTypep(dtp);
this->boundp(boundp);
refDTypep(nullptr);
dtypep(nullptr); // V3Width will resolve
}
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNode* boundp)
AstQueueDType(FileLine* fl, AstNodeDType* dtp, AstNodeExpr* boundp)
: ASTGEN_SUPER_QueueDType(fl) {
this->boundp(boundp);
refDTypep(dtp);
@ -1000,7 +1003,7 @@ public:
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
const AstQueueDType* const asamep = static_cast<const AstQueueDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
@ -1029,7 +1032,7 @@ public:
};
class AstRefDType final : public AstNodeDType {
// @astgen op1 := typeofp : Optional[AstNode]
// @astgen op2 := classOrPackageOpp : Optional[AstNode]
// @astgen op2 := classOrPackageOpp : Optional[AstNodeExpr]
// @astgen op3 := paramsp : List[AstPin]
private:
// Pre-Width must reference the Typeref, not what it points to, as some child
@ -1043,7 +1046,7 @@ public:
AstRefDType(FileLine* fl, const string& name)
: ASTGEN_SUPER_RefDType(fl)
, m_name{name} {}
AstRefDType(FileLine* fl, const string& name, AstNode* classOrPackagep, AstPin* paramsp)
AstRefDType(FileLine* fl, const string& name, AstNodeExpr* classOrPackagep, AstPin* paramsp)
: ASTGEN_SUPER_RefDType(fl)
, m_name{name} {
this->classOrPackageOpp(classOrPackagep);
@ -1063,13 +1066,14 @@ public:
return (m_typedefp == asamep->m_typedefp && m_refDTypep == asamep->m_refDTypep
&& m_name == asamep->m_name && m_classOrPackagep == asamep->m_classOrPackagep);
}
bool similarDType(AstNodeDType* samep) const override {
bool similarDType(const AstNodeDType* samep) const override {
return skipRefp()->similarDType(samep->skipRefp());
}
void dump(std::ostream& str = std::cout) const override;
void dumpSmall(std::ostream& str) const override;
string name() const override { return m_name; }
string prettyDTypeName() const override {
return subDTypep() ? subDTypep()->name() : prettyName();
return subDTypep() ? prettyName(subDTypep()->name()) : prettyName();
}
AstBasicDType* basicp() const override VL_MT_SAFE {
return subDTypep() ? subDTypep()->basicp() : nullptr;
@ -1139,7 +1143,7 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override;
bool similarDType(AstNodeDType* samep) const override;
bool similarDType(const AstNodeDType* samep) const override;
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override { return m_refDTypep ? m_refDTypep : childDTypep(); }
@ -1170,7 +1174,7 @@ public:
AstNodeDType* subDTypep() const override { return nullptr; }
AstNodeDType* virtRefDTypep() const override { return nullptr; }
void virtRefDTypep(AstNodeDType* nodep) override {}
bool similarDType(AstNodeDType* samep) const override { return this == samep; }
bool similarDType(const AstNodeDType* samep) const override { return this == samep; }
AstBasicDType* basicp() const override VL_MT_SAFE { return nullptr; }
// cppcheck-suppress csyleCast
AstNodeDType* skipRefp() const override VL_MT_SAFE { return (AstNodeDType*)this; }
@ -1204,7 +1208,7 @@ public:
if (m_refDTypep && m_refDTypep->clonep()) m_refDTypep = m_refDTypep->clonep();
}
bool same(const AstNode* samep) const override;
bool similarDType(AstNodeDType* samep) const override;
bool similarDType(const AstNodeDType* samep) const override;
void dumpSmall(std::ostream& str) const override;
AstNodeDType* getChildDTypep() const override { return childDTypep(); }
AstNodeDType* subDTypep() const override VL_MT_SAFE {

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -60,6 +60,8 @@ void AstNodeFTaskRef::cloneRelink() {
}
}
bool AstNodeFTaskRef::isGateOptimizable() const { return m_taskp && m_taskp->isGateOptimizable(); }
const char* AstNodeVarRef::broken() const {
BROKEN_RTN(m_varp && !m_varp->brokeExists());
BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
@ -123,7 +125,7 @@ const char* AstNodeUOrStructDType::broken() const {
void AstNodeStmt::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeCCall::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
this->AstNodeExpr::dump(str);
if (funcp()) {
str << " " << funcp()->name() << " => ";
funcp()->dump(str);
@ -250,23 +252,23 @@ int AstNodeUOrStructDType::widthAlignBytes() const {
}
}
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
AstNodeBiop* AstEq::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
return new AstEqN{fl, lhsp, rhsp};
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
return new AstEqD{fl, lhsp, rhsp};
} else {
return new AstEq(fl, lhsp, rhsp);
return new AstEq{fl, lhsp, rhsp};
}
}
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNode* lhsp, AstNode* rhsp) {
AstNodeBiop* AstEqWild::newTyped(FileLine* fl, AstNodeExpr* lhsp, AstNodeExpr* rhsp) {
if (lhsp->isString() && rhsp->isString()) {
return new AstEqN(fl, lhsp, rhsp);
return new AstEqN{fl, lhsp, rhsp};
} else if (lhsp->isDouble() && rhsp->isDouble()) {
return new AstEqD(fl, lhsp, rhsp);
return new AstEqD{fl, lhsp, rhsp};
} else {
return new AstEqWild(fl, lhsp, rhsp);
return new AstEqWild{fl, lhsp, rhsp};
}
}
@ -277,13 +279,13 @@ AstExecGraph::AstExecGraph(FileLine* fileline, const string& name)
AstExecGraph::~AstExecGraph() { VL_DO_DANGLING(delete m_depGraphp, m_depGraphp); }
AstNode* AstInsideRange::newAndFromInside(AstNode* exprp, AstNode* lhsp, AstNode* rhsp) {
AstNode* const ap = new AstGte(fileline(), exprp->cloneTree(true), lhsp);
AstNode* const bp = new AstLte(fileline(), exprp->cloneTree(true), rhsp);
AstNodeExpr* AstInsideRange::newAndFromInside(AstNodeExpr* exprp, AstNodeExpr* lhsp,
AstNodeExpr* rhsp) {
AstNodeExpr* const ap = new AstGte{fileline(), exprp->cloneTree(true), lhsp};
AstNodeExpr* const bp = new AstLte{fileline(), exprp->cloneTree(true), rhsp};
ap->fileline()->modifyWarnOff(V3ErrorCode::UNSIGNED, true);
bp->fileline()->modifyWarnOff(V3ErrorCode::CMPCONST, true);
AstNode* const newp = new AstAnd(fileline(), ap, bp);
return newp;
return new AstAnd{fileline(), ap, bp};
}
AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
@ -291,11 +293,11 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
if (literal[0] == '"') {
// This is a string
const string v = literal.substr(1, literal.find('"', 1) - 1);
return new AstConst(fl, AstConst::VerilogStringLiteral(), v);
return new AstConst{fl, AstConst::VerilogStringLiteral{}, v};
} else if (literal.find_first_of(".eEpP") != string::npos) {
// This may be a real
const double v = VString::parseDouble(literal, &success);
if (success) return new AstConst(fl, AstConst::RealDouble(), v);
if (success) return new AstConst{fl, AstConst::RealDouble{}, v};
}
if (!success) {
// This is either an integer or an error
@ -308,18 +310,18 @@ AstConst* AstConst::parseParamLiteral(FileLine* fl, const string& literal) {
char* endp;
const int v = strtol(literal.c_str(), &endp, 0);
if ((v != 0) && (endp[0] == 0)) { // C literal
return new AstConst(fl, AstConst::Signed32(), v);
return new AstConst{fl, AstConst::Signed32{}, v};
} else { // Try a Verilog literal (fatals if not)
return new AstConst(fl, AstConst::StringToParse(), literal.c_str());
return new AstConst{fl, AstConst::StringToParse{}, literal.c_str()};
}
}
return nullptr;
}
AstNetlist::AstNetlist()
: ASTGEN_SUPER_Netlist(new FileLine(FileLine::builtInFilename()))
, m_typeTablep{new AstTypeTable(fileline())}
, m_constPoolp{new AstConstPool(fileline())} {
: ASTGEN_SUPER_Netlist(new FileLine{FileLine::builtInFilename()})
, m_typeTablep{new AstTypeTable{fileline()}}
, m_constPoolp{new AstConstPool{fileline()}} {
addMiscsp(m_typeTablep);
addMiscsp(m_constPoolp);
}
@ -1045,7 +1047,7 @@ AstVoidDType* AstTypeTable::findVoidDType(FileLine* fl) {
AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
if (VL_UNLIKELY(!m_queueIndexp)) {
AstQueueDType* const newp = new AstQueueDType(fl, AstNode::findUInt32DType(), nullptr);
AstQueueDType* const newp = new AstQueueDType{fl, AstNode::findUInt32DType(), nullptr};
addTypesp(newp);
m_queueIndexp = newp;
}
@ -1055,7 +1057,7 @@ AstQueueDType* AstTypeTable::findQueueIndexDType(FileLine* fl) {
AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
if (m_basicps[kwd]) return m_basicps[kwd];
//
AstBasicDType* const new1p = new AstBasicDType(fl, kwd);
AstBasicDType* const new1p = new AstBasicDType{fl, kwd};
// Because the detailed map doesn't update this map,
// check the detailed map for this same node
// Also adds this new node to the detailed map
@ -1072,7 +1074,7 @@ AstBasicDType* AstTypeTable::findBasicDType(FileLine* fl, VBasicDTypeKwd kwd) {
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd, int width,
int widthMin, VSigning numeric) {
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
AstBasicDType* const new1p = new AstBasicDType{fl, kwd, numeric, width, widthMin};
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
@ -1085,7 +1087,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
const VNumRange& range, int widthMin,
VSigning numeric) {
AstBasicDType* const new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* const new1p = new AstBasicDType{fl, kwd, numeric, range, widthMin};
AstBasicDType* const newp = findInsertSameDType(new1p);
if (newp != new1p) {
VL_DO_DANGLING(new1p->deleteTree(), new1p);
@ -1096,8 +1098,8 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, VBasicDTypeKwd kwd,
}
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
const VBasicTypeKey key(nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange());
const VBasicTypeKey key{nodep->width(), nodep->widthMin(), nodep->numeric(), nodep->keyword(),
nodep->nrange()};
DetailedMap& mapr = m_detailedMap;
const auto it = mapr.find(key);
if (it != mapr.end()) return it->second;
@ -1109,8 +1111,8 @@ AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
AstConstPool::AstConstPool(FileLine* fl)
: ASTGEN_SUPER_ConstPool(fl)
, m_modp{new AstModule(fl, "@CONST-POOL@")}
, m_scopep{new AstScope(fl, m_modp, "@CONST-POOL@", nullptr, nullptr)} {
, m_modp{new AstModule{fl, "@CONST-POOL@"}}
, m_scopep{new AstScope{fl, m_modp, "@CONST-POOL@", nullptr, nullptr}} {
this->modulep(m_modp);
m_modp->addStmtsp(m_scopep);
}
@ -1120,14 +1122,14 @@ const char* AstConstPool::broken() const {
return nullptr;
}
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNode* initp) {
AstVarScope* AstConstPool::createNewEntry(const string& name, AstNodeExpr* initp) {
FileLine* const fl = initp->fileline();
AstVar* const varp = new AstVar(fl, VVarType::MODULETEMP, name, initp->dtypep());
AstVar* const varp = new AstVar{fl, VVarType::MODULETEMP, name, initp->dtypep()};
varp->isConst(true);
varp->isStatic(true);
varp->valuep(initp->cloneTree(false));
m_modp->addStmtsp(varp);
AstVarScope* const varScopep = new AstVarScope(fl, m_scopep, varp);
AstVarScope* const varScopep = new AstVarScope{fl, m_scopep, varp};
m_scopep->addVarsp(varScopep);
return varScopep;
}
@ -1191,6 +1193,7 @@ AstVarScope* AstConstPool::findTable(AstInitArray* initp) {
UASSERT_OBJ(VN_IS(valuep, Const), valuep, "Const pool table entry must be Const");
}
// Try to find an existing table with the same content
// cppcheck-has-bug-suppress unreadVariable
const V3Hash hash = V3Hasher::uncachedHash(initp);
const auto& er = m_tables.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
@ -1220,6 +1223,7 @@ static bool sameInit(const AstConst* ap, const AstConst* bp) {
AstVarScope* AstConstPool::findConst(AstConst* initp, bool mergeDType) {
// Try to find an existing constant with the same value
// cppcheck-has-bug-suppress unreadVariable
const V3Hash hash = initp->num().toHash();
const auto& er = m_consts.equal_range(hash.value());
for (auto it = er.first; it != er.second; ++it) {
@ -1376,8 +1380,8 @@ string AstBasicDType::prettyDTypeName() const {
return os.str();
}
void AstNodeMath::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstNodeExpr::dump(std::ostream& str) const { this->AstNode::dump(str); }
void AstNodeUniop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstCCast::dump(std::ostream& str) const {
this->AstNodeUniop::dump(str);
@ -1503,8 +1507,16 @@ void AstDisplay::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
// str << " " << displayType().ascii();
}
void AstEnumDType::dump(std::ostream& str) const {
this->AstNodeDType::dump(str);
str << " enum";
}
void AstEnumDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "enum";
}
void AstEnumItemRef::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
str << " -> ";
if (itemp()) {
itemp()->dump(str);
@ -1565,17 +1577,17 @@ void AstInitArray::cloneRelink() {
if (it->second->clonep()) it->second = it->second->clonep();
}
}
void AstInitArray::addIndexValuep(uint64_t index, AstNode* newp) {
void AstInitArray::addIndexValuep(uint64_t index, AstNodeExpr* newp) {
const auto it = m_map.find(index);
if (it != m_map.end()) {
it->second->valuep(newp);
} else {
AstInitItem* const itemp = new AstInitItem(fileline(), newp);
AstInitItem* const itemp = new AstInitItem{fileline(), newp};
m_map.emplace(index, itemp);
addInitsp(itemp);
}
}
AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
AstNodeExpr* AstInitArray::getIndexValuep(uint64_t index) const {
const auto it = m_map.find(index);
if (it == m_map.end()) {
return nullptr;
@ -1583,8 +1595,8 @@ AstNode* AstInitArray::getIndexValuep(uint64_t index) const {
return it->second->valuep();
}
}
AstNode* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
AstNode* valuep = getIndexValuep(index);
AstNodeExpr* AstInitArray::getIndexDefaultedValuep(uint64_t index) const {
AstNodeExpr* valuep = getIndexValuep(index);
if (!valuep) valuep = defaultp();
return valuep;
}
@ -1615,11 +1627,11 @@ void AstJumpLabel::dump(std::ostream& str) const {
}
}
void AstLogOr::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
if (sideEffect()) str << " [SIDE]";
}
void AstMemberSel::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
str << " -> ";
if (varp()) {
varp()->dump(str);
@ -1636,7 +1648,6 @@ const char* AstMemberSel::broken() const {
}
void AstMethodCall::dump(std::ostream& str) const {
this->AstNodeFTaskRef::dump(str);
if (isStatement()) str << " [STMT]";
str << " -> ";
if (taskp()) {
taskp()->dump(str);
@ -1705,7 +1716,7 @@ void AstPrintTimeScale::dump(std::ostream& str) const {
str << " " << timeunit();
}
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstNodeTermop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstTime::dump(std::ostream& str) const {
this->AstNodeTermop::dump(str);
str << " " << timeunit();
@ -1758,6 +1769,10 @@ void AstRefDType::dump(std::ostream& str) const {
str << " -> UNLINKED";
}
}
void AstRefDType::dumpSmall(std::ostream& str) const {
this->AstNodeDType::dumpSmall(str);
str << "ref";
}
const char* AstRefDType::broken() const {
BROKEN_RTN(m_typedefp && !m_typedefp->brokeExists());
BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists());
@ -1857,7 +1872,7 @@ const char* AstNetlist::broken() const {
}
AstPackage* AstNetlist::dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName());
m_dollarUnitPkgp = new AstPackage{fileline(), AstPackage::dollarUnitName()};
// packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->inLibrary(true);
m_dollarUnitPkgp->modTrace(false); // may reconsider later
@ -1908,10 +1923,10 @@ void AstPackageImport::cloneRelink() {
if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep();
}
void AstPatMember::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
if (isDefault()) str << " [DEFAULT]";
}
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeMath::dump(str); }
void AstNodeTriop::dump(std::ostream& str) const { this->AstNodeExpr::dump(str); }
void AstSel::dump(std::ostream& str) const {
this->AstNodeTriop::dump(str);
if (declRange().ranged()) {
@ -1979,7 +1994,7 @@ bool AstWildcardArrayDType::same(const AstNode* samep) const {
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstWildcardArrayDType::similarDType(AstNodeDType* samep) const {
bool AstWildcardArrayDType::similarDType(const AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
@ -1993,7 +2008,7 @@ bool AstUnsizedArrayDType::same(const AstNode* samep) const {
if (!asamep->subDTypep()) return false;
return (subDTypep() == asamep->subDTypep());
}
bool AstUnsizedArrayDType::similarDType(AstNodeDType* samep) const {
bool AstUnsizedArrayDType::similarDType(const AstNodeDType* samep) const {
const AstNodeArrayDType* const asamep = static_cast<const AstNodeArrayDType*>(samep);
return type() == samep->type() && asamep->subDTypep()
&& subDTypep()->skipRefp()->similarDType(asamep->subDTypep()->skipRefp());
@ -2018,7 +2033,7 @@ void AstVarScope::dump(std::ostream& str) const {
}
}
void AstNodeVarRef::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " " << access().arrow() << " ";
}
@ -2086,7 +2101,7 @@ void AstScope::dump(std::ostream& str) const {
str << " [modp=" << reinterpret_cast<const void*>(modp()) << "]";
}
void AstScopeName::dump(std::ostream& str) const {
this->AstNodeMath::dump(str);
this->AstNodeExpr::dump(str);
if (dpiExport()) str << " [DPIEX]";
if (forFormat()) str << " [FMT]";
}
@ -2145,7 +2160,7 @@ void AstActive::cloneRelink() {
if (m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
}
void AstNodeFTaskRef::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
this->AstNodeExpr::dump(str);
if (classOrPackagep()) str << " pkg=" << nodeAddr(classOrPackagep());
str << " -> ";
if (dotted() != "") str << ".=" << dotted() << " ";
@ -2248,8 +2263,15 @@ void AstCFunc::dump(std::ostream& str) const {
if (isVirtual()) str << " [VIRT]";
if (isCoroutine()) str << " [CORO]";
}
const char* AstCAwait::broken() const {
BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists());
return nullptr;
}
void AstCAwait::cloneRelink() {
if (m_sensesp && m_sensesp->clonep()) m_sensesp = m_sensesp->clonep();
}
void AstCAwait::dump(std::ostream& str) const {
this->AstNodeStmt::dump(str);
this->AstNodeUniop::dump(str);
if (sensesp()) {
str << " => ";
sensesp()->dump(str);
@ -2265,7 +2287,7 @@ int AstCMethodHard::instrCount() const {
return INSTR_COUNT_LD;
}
}
return AstNodeStmt::instrCount();
return 0;
}
const char* AstCFunc::broken() const {
BROKEN_RTN((m_scopep && !m_scopep->brokeExists()));
@ -2282,8 +2304,8 @@ void AstCUse::dump(std::ostream& str) const {
AstAlways* AstAssignW::convertToAlways() {
const bool hasTimingControl = isTimingControl();
AstNode* const lhs1p = lhsp()->unlinkFrBack();
AstNode* const rhs1p = rhsp()->unlinkFrBack();
AstNodeExpr* const lhs1p = lhsp()->unlinkFrBack();
AstNodeExpr* const rhs1p = rhsp()->unlinkFrBack();
AstNode* const controlp = timingControlp() ? timingControlp()->unlinkFrBack() : nullptr;
FileLine* const flp = fileline();
AstNode* bodysp = new AstAssign{flp, lhs1p, rhs1p, controlp};

View File

@ -95,8 +95,8 @@ private:
m_unnamedScope = dot(m_unnamedScope, ident);
// Create CellInline for dotted var resolution
if (!m_ftaskp) {
AstCellInline* const inlinep = new AstCellInline(
nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit());
AstCellInline* const inlinep = new AstCellInline{
nodep->fileline(), m_unnamedScope, blockName, m_modp->timeunit()};
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}

View File

@ -355,8 +355,8 @@ void V3Broken::brokenAll(AstNetlist* nodep) {
void V3Broken::selfTest() {
// Exercise addNewed and deleted for coverage, as otherwise only used with VL_LEAK_CHECKS
FileLine* const fl = new FileLine(FileLine::commandLineFilename());
const AstNode* const newp = new AstBegin(fl, "[EditWrapper]", nullptr);
FileLine* const fl = new FileLine{FileLine::commandLineFilename()};
const AstNode* const newp = new AstBegin{fl, "[EditWrapper]", nullptr};
addNewed(newp);
deleted(newp);
VL_DO_DANGLING(delete newp, newp);

View File

@ -112,13 +112,14 @@ public:
rootFuncp->name(m_basename);
for (AstCFunc* const funcp : m_newFunctions) {
AstCCall* const callp = new AstCCall{m_modp->fileline(), funcp};
callp->dtypeSetVoid();
if (m_type.isClass()) {
callp->argTypes("vlSymsp");
} else {
if (m_type.isCoverage()) callp->argTypes("first");
callp->selfPointer("this");
}
rootFuncp->addStmtsp(callp);
rootFuncp->addStmtsp(callp->makeStmt());
}
}
}
@ -151,7 +152,7 @@ void V3CCtors::evalAsserts() {
AstVarRef* const vrefp
= new AstVarRef{varp->fileline(), varp, VAccess::READ};
vrefp->selfPointer("this");
AstNode* newp = vrefp;
AstNodeExpr* newp = vrefp;
if (varp->isWide()) {
newp = new AstWordSel{
varp->fileline(), newp,
@ -159,15 +160,14 @@ void V3CCtors::evalAsserts() {
}
const uint64_t value = VL_MASK_Q(storedWidth) & ~VL_MASK_Q(lastWordWidth);
newp = new AstAnd{varp->fileline(), newp,
new AstConst(varp->fileline(), AstConst::WidthedValue(),
new AstConst(varp->fileline(), AstConst::WidthedValue{},
storedWidth, value)};
AstNodeIf* const ifp = new AstIf{
varp->fileline(), newp,
new AstCStmt{varp->fileline(), "Verilated::overWidthError(\""
+ varp->prettyName() + "\");"}};
ifp->branchPred(VBranchPred::BP_UNLIKELY);
newp = ifp;
funcp->addStmtsp(newp);
funcp->addStmtsp(ifp);
}
}
}

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