Merge from master for release.
This commit is contained in:
commit
8468af1a20
|
|
@ -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
66
Changes
|
|
@ -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:**
|
||||
|
|
|
|||
53
Makefile.in
53
Makefile.in
|
|
@ -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 \
|
||||
|
|
|
|||
18
README.rst
18
README.rst
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:")
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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])
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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()}};
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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".
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-----------------------------
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.)
|
||||
|
|
|
|||
|
|
@ -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::
|
||||
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -37,5 +37,4 @@ PREDEFINED = \
|
|||
"VL_NOT_FINAL=" \
|
||||
"VL_PURE=" \
|
||||
"VL_REQUIRES()=" \
|
||||
"VL_THREAD_LOCAL=" \
|
||||
"__restrict=" \
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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")
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
};
|
||||
|
||||
//=============================================================================
|
||||
|
|
|
|||
|
|
@ -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"
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//********************************************************************
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
@ -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()); }
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -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::*;
|
||||
|
|
@ -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; }
|
||||
};
|
||||
|
||||
//===========================================================================
|
||||
|
|
|
|||
|
|
@ -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];
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
//********************************************************************
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
||||
|
|
|
|||
|
|
@ -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']):
|
||||
|
|
|
|||
|
|
@ -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):
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
|
|
|
|||
|
|
@ -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); }
|
||||
|
||||
|
|
|
|||
|
|
@ -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};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
48
src/V3Ast.h
48
src/V3Ast.h
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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
1128
src/V3AstNodeOther.h
1128
src/V3AstNodeOther.h
File diff suppressed because it is too large
Load Diff
|
|
@ -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};
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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
Loading…
Reference in New Issue