mirror of
https://github.com/verilator/verilator.git
synced 2026-10-06 01:54:01 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
436d3d76f0 | ||
|
|
c1f0787669 | ||
|
|
dae4c8ee22 | ||
|
|
5daf7385f1 | ||
|
|
4ce8164277 | ||
|
|
7ec32799b0 | ||
|
|
812861e7f2 | ||
|
|
1857f6399c | ||
|
|
f7ccc013e7 | ||
|
|
2e1fa8f338 | ||
|
|
70459b3208 | ||
|
|
2a23ec74e4 | ||
|
|
be1ace423e | ||
|
|
2d0149b703 | ||
|
|
34ced254c0 | ||
|
|
fe15171649 | ||
|
|
4092ac7e72 | ||
|
|
1a07af57a3 | ||
|
|
c840ffb0ae | ||
|
|
fbe8439eb8 | ||
|
|
754c5c71f1 | ||
|
|
6940ee420d | ||
|
|
b645fcf027 | ||
|
|
ffb02cea15 | ||
|
|
f753ae2518 | ||
|
|
caa19c0cb3 | ||
|
|
aa3942ab24 | ||
|
|
cc1133c0d9 | ||
|
|
ac659d525b | ||
|
|
283f6c7433 | ||
|
|
5b65c15eca | ||
|
|
6b4183632c | ||
|
|
e0e164cea2 | ||
|
|
a379382d32 | ||
|
|
e2a6e19cac | ||
|
|
61bfb6c308 | ||
|
|
bdcfc4e286 | ||
|
|
70c6651aac | ||
|
|
41bb54bc2c | ||
|
|
001c098e5a | ||
|
|
98e40c847c | ||
|
|
05c7a3b90b | ||
|
|
694f2ff7c7 | ||
|
|
6281385ee8 | ||
|
|
7e6dd9473f | ||
|
|
929e15fa4c | ||
|
|
432d5f851d | ||
|
|
d4f4fefd1d | ||
|
|
d8080008b4 | ||
|
|
bed9aa9904 | ||
|
|
35fa0d051d | ||
|
|
0507fb4655 | ||
|
|
f4a01eb452 | ||
|
|
4954e76b28 | ||
|
|
fa1b11252e | ||
|
|
dddc1b5b4d | ||
|
|
20faa99464 | ||
|
|
dc43071f1c | ||
|
|
fdf29b970f | ||
|
|
70814fa11a | ||
|
|
529b8337ec | ||
|
|
f8dd65c7cd | ||
|
|
28a59a2b21 | ||
|
|
d3e205f201 | ||
|
|
dfe28f7ed0 | ||
|
|
bb871728c9 | ||
|
|
69dce205d3 | ||
|
|
052812bb87 | ||
|
|
0380a36c76 | ||
|
|
44f49669a3 | ||
|
|
ff244c1d1f | ||
|
|
260ac342f4 | ||
|
|
87d856339f | ||
|
|
e171463fa2 | ||
|
|
481adf8fe7 | ||
|
|
b8288b97f7 | ||
|
|
0d34f56b74 | ||
|
|
dcaf6476e8 | ||
|
|
76b2ac9cc1 | ||
|
|
b6a400ee9b | ||
|
|
78d6ec8114 | ||
|
|
88dd95980a | ||
|
|
b531001f55 | ||
|
|
1d0563212e | ||
|
|
8ca49d98c1 | ||
|
|
036c1fb0f9 | ||
|
|
19258ee18a | ||
|
|
578d8d8391 | ||
|
|
010ae580b1 | ||
|
|
951f5eaa82 | ||
|
|
3a69dd4a43 | ||
|
|
f52155a768 | ||
|
|
16b3d9101c |
@@ -9,7 +9,7 @@ assignees: ''
|
|||||||
|
|
||||||
Thanks for taking the time to report this.
|
Thanks for taking the time to report this.
|
||||||
|
|
||||||
Can you attach an example that shows the issue? (Must be openly licensed, ideally in test_regress format.)
|
Can you attach an example that shows the issue? (Must be openly licensed, completely self-contaned so can directly run what you provide. Ideally use test_regress format, see https://veripool.org/guide/latest/contributing.html?highlight=test_regress#reporting-bugs
|
||||||
|
|
||||||
What 'verilator' command line do we use to run your example?
|
What 'verilator' command line do we use to run your example?
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -16,14 +16,14 @@ cmake_minimum_required(VERSION 3.15)
|
|||||||
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
cmake_policy(SET CMP0091 NEW) # Use MSVC_RUNTIME_LIBRARY to select the runtime
|
||||||
project(
|
project(
|
||||||
Verilator
|
Verilator
|
||||||
VERSION 5.032
|
VERSION 5.034
|
||||||
HOMEPAGE_URL https://verilator.org
|
HOMEPAGE_URL https://verilator.org
|
||||||
LANGUAGES CXX
|
LANGUAGES CXX
|
||||||
)
|
)
|
||||||
|
|
||||||
# Set default build type to Release if not specified
|
# Set default build type to Release if not specified
|
||||||
if(NOT CMAKE_BUILD_TYPE)
|
if(NOT CMAKE_BUILD_TYPE)
|
||||||
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type" FORCE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
option(
|
option(
|
||||||
|
|||||||
@@ -8,6 +8,65 @@ The changes in each Verilator version are described below. The
|
|||||||
contributors that suggested a given feature are shown in []. Thanks!
|
contributors that suggested a given feature are shown in []. Thanks!
|
||||||
|
|
||||||
|
|
||||||
|
Verilator 5.034 2025-02-24
|
||||||
|
==========================
|
||||||
|
|
||||||
|
**Important:**
|
||||||
|
|
||||||
|
* This is likely the last version to support Ubuntu 20.04, which is at end-of-life.
|
||||||
|
* Add expression coverage (#4677) (#5719). [Todd Strader]
|
||||||
|
|
||||||
|
**Other:**
|
||||||
|
|
||||||
|
* Add `COVERIGN` warning, as a more specific UNSUPPORTED error.
|
||||||
|
* Add `--public-ignore` to ignore public metacomments (#5716). [Andrew Nolte]
|
||||||
|
* Add `--preproc-token-limit` (#5768). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Add lint error on importing package within a class (#5634) (#5679). [Nick Brereton]
|
||||||
|
* Add `--preproc-resolve` for modules in preprocessor output (#5789). [Kamil Rakoczy, Antmicro Ltd.]
|
||||||
|
* Support multidimensional array access via VPI (#2812) (#5573). [Krzysztof Starecki]
|
||||||
|
* Support nested classes (#4178) (#5778). [Kamil Rakoczy, Antmicro Ltd.]
|
||||||
|
* Support VPI array accessors (#5612). [Moubarak Jeje]
|
||||||
|
* Support unpacked structure constrained randomization (#5657) (#5759). [Yilou Wang]
|
||||||
|
* Support generated classes (#5665). [Shou-Li Hsu]
|
||||||
|
* Support constraints on associative array user-defined keys (#5671) (#5729). [Yilou Wang]
|
||||||
|
* Support `+incdir` with multiple directories.
|
||||||
|
* Support integer atom type ports in `--hierarchical` (#5748). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Support constrained random for arrays in structs (#5765) (#5802). [Yilou Wang]
|
||||||
|
* Support selects on arbitrary string expressions (#5773). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Support side effects of form 'variable[index_function()]++'.
|
||||||
|
* Improve hierarchical DPI wrapper scheduling performance (#2583) (#5734). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Improve VPI write errors (#5712). [Andrew Nolte]
|
||||||
|
* Improve `resetall support (#5728) (#5730). [Ethan Sifferman]
|
||||||
|
* Optimize labels as final `if` block statements (#5744).
|
||||||
|
* Optimize empty function definition bodies (#5750).
|
||||||
|
* Optimize splitting trigger computation and dump (#5798). [Geza Lore]
|
||||||
|
* Fix error message when call task as a function (#3089). [Matthew Ballance]
|
||||||
|
* Fix force VPI public signal visibility (#5225). [Frédéric Requin]
|
||||||
|
* Fix VPI iteration over hierarchy (#5314) (#5731). [Natan Kreimer]
|
||||||
|
* Fix constrained random for > 64-bit associative arrays (#5670) (#5682). [Yilou Wang]
|
||||||
|
* Fix mis-optimizing away `$urandom` (#5703). [Parker Schless]
|
||||||
|
* Fix packages with `--public-depth 1` (#5708). [Andrew Nolte]
|
||||||
|
* Fix V3Simulate constant reuse (#5709). [Geza Lore]
|
||||||
|
* Fix man pages what-is section (#5710). [Ahmed El-Mahmoudy]
|
||||||
|
* Fix pattern assignment to real inside struct (#5713).
|
||||||
|
* Fix %p format output for real inside struct (#5713).
|
||||||
|
* Fix segfault when only enum value referenced in package (#5714). [Dan Katz]
|
||||||
|
* Fix `BLKSEQ` on suspendable processes (#5722). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Fix vpiDefName issues with non-inlined scopes and dpi conflicts (#5732). [Andrew Nolte]
|
||||||
|
* Fix inlined expression with assignment under LHS of NBA (#5736) (#5740). [Geza Lore]
|
||||||
|
* Fix duplicate-named class variable equivalence (#5737).
|
||||||
|
* Fix `-j` ignored after `-f` (#5749). [Luca Colagrande]
|
||||||
|
* Fix handling forced assigns in V3Life (#5757). [Bartłomiej Chmiel, Antmicro Ltd.]
|
||||||
|
* Fix VFileContent reference count (#5769) (#5771). [Dave Sargeant]
|
||||||
|
* Fix ignoring joins in stringify in preprocessor (#5777). [Krzysztof Bieganski, Antmicro Ltd.]
|
||||||
|
* Fix unpacked split_var (#5782) (#5785). [Yutetsu TAKATSUKASA]
|
||||||
|
* Fix time import error on time parameters (#5786). [Luca Colagrande]
|
||||||
|
* Fix dpi context functions (#5788). [Ryszard Rozak, Antmicro Ltd.]
|
||||||
|
* Fix `$monitor` with dotted references (#5794). [Ahmed Elzeftawi]
|
||||||
|
* Fix parsing input wire with default and range (#5800). [RJ Cunningham]
|
||||||
|
* Fix matching language extension options including dots.
|
||||||
|
|
||||||
|
|
||||||
Verilator 5.032 2025-01-01
|
Verilator 5.032 2025-01-01
|
||||||
==========================
|
==========================
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -192,7 +192,7 @@ examples: all_nomsg
|
|||||||
# Docs
|
# Docs
|
||||||
|
|
||||||
.PHONY: docs
|
.PHONY: docs
|
||||||
docs: info
|
docs: info $(VL_INST_MAN_FILES)
|
||||||
|
|
||||||
info: $(INFOS)
|
info: $(INFOS)
|
||||||
|
|
||||||
@@ -201,7 +201,8 @@ verilator.1: ${srcdir}/bin/verilator
|
|||||||
verilator_coverage.1: ${srcdir}/bin/verilator_coverage
|
verilator_coverage.1: ${srcdir}/bin/verilator_coverage
|
||||||
pod2man $< $@
|
pod2man $< $@
|
||||||
%.1: ${srcdir}/bin/%
|
%.1: ${srcdir}/bin/%
|
||||||
help2man --no-info --no-discard-stderr --version-string=- $< -o $@
|
help2man --no-info --no-discard-stderr --version-string=- \
|
||||||
|
-n "$(shell $< --help | head -n 3 | tail -n 1)" $< -o $@
|
||||||
|
|
||||||
.PHONY: verilator.html
|
.PHONY: verilator.html
|
||||||
verilator.html:
|
verilator.html:
|
||||||
|
|||||||
+13
-9
@@ -269,8 +269,7 @@ __END__
|
|||||||
|
|
||||||
=head1 NAME
|
=head1 NAME
|
||||||
|
|
||||||
Verilator - Translate and simulate SystemVerilog code using C++/SystemC
|
Verilator - Lint, compile and simulate SystemVerilog code using C++/SystemC
|
||||||
|
|
||||||
|
|
||||||
=head1 SYNOPSIS
|
=head1 SYNOPSIS
|
||||||
|
|
||||||
@@ -329,6 +328,8 @@ detailed descriptions of these arguments.
|
|||||||
--compiler-include Include additional header in the precompiled one
|
--compiler-include Include additional header in the precompiled one
|
||||||
--converge-limit <loops> Tune convergence settle time
|
--converge-limit <loops> Tune convergence settle time
|
||||||
--coverage Enable all coverage
|
--coverage Enable all coverage
|
||||||
|
--coverage-expr Enable expression coverage
|
||||||
|
--coverage-expr-max <value> Maximum permutations allowed for an expression
|
||||||
--coverage-line Enable line coverage
|
--coverage-line Enable line coverage
|
||||||
--coverage-max-width <width> Maximum array depth for coverage
|
--coverage-max-width <width> Maximum array depth for coverage
|
||||||
--coverage-toggle Enable toggle coverage
|
--coverage-toggle Enable toggle coverage
|
||||||
@@ -375,8 +376,8 @@ detailed descriptions of these arguments.
|
|||||||
--gdb Run Verilator under GDB interactively
|
--gdb Run Verilator under GDB interactively
|
||||||
--gdbbt Run Verilator under GDB for backtrace
|
--gdbbt Run Verilator under GDB for backtrace
|
||||||
--generate-key Create random key for --protect-key
|
--generate-key Create random key for --protect-key
|
||||||
--getenv <var> Get environment variable with defaults
|
|
||||||
--get-supported <feature> Get if feature is supported
|
--get-supported <feature> Get if feature is supported
|
||||||
|
--getenv <var> Get environment variable with defaults
|
||||||
--help Show this help
|
--help Show this help
|
||||||
--hierarchical Enable hierarchical Verilation
|
--hierarchical Enable hierarchical Verilation
|
||||||
--hierarchical-params-file <name> Internal option that specifies parameters file for hier blocks
|
--hierarchical-params-file <name> Internal option that specifies parameters file for hier blocks
|
||||||
@@ -386,6 +387,11 @@ detailed descriptions of these arguments.
|
|||||||
--inline-mult <value> Tune module inlining
|
--inline-mult <value> Tune module inlining
|
||||||
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
|
--instr-count-dpi <value> Assumed dynamic instruction count of DPI imports
|
||||||
-j <jobs> Parallelism for --build-jobs/--verilate-jobs
|
-j <jobs> Parallelism for --build-jobs/--verilate-jobs
|
||||||
|
--no-json-edit-nums Don't dump editNum in .tree.json files
|
||||||
|
--no-json-ids Don't use short identifiers instead of adresses/paths in .tree.json
|
||||||
|
--json-only Create JSON parser output (.tree.json and .meta.json)
|
||||||
|
--json-only-output .tree.json output filename
|
||||||
|
--json-only-meta-output .tree.meta.json output filename
|
||||||
--l2-name <value> Verilog scope name of the top module
|
--l2-name <value> Verilog scope name of the top module
|
||||||
--language <lang> Default language standard to parse
|
--language <lang> Default language standard to parse
|
||||||
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
-LDFLAGS <flags> Linker pre-object arguments for makefile
|
||||||
@@ -422,6 +428,8 @@ detailed descriptions of these arguments.
|
|||||||
--pipe-filter <command> Filter all input through a script
|
--pipe-filter <command> Filter all input through a script
|
||||||
--pp-comments Show preprocessor comments with -E
|
--pp-comments Show preprocessor comments with -E
|
||||||
--prefix <topname> Name of top-level class
|
--prefix <topname> Name of top-level class
|
||||||
|
--preproc-resolve Include all found modules in the output with -E
|
||||||
|
--preproc-token-limit Maximum tokens on a line allowed by preprocessor
|
||||||
--private Debugging; see docs
|
--private Debugging; see docs
|
||||||
--prof-c Compile C++ code with profiling
|
--prof-c Compile C++ code with profiling
|
||||||
--prof-cfuncs Name functions for profiling
|
--prof-cfuncs Name functions for profiling
|
||||||
@@ -432,8 +440,9 @@ detailed descriptions of these arguments.
|
|||||||
--protect-lib <name> Create a DPI protected library
|
--protect-lib <name> Create a DPI protected library
|
||||||
--public Mark signals as public; see docs
|
--public Mark signals as public; see docs
|
||||||
--public-depth <level> Mark public to specified module depth
|
--public-depth <level> Mark public to specified module depth
|
||||||
--public-params Mark all parameters as public_flat
|
|
||||||
--public-flat-rw Mark all variables, etc as public_flat_rw
|
--public-flat-rw Mark all variables, etc as public_flat_rw
|
||||||
|
--public-ignore Ignore all public comment markings
|
||||||
|
--public-params Mark all parameters as public_flat
|
||||||
-pvalue+<name>=<value> Overwrite toplevel parameter
|
-pvalue+<name>=<value> Overwrite toplevel parameter
|
||||||
--quiet Minimize additional printing
|
--quiet Minimize additional printing
|
||||||
--quiet-exit Don't print the command on failure
|
--quiet-exit Don't print the command on failure
|
||||||
@@ -506,11 +515,6 @@ detailed descriptions of these arguments.
|
|||||||
--x-assign <mode> Assign non-initial Xs to this value
|
--x-assign <mode> Assign non-initial Xs to this value
|
||||||
--x-initial <mode> Assign initial Xs to this value
|
--x-initial <mode> Assign initial Xs to this value
|
||||||
--x-initial-edge Enable initial X->0 and X->1 edge triggers
|
--x-initial-edge Enable initial X->0 and X->1 edge triggers
|
||||||
--no-json-edit-nums Don't dump editNum in .tree.json files
|
|
||||||
--no-json-ids Don't use short identifiers instead of adresses/paths in .tree.json
|
|
||||||
--json-only Create JSON parser output (.tree.json and .meta.json)
|
|
||||||
--json-only-output .tree.json output filename
|
|
||||||
--json-only-meta-output .tree.meta.json output filename
|
|
||||||
--xml-only Create XML parser output
|
--xml-only Create XML parser output
|
||||||
--xml-output XML output filename
|
--xml-output XML output filename
|
||||||
-y <dir> Directory to search for modules
|
-y <dir> Directory to search for modules
|
||||||
|
|||||||
+1
-1
@@ -521,7 +521,7 @@ def write_vcd(filename):
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""Create Gantt chart of multi-threaded execution.
|
description="""Create Gantt chart of Verilator multi-threaded execution
|
||||||
|
|
||||||
Verilator_gantt creates a visual representation to help analyze Verilator
|
Verilator_gantt creates a visual representation to help analyze Verilator
|
||||||
#xmultithreaded simulation performance, by showing when each macro-task
|
#xmultithreaded simulation performance, by showing when each macro-task
|
||||||
|
|||||||
@@ -164,7 +164,7 @@ def profcfunc(filename):
|
|||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
allow_abbrev=False,
|
allow_abbrev=False,
|
||||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||||
description="""Read gprof report created with --prof-cfuncs.
|
description="""Read gprof report created with Verilator --prof-cfuncs
|
||||||
|
|
||||||
Verilator_profcfunc reads a profile report created by gprof. The names of
|
Verilator_profcfunc reads a profile report created by gprof. The names of
|
||||||
the functions are then transformed, assuming the user used Verilator's
|
the functions are then transformed, assuming the user used Verilator's
|
||||||
|
|||||||
+3
-2
@@ -10,7 +10,7 @@
|
|||||||
# Then 'make maintainer-dist'
|
# Then 'make maintainer-dist'
|
||||||
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
|
||||||
#AC_INIT([Verilator],[#.### devel])
|
#AC_INIT([Verilator],[#.### devel])
|
||||||
AC_INIT([Verilator],[5.032 2025-01-01],
|
AC_INIT([Verilator],[5.034 2025-02-24],
|
||||||
[https://verilator.org],
|
[https://verilator.org],
|
||||||
[verilator],[https://verilator.org])
|
[verilator],[https://verilator.org])
|
||||||
|
|
||||||
@@ -478,6 +478,7 @@ m4_foreach([cflag],[
|
|||||||
[-Wno-parentheses-equality],
|
[-Wno-parentheses-equality],
|
||||||
[-Wno-shadow],
|
[-Wno-shadow],
|
||||||
[-Wno-sign-compare],
|
[-Wno-sign-compare],
|
||||||
|
[-Wno-subobject-linkage],
|
||||||
[-Wno-tautological-bitwise-compare],
|
[-Wno-tautological-bitwise-compare],
|
||||||
[-Wno-tautological-compare],
|
[-Wno-tautological-compare],
|
||||||
[-Wno-uninitialized],
|
[-Wno-uninitialized],
|
||||||
@@ -538,7 +539,7 @@ _MY_LDLIBS_CHECK_IFELSE(
|
|||||||
[if test "$CFG_WITH_TCMALLOC" != "no"; then
|
[if test "$CFG_WITH_TCMALLOC" != "no"; then
|
||||||
CFG_LIBS="$LTCMALLOC $CFG_LIBS";
|
CFG_LIBS="$LTCMALLOC $CFG_LIBS";
|
||||||
# If using tcmalloc, add some extra options to make the compiler not assume
|
# If using tcmalloc, add some extra options to make the compiler not assume
|
||||||
# it is using it's own versions of the standard library functions
|
# it is using its own versions of the standard library functions
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-malloc)
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-calloc)
|
||||||
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
_MY_CXX_CHECK_OPT(CFG_CXXFLAGS_SRC,-fno-builtin-realloc)
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ This contributing document contains some suggestions that may make
|
|||||||
contributions flow more efficiently.
|
contributions flow more efficiently.
|
||||||
|
|
||||||
|
|
||||||
Did you find a bug?
|
Did you find a Verilator bug?
|
||||||
-------------------
|
-----------------------------
|
||||||
|
|
||||||
- Please **ensure the bug was not already reported** by searching
|
- Please **ensure the bug was not already reported** by searching
|
||||||
`Verilator Issues <https://verilator.org/issues>`__.
|
`Verilator Issues <https://verilator.org/issues>`__.
|
||||||
@@ -28,8 +28,8 @@ Did you find a bug?
|
|||||||
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
<https://github.com/verilator/verilator/blob/master/docs/internals.rst>`__.
|
||||||
|
|
||||||
|
|
||||||
Did you write a patch that fixes a bug?
|
Did you write a patch that fixes a Verilator bug?
|
||||||
---------------------------------------
|
-------------------------------------------------
|
||||||
|
|
||||||
- Please `Open a new Verilator issue <https://verilator.org/issues/new>`__
|
- Please `Open a new Verilator issue <https://verilator.org/issues/new>`__
|
||||||
if there is not one already describing the bug.
|
if there is not one already describing the bug.
|
||||||
@@ -72,8 +72,8 @@ Did you write a patch that fixes a bug?
|
|||||||
- Most important is we get your patch.
|
- Most important is we get your patch.
|
||||||
|
|
||||||
|
|
||||||
Do you have questions?
|
Do you have questions on Verilator?
|
||||||
----------------------
|
-----------------------------------
|
||||||
|
|
||||||
- Please see FAQ section and rest of the `Verilator
|
- Please see FAQ section and rest of the `Verilator
|
||||||
manual <https://verilator.org/verilator_doc.html>`__, or `Verilator
|
manual <https://verilator.org/verilator_doc.html>`__, or `Verilator
|
||||||
|
|||||||
@@ -38,9 +38,11 @@ Daniel Bates
|
|||||||
David Horton
|
David Horton
|
||||||
David Ledger
|
David Ledger
|
||||||
David Metz
|
David Metz
|
||||||
|
Dave Sargeant
|
||||||
David Stanford
|
David Stanford
|
||||||
David Turner
|
David Turner
|
||||||
Dercury
|
Dercury
|
||||||
|
Diego Roux
|
||||||
Don Williamson
|
Don Williamson
|
||||||
Drew Ranck
|
Drew Ranck
|
||||||
Drew Taussig
|
Drew Taussig
|
||||||
@@ -99,6 +101,7 @@ Jesse Taube
|
|||||||
Jevin Sweval
|
Jevin Sweval
|
||||||
Jiacheng Qian
|
Jiacheng Qian
|
||||||
Jiamin Zhu
|
Jiamin Zhu
|
||||||
|
Jitesh Nayak
|
||||||
Jinyan Xu
|
Jinyan Xu
|
||||||
Jiuyang Liu
|
Jiuyang Liu
|
||||||
Joey Liu
|
Joey Liu
|
||||||
@@ -155,10 +158,13 @@ Miodrag Milanović
|
|||||||
Mladen Slijepcevic
|
Mladen Slijepcevic
|
||||||
Morten Borup Petersen
|
Morten Borup Petersen
|
||||||
Mostafa Gamal
|
Mostafa Gamal
|
||||||
|
Moubarak Jeje
|
||||||
Nandu Raj
|
Nandu Raj
|
||||||
|
Natan Kreimer
|
||||||
Nathan Graybeal
|
Nathan Graybeal
|
||||||
Nathan Kohagen
|
Nathan Kohagen
|
||||||
Nathan Myers
|
Nathan Myers
|
||||||
|
Nick Brereton
|
||||||
Nolan Poe
|
Nolan Poe
|
||||||
Oleh Maksymenko
|
Oleh Maksymenko
|
||||||
Patrick Stewart
|
Patrick Stewart
|
||||||
@@ -210,6 +216,7 @@ Todd Strader
|
|||||||
Tomasz Gorochowik
|
Tomasz Gorochowik
|
||||||
Topa Topino
|
Topa Topino
|
||||||
Toru Niina
|
Toru Niina
|
||||||
|
Trung Nguyen
|
||||||
Tudor Timi
|
Tudor Timi
|
||||||
Tymoteusz Blazejczyk
|
Tymoteusz Blazejczyk
|
||||||
Udi Finkelstein
|
Udi Finkelstein
|
||||||
|
|||||||
@@ -237,7 +237,17 @@ Summary:
|
|||||||
.. option:: --coverage
|
.. option:: --coverage
|
||||||
|
|
||||||
Enables all forms of coverage, an alias for :vlopt:`--coverage-line`
|
Enables all forms of coverage, an alias for :vlopt:`--coverage-line`
|
||||||
:vlopt:`--coverage-toggle` :vlopt:`--coverage-user`.
|
:vlopt:`--coverage-toggle` :vlopt:`--coverage-expr` :vlopt:`--coverage-user`.
|
||||||
|
|
||||||
|
.. option:: --coverage-expr
|
||||||
|
|
||||||
|
Enables expression coverage analysis. See :ref:`Expression Coverage`.
|
||||||
|
|
||||||
|
.. option:: --coverage-expr-max <value>
|
||||||
|
|
||||||
|
Rarely needed. Specifies the maximum number of permutations able to be
|
||||||
|
covered for a given expression. Defaults to 32. Increasing may slow
|
||||||
|
coverage simulations and make analyzing the results unwieldy.
|
||||||
|
|
||||||
.. option:: --coverage-line
|
.. option:: --coverage-line
|
||||||
|
|
||||||
@@ -480,8 +490,8 @@ Summary:
|
|||||||
out. Beware of enabling debugging messages, as they will also go to
|
out. Beware of enabling debugging messages, as they will also go to
|
||||||
standard out. See :vlopt:`--no-std`, which is implied by this.
|
standard out. See :vlopt:`--no-std`, which is implied by this.
|
||||||
|
|
||||||
See also :vlopt:`--dump-defines`, :vlopt:`-P`, and
|
See also :vlopt:`--dump-defines`, :vlopt:`-P`, :vlopt:`--pp-comments`
|
||||||
:vlopt:`--pp-comments` options.
|
and :vlopt:`--preproc-resolve` options.
|
||||||
|
|
||||||
.. option:: --emit-accessors
|
.. option:: --emit-accessors
|
||||||
|
|
||||||
@@ -751,7 +761,10 @@ Summary:
|
|||||||
|
|
||||||
.. option:: +incdir+<dir>
|
.. option:: +incdir+<dir>
|
||||||
|
|
||||||
See :vlopt:`-y`.
|
See :vlopt:`-y`. Unlike with :vlopt:`-y`, multiple directories may be
|
||||||
|
specified separated with a `+` symbol; this is for Verilog-XL
|
||||||
|
compatibility and is not recommended usage as this is not supported by
|
||||||
|
some third-party tools.
|
||||||
|
|
||||||
.. option:: --inline-mult <value>
|
.. option:: --inline-mult <value>
|
||||||
|
|
||||||
@@ -779,6 +792,38 @@ Summary:
|
|||||||
the number of threads in the current hardware. Otherwise, must be a
|
the number of threads in the current hardware. Otherwise, must be a
|
||||||
positive integer specifying the maximum number of parallel build jobs.
|
positive integer specifying the maximum number of parallel build jobs.
|
||||||
|
|
||||||
|
.. option:: --json-only
|
||||||
|
|
||||||
|
Create JSON output only, do not create any other output.
|
||||||
|
|
||||||
|
The JSON format is intended to be used to leverage Verilator's parser and
|
||||||
|
elaboration to feed to other downstream tools. For details on the format, see
|
||||||
|
the Verilator Internals manual. Be aware that the JSON
|
||||||
|
format is still evolving; there will be some changes in future versions.
|
||||||
|
|
||||||
|
This option disables some more aggressive transformations and dumps only
|
||||||
|
the final state of the AST. For more granular and unaltered dumps, meant
|
||||||
|
mainly for debugging see :vlopt:`--dump-tree-json`.
|
||||||
|
|
||||||
|
.. option:: --json-only-meta-output <filename>
|
||||||
|
|
||||||
|
Specifies the filename for the metadata output file (`.tree.meta.json`) of --json-only.
|
||||||
|
Using this option automatically sets :vlopt:`--json-only`.
|
||||||
|
|
||||||
|
.. option:: --json-only-output <filename>
|
||||||
|
|
||||||
|
Specifies the filename for the main output file (`.tree.json`) of --json-only.
|
||||||
|
Using this option automatically sets :vlopt:`--json-only`.
|
||||||
|
|
||||||
|
.. option:: --no-json-edit-nums
|
||||||
|
|
||||||
|
Don't dump edit number in .tree.json files. This may make the file more
|
||||||
|
run-to-run stable for easier comparison.
|
||||||
|
|
||||||
|
.. option:: --no-json-ids
|
||||||
|
|
||||||
|
Don't use short identifiers instead of addresses/paths in .tree.json.
|
||||||
|
|
||||||
.. option:: --l2-name <value>
|
.. option:: --l2-name <value>
|
||||||
|
|
||||||
Instead of using the module name when showing Verilog scope, use the
|
Instead of using the module name when showing Verilog scope, use the
|
||||||
@@ -1107,6 +1152,20 @@ Summary:
|
|||||||
prepended to the name of the :vlopt:`--top` option, or V prepended to
|
prepended to the name of the :vlopt:`--top` option, or V prepended to
|
||||||
the first Verilog filename passed on the command line.
|
the first Verilog filename passed on the command line.
|
||||||
|
|
||||||
|
.. option:: --preproc-resolve
|
||||||
|
|
||||||
|
With :vlopt:`-E`, resolve referenced instance modules, to include
|
||||||
|
preprocessed output of submodules. Used to convert a multi-file design
|
||||||
|
into a single output file.
|
||||||
|
|
||||||
|
See :vlopt:`-E`.
|
||||||
|
|
||||||
|
.. option:: --preproc-token-limit <value>
|
||||||
|
|
||||||
|
Rarely needed. Configure the limit of the number of tokens Verilator
|
||||||
|
can process on a single line to prevent infinite loops and other hangs.
|
||||||
|
Defaults to 40000 tokens.
|
||||||
|
|
||||||
.. option:: --private
|
.. option:: --private
|
||||||
|
|
||||||
Opposite of :vlopt:`--public`. This is the default; this option exists for
|
Opposite of :vlopt:`--public`. This is the default; this option exists for
|
||||||
@@ -1208,6 +1267,13 @@ Summary:
|
|||||||
module specifically enabled it with
|
module specifically enabled it with
|
||||||
:option:`/*verilator&32;inline_module*/`.
|
:option:`/*verilator&32;inline_module*/`.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: --public-depth <level>
|
||||||
|
|
||||||
|
Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules.
|
||||||
|
It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the
|
||||||
|
a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public.
|
||||||
|
|
||||||
.. option:: --public-flat-rw
|
.. option:: --public-flat-rw
|
||||||
|
|
||||||
Declares all variables, ports, and wires public as if they had
|
Declares all variables, ports, and wires public as if they had
|
||||||
@@ -1219,11 +1285,12 @@ Summary:
|
|||||||
marking only those signals that need public_flat_rw is typically
|
marking only those signals that need public_flat_rw is typically
|
||||||
significantly better performing.
|
significantly better performing.
|
||||||
|
|
||||||
.. option:: --public-depth <level>
|
.. option:: --public-ignore
|
||||||
|
|
||||||
Enables public as with :vlopt:`--public-flat-rw`, but only to the specified depth of modules.
|
Ignore all :code:`/*verilator public* */` metacomments. This is useful
|
||||||
It operates at the module maximum level, so if a module's cells are A.B.X and A.X, the
|
for speed-optimizing VPI builds where VPI is not being used. This only
|
||||||
a --public-depth 3 must be used to make module X public, and both A.B.X and A.X will be public.
|
affects metacomments; options such as :vlopt:`--public`,
|
||||||
|
:vlopt:`--public-depth`, etc. work normally.
|
||||||
|
|
||||||
.. option:: --public-params
|
.. option:: --public-params
|
||||||
|
|
||||||
@@ -1231,6 +1298,7 @@ Summary:
|
|||||||
:code:`/*verilator public_flat_rd*/`
|
:code:`/*verilator public_flat_rd*/`
|
||||||
metacomments.
|
metacomments.
|
||||||
|
|
||||||
|
|
||||||
.. option:: -pvalue+<name>=<value>
|
.. option:: -pvalue+<name>=<value>
|
||||||
|
|
||||||
Overwrites the given parameter(s) of the top-level module. See
|
Overwrites the given parameter(s) of the top-level module. See
|
||||||
@@ -1881,38 +1949,6 @@ Summary:
|
|||||||
iterations. This may be another indication of problems with the
|
iterations. This may be another indication of problems with the
|
||||||
modeled design that should be addressed.
|
modeled design that should be addressed.
|
||||||
|
|
||||||
.. option:: --json-only
|
|
||||||
|
|
||||||
Create JSON output only, do not create any other output.
|
|
||||||
|
|
||||||
The JSON format is intended to be used to leverage Verilator's parser and
|
|
||||||
elaboration to feed to other downstream tools. For details on the format, see
|
|
||||||
the Verilator Internals manual. Be aware that the JSON
|
|
||||||
format is still evolving; there will be some changes in future versions.
|
|
||||||
|
|
||||||
This option disables some more aggressive transformations and dumps only
|
|
||||||
the final state of the AST. For more granular and unaltered dumps, meant
|
|
||||||
mainly for debugging see :vlopt:`--dump-tree-json`.
|
|
||||||
|
|
||||||
.. option:: --json-only-meta-output <filename>
|
|
||||||
|
|
||||||
Specifies the filename for the metadata output file (`.tree.meta.json`) of --json-only.
|
|
||||||
Using this option automatically sets :vlopt:`--json-only`.
|
|
||||||
|
|
||||||
.. option:: --json-only-output <filename>
|
|
||||||
|
|
||||||
Specifies the filename for the main output file (`.tree.json`) of --json-only.
|
|
||||||
Using this option automatically sets :vlopt:`--json-only`.
|
|
||||||
|
|
||||||
.. option:: --no-json-edit-nums
|
|
||||||
|
|
||||||
Don't dump edit number in .tree.json files. This may make the file more
|
|
||||||
run-to-run stable for easier comparison.
|
|
||||||
|
|
||||||
.. option:: --no-json-ids
|
|
||||||
|
|
||||||
Don't use short identifiers instead of addresses/paths in .tree.json.
|
|
||||||
|
|
||||||
.. option:: --xml-only
|
.. option:: --xml-only
|
||||||
|
|
||||||
Create XML output only, do not create any other output.
|
Create XML output only, do not create any other output.
|
||||||
@@ -2142,6 +2178,13 @@ The grammar of configuration commands is as follows:
|
|||||||
:option:`/*verilator&32;public_flat*/`, etc., metacomments. See
|
:option:`/*verilator&32;public_flat*/`, etc., metacomments. See
|
||||||
also :ref:`VPI Example`.
|
also :ref:`VPI Example`.
|
||||||
|
|
||||||
|
.. option:: profile_data -hier-dpi "<function_name>" -cost <cost_value>
|
||||||
|
|
||||||
|
Internal profiling data inserted during :vlopt:`--hierarchical`; specifies
|
||||||
|
execution cost of a hierarchical DPI wrappers for modules with
|
||||||
|
:option:`/*verilator&32;hier_block*/` metacomment. See
|
||||||
|
:ref:`Hierarchical Verilation`.
|
||||||
|
|
||||||
.. option:: profile_data -mtask "<mtask_hash>" -cost <cost_value>
|
.. option:: profile_data -mtask "<mtask_hash>" -cost <cost_value>
|
||||||
|
|
||||||
Feeds profile-guided optimization data into the Verilator algorithms in
|
Feeds profile-guided optimization data into the Verilator algorithms in
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ to read multiple inputs. If no data file is specified, by default,
|
|||||||
Specifies the directory name to which source files with annotated coverage
|
Specifies the directory name to which source files with annotated coverage
|
||||||
data should be written.
|
data should be written.
|
||||||
|
|
||||||
Points are children of each line coverage- branches or toggle points.
|
Points are children of each line coverage- branches, expressions or toggle points.
|
||||||
When point counts are aggregated into a line, the minimum and maximum counts
|
When point counts are aggregated into a line, the minimum and maximum counts
|
||||||
are used to determine the status of the line (complete, partial, failing)
|
are used to determine the status of the line (complete, partial, failing)
|
||||||
The count is equal to the maximum of the points.
|
The count is equal to the maximum of the points.
|
||||||
|
|||||||
@@ -270,6 +270,42 @@ A :option:`/*verilator&32;coverage_off*/`
|
|||||||
signals that do not need toggle analysis, such as RAMs and register files.
|
signals that do not need toggle analysis, such as RAMs and register files.
|
||||||
|
|
||||||
|
|
||||||
|
.. _Expression Coverage:
|
||||||
|
|
||||||
|
Expression Coverage
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
With :vlopt:`--coverage` or :vlopt:`--coverage-expr`, Verilator will
|
||||||
|
automatically add coverage analysis at each expression, indicating with a
|
||||||
|
truth table how every Boolean truth-table possibility in the expression
|
||||||
|
occurred.
|
||||||
|
|
||||||
|
Multi-bit expressions are ignored, but sub-expressions with are entirely
|
||||||
|
Boolean are analyzed. Expression coverage does not fully explore the truth
|
||||||
|
table of an expression, rather is looks at each term's contribution. E.g.
|
||||||
|
an AND operation will check coverage for TT, XF and FX.
|
||||||
|
|
||||||
|
Some expressions may produce too many cover points. Verilator limits the
|
||||||
|
maximum number of cover points per expression to 32, but this may be
|
||||||
|
controlled with :vlopt:`--coverage-expr-max`.
|
||||||
|
|
||||||
|
Below is an example showing expression coverage produced from `verilator_coverage`
|
||||||
|
as applied to the condition expression inside an if statement. Each line
|
||||||
|
shows the minimum number of terms and their values (e.g. `(t1==0 && t2==1)`) needed
|
||||||
|
to reach a result for the overall expression (e.g. `=> 1`). Each line also
|
||||||
|
shows the number of times this combination was hit. Note that individual lines
|
||||||
|
are not mutually exclusive.
|
||||||
|
|
||||||
|
.. code-block::
|
||||||
|
|
||||||
|
%000004 if ((~t1 && t2) || (~t3 && t4)) $write("");
|
||||||
|
-000002 point: comment=(t1==0 && t2==1) => 1 hier=top.t
|
||||||
|
-000002 point: comment=(t1==1 && t3==1) => 0 hier=top.t
|
||||||
|
-000004 point: comment=(t1==1 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t2==0 && t3==1) => 0 hier=top.t
|
||||||
|
-000003 point: comment=(t2==0 && t4==0) => 0 hier=top.t
|
||||||
|
-000002 point: comment=(t3==0 && t4==1) => 1 hier=top.t
|
||||||
|
|
||||||
.. _Suppressing Coverage:
|
.. _Suppressing Coverage:
|
||||||
|
|
||||||
Suppressing Coverage
|
Suppressing Coverage
|
||||||
|
|||||||
+15
-3
@@ -44,7 +44,7 @@ Warnings may be disabled in multiple ways:
|
|||||||
|
|
||||||
.. code-block:: sv
|
.. code-block:: sv
|
||||||
|
|
||||||
lint_off -rule UNSIGNED -file "*/example.v" -line 1
|
lint_off -rule UNSIGNED -file "*/example.v" -lines 1
|
||||||
|
|
||||||
|
|
||||||
Error And Warning Format
|
Error And Warning Format
|
||||||
@@ -445,6 +445,18 @@ List Of Warnings
|
|||||||
correctly.
|
correctly.
|
||||||
|
|
||||||
|
|
||||||
|
.. option:: COVERIGN
|
||||||
|
|
||||||
|
Warns that Verilator does not support certain forms of
|
||||||
|
:code:`covergroup`, :code:`coverpoint`, and coverage options, and the
|
||||||
|
construct was are ignored.
|
||||||
|
|
||||||
|
Disabling the :option:`UNSUPPORTED` error also disables this warning.
|
||||||
|
|
||||||
|
Ignoring this warning may make Verilator ignore lint checking on the
|
||||||
|
construct, and collect coverage data differently from other simulators.
|
||||||
|
|
||||||
|
|
||||||
.. option:: DECLFILENAME
|
.. option:: DECLFILENAME
|
||||||
|
|
||||||
.. TODO better example
|
.. TODO better example
|
||||||
@@ -2009,12 +2021,12 @@ List Of Warnings
|
|||||||
|
|
||||||
.. code-block:: sv
|
.. code-block:: sv
|
||||||
|
|
||||||
wire _unused_ok = &{1'b0,
|
wire _unused_ok = 1'b0 && &{1'b0,
|
||||||
sig_not_used_a,
|
sig_not_used_a,
|
||||||
sig_not_used_yet_b, // To be fixed
|
sig_not_used_yet_b, // To be fixed
|
||||||
1'b0};
|
1'b0};
|
||||||
|
|
||||||
The reduction AND and constant zeros mean the net will always be zero,
|
The AND with constant zero mean the net will always be zero,
|
||||||
so won't use simulation runtime. The redundant leading and trailing
|
so won't use simulation runtime. The redundant leading and trailing
|
||||||
zeros avoid syntax errors if there are no signals between them. The
|
zeros avoid syntax errors if there are no signals between them. The
|
||||||
magic name "unused" (controlled by the :vlopt:`--unused-regexp` option)
|
magic name "unused" (controlled by the :vlopt:`--unused-regexp` option)
|
||||||
|
|||||||
@@ -104,6 +104,7 @@ Eiler
|
|||||||
Eivind
|
Eivind
|
||||||
El
|
El
|
||||||
Elbourne
|
Elbourne
|
||||||
|
Elzeftawi
|
||||||
Embecosm
|
Embecosm
|
||||||
Engstrom
|
Engstrom
|
||||||
Enzo
|
Enzo
|
||||||
@@ -362,6 +363,7 @@ Sanguinetti
|
|||||||
Sanjay
|
Sanjay
|
||||||
Sasselli
|
Sasselli
|
||||||
Scharrer
|
Scharrer
|
||||||
|
Schless
|
||||||
Seitz
|
Seitz
|
||||||
Shahid
|
Shahid
|
||||||
Shahrestani
|
Shahrestani
|
||||||
@@ -901,6 +903,7 @@ predefines
|
|||||||
prepareClone
|
prepareClone
|
||||||
prepend
|
prepend
|
||||||
prepended
|
prepended
|
||||||
|
preproc
|
||||||
preprocess
|
preprocess
|
||||||
preprocessed
|
preprocessed
|
||||||
preprocessing
|
preprocessing
|
||||||
|
|||||||
@@ -3910,7 +3910,7 @@ char *pnt = buf;
|
|||||||
int len = 0;
|
int len = 0;
|
||||||
|
|
||||||
/* zero is illegal for a value...it is assumed they start at one */
|
/* zero is illegal for a value...it is assumed they start at one */
|
||||||
while (value && len <= 14)
|
while (value && len < 14)
|
||||||
{
|
{
|
||||||
value--;
|
value--;
|
||||||
++len;
|
++len;
|
||||||
|
|||||||
+17
-19
@@ -1898,7 +1898,7 @@ std::string VL_TO_STRING(CData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 8, lhs
|
|||||||
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 16, lhs); }
|
std::string VL_TO_STRING(SData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 16, lhs); }
|
||||||
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 32, lhs); }
|
std::string VL_TO_STRING(IData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 32, lhs); }
|
||||||
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 64, lhs); }
|
std::string VL_TO_STRING(QData lhs) { return VL_SFORMATF_N_NX("'h%0x", 0, 64, lhs); }
|
||||||
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_N_NX("%d", 0, 64, lhs); }
|
std::string VL_TO_STRING(double lhs) { return VL_SFORMATF_N_NX("%g", 0, 64, lhs); }
|
||||||
std::string VL_TO_STRING_W(int words, const WDataInP obj) {
|
std::string VL_TO_STRING_W(int words, const WDataInP obj) {
|
||||||
return VL_SFORMATF_N_NX("'h%0x", 0, words * VL_EDATASIZE, obj);
|
return VL_SFORMATF_N_NX("'h%0x", 0, words * VL_EDATASIZE, obj);
|
||||||
}
|
}
|
||||||
@@ -3289,7 +3289,7 @@ uint32_t VerilatedVarProps::entSize() const VL_MT_SAFE {
|
|||||||
case VLVT_UINT16: size = sizeof(SData); break;
|
case VLVT_UINT16: size = sizeof(SData); break;
|
||||||
case VLVT_UINT32: size = sizeof(IData); break;
|
case VLVT_UINT32: size = sizeof(IData); break;
|
||||||
case VLVT_UINT64: size = sizeof(QData); break;
|
case VLVT_UINT64: size = sizeof(QData); break;
|
||||||
case VLVT_WDATA: size = VL_WORDS_I(packed().elements()) * sizeof(IData); break;
|
case VLVT_WDATA: size = VL_WORDS_I(entBits()) * sizeof(IData); break;
|
||||||
default: size = 0; break; // LCOV_EXCL_LINE
|
default: size = 0; break; // LCOV_EXCL_LINE
|
||||||
}
|
}
|
||||||
return size;
|
return size;
|
||||||
@@ -3308,7 +3308,7 @@ void* VerilatedVarProps::datapAdjustIndex(void* datap, int dim, int indx) const
|
|||||||
uint8_t* bytep = reinterpret_cast<uint8_t*>(datap);
|
uint8_t* bytep = reinterpret_cast<uint8_t*>(datap);
|
||||||
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
|
// If on index 1 of a 2 index array, then each index 1 is index2sz*entsz
|
||||||
size_t slicesz = entSize();
|
size_t slicesz = entSize();
|
||||||
for (int d = dim + 1; d <= m_udims; ++d) slicesz *= elements(d);
|
for (int d = dim + 1; d <= udims(); ++d) slicesz *= elements(d);
|
||||||
bytep += indxAdj * slicesz;
|
bytep += indxAdj * slicesz;
|
||||||
return bytep;
|
return bytep;
|
||||||
}
|
}
|
||||||
@@ -3369,32 +3369,30 @@ void VerilatedScope::exportInsert(int finalize, const char* namep, void* cb) VL_
|
|||||||
}
|
}
|
||||||
|
|
||||||
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
void VerilatedScope::varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE {
|
VerilatedVarType vltype, int vlflags, int udims,
|
||||||
|
int pdims...) VL_MT_UNSAFE {
|
||||||
// Grab dimensions
|
// Grab dimensions
|
||||||
// In the future we may just create a large table at emit time and
|
// In the future we may just create a large table at emit time and
|
||||||
// statically construct from that.
|
// statically construct from that.
|
||||||
if (!finalize) return;
|
if (!finalize) return;
|
||||||
|
|
||||||
if (!m_varsp) m_varsp = new VerilatedVarNameMap;
|
if (!m_varsp) m_varsp = new VerilatedVarNameMap;
|
||||||
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), dims, isParam);
|
VerilatedVar var(namep, datap, vltype, static_cast<VerilatedVarFlags>(vlflags), udims, pdims,
|
||||||
|
isParam);
|
||||||
|
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, dims);
|
va_start(ap, pdims);
|
||||||
for (int i = 0; i < dims; ++i) {
|
for (int i = 0; i < udims; ++i) {
|
||||||
const int msb = va_arg(ap, int);
|
const int msb = va_arg(ap, int);
|
||||||
const int lsb = va_arg(ap, int);
|
const int lsb = va_arg(ap, int);
|
||||||
if (i == 0) {
|
var.m_unpacked[i].m_left = msb;
|
||||||
var.m_packed.m_left = msb;
|
var.m_unpacked[i].m_right = lsb;
|
||||||
var.m_packed.m_right = lsb;
|
}
|
||||||
} else if (i >= 1 && i <= var.udims()) {
|
for (int i = 0; i < pdims; ++i) {
|
||||||
var.m_unpacked[i - 1].m_left = msb;
|
const int msb = va_arg(ap, int);
|
||||||
var.m_unpacked[i - 1].m_right = lsb;
|
const int lsb = va_arg(ap, int);
|
||||||
} else {
|
var.m_packed[i].m_left = msb;
|
||||||
// We could have a linked list of ranges, but really this whole thing needs
|
var.m_packed[i].m_right = lsb;
|
||||||
// to be generalized to support structs and unions, etc.
|
|
||||||
const std::string msg = "Unsupported multi-dimensional public varInsert: "s + namep;
|
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "", msg.c_str());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
va_end(ap);
|
va_end(ap);
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -175,6 +175,9 @@ enum class VerilatedAssertDirectiveType : uint8_t {
|
|||||||
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
using VerilatedAssertType_t = std::underlying_type<VerilatedAssertType>::type;
|
||||||
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
using VerilatedAssertDirectiveType_t = std::underlying_type<VerilatedAssertDirectiveType>::type;
|
||||||
|
|
||||||
|
// Type trait for custom struct
|
||||||
|
template <typename>
|
||||||
|
struct VlIsCustomStruct : public std::false_type {};
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// Utility functions
|
// Utility functions
|
||||||
|
|
||||||
@@ -726,7 +729,7 @@ public: // But internals only - called from VerilatedModule's
|
|||||||
const Type& type) VL_MT_UNSAFE;
|
const Type& type) VL_MT_UNSAFE;
|
||||||
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
void exportInsert(int finalize, const char* namep, void* cb) VL_MT_UNSAFE;
|
||||||
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
void varInsert(int finalize, const char* namep, void* datap, bool isParam,
|
||||||
VerilatedVarType vltype, int vlflags, int dims, ...) VL_MT_UNSAFE;
|
VerilatedVarType vltype, int vlflags, int udims, int pdims, ...) VL_MT_UNSAFE;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
const char* name() const VL_MT_SAFE_POSTINIT { return m_namep; }
|
||||||
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
const char* identifier() const VL_MT_SAFE_POSTINIT { return m_identifierp; }
|
||||||
|
|||||||
@@ -289,7 +289,7 @@ static void _vl_svGetBitArrElemVecVal(svBitVecVal* d, const svOpenArrayHandle s,
|
|||||||
}
|
}
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) d[i] = wdatap[i];
|
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) d[i] = wdatap[i];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default: // LCOV_EXCL_START // Errored earlier
|
default: // LCOV_EXCL_START // Errored earlier
|
||||||
@@ -328,7 +328,7 @@ static void _vl_svGetLogicArrElemVecVal(svLogicVecVal* d, const svOpenArrayHandl
|
|||||||
}
|
}
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) {
|
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) {
|
||||||
d[i].aval = wdatap[i];
|
d[i].aval = wdatap[i];
|
||||||
d[i].bval = 0;
|
d[i].bval = 0;
|
||||||
}
|
}
|
||||||
@@ -354,7 +354,7 @@ static void _vl_svPutBitArrElemVecVal(const svOpenArrayHandle d, const svBitVecV
|
|||||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1], s[0]); break;
|
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1], s[0]); break;
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i];
|
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) wdatap[i] = s[i];
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default: // LCOV_EXCL_START // Errored earlier
|
default: // LCOV_EXCL_START // Errored earlier
|
||||||
@@ -376,7 +376,7 @@ static void _vl_svPutLogicArrElemVecVal(const svOpenArrayHandle d, const svLogic
|
|||||||
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1].aval, s[0].aval); break;
|
case VLVT_UINT64: *(reinterpret_cast<QData*>(datap)) = VL_SET_QII(s[1].aval, s[0].aval); break;
|
||||||
case VLVT_WDATA: {
|
case VLVT_WDATA: {
|
||||||
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
WDataOutP wdatap = (reinterpret_cast<WDataOutP>(datap));
|
||||||
for (int i = 0; i < VL_WORDS_I(varp->packed().elements()); ++i) wdatap[i] = s[i].aval;
|
for (int i = 0; i < VL_WORDS_I(varp->entBits()); ++i) wdatap[i] = s[i].aval;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default: // LCOV_EXCL_START // Errored earlier
|
default: // LCOV_EXCL_START // Errored earlier
|
||||||
|
|||||||
@@ -282,6 +282,7 @@ std::string parseNestedSelect(const std::string& nested_select_expr,
|
|||||||
indices.push_back(idx);
|
indices.push_back(idx);
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// VlRandomizer:: Methods
|
// VlRandomizer:: Methods
|
||||||
|
|
||||||
@@ -467,17 +468,27 @@ bool VlRandomizer::parseSolution(std::iostream& f) {
|
|||||||
"hex_index contains invalid format");
|
"hex_index contains invalid format");
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const long long index = std::stoll(hex_index.substr(start + 2), nullptr, 16);
|
std::string trimmed_hex = hex_index.substr(start + 2);
|
||||||
oss << "[" << index << "]";
|
|
||||||
|
if (trimmed_hex.size() <= 8) { // Small numbers: <= 32 bits
|
||||||
|
// Convert to decimal and output directly
|
||||||
|
oss << "[" << std::to_string(std::stoll(trimmed_hex, nullptr, 16)) << "]";
|
||||||
|
} else { // Large numbers: > 32 bits
|
||||||
|
// Trim leading zeros and handle empty case
|
||||||
|
trimmed_hex.erase(0, trimmed_hex.find_first_not_of('0'));
|
||||||
|
oss << "[" << (trimmed_hex.empty() ? "0" : trimmed_hex) << "]";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
const std::string indexed_name = oss.str();
|
const std::string indexed_name = oss.str();
|
||||||
const auto it = std::find_if(m_arr_vars.begin(), m_arr_vars.end(),
|
|
||||||
[&indexed_name](const auto& entry) {
|
const auto iti = std::find_if(m_arr_vars.begin(), m_arr_vars.end(),
|
||||||
return entry.second->m_name == indexed_name;
|
[&indexed_name](const auto& entry) {
|
||||||
});
|
return entry.second->m_name == indexed_name;
|
||||||
if (it != m_arr_vars.end()) {
|
});
|
||||||
|
if (iti != m_arr_vars.end()) {
|
||||||
std::ostringstream ss;
|
std::ostringstream ss;
|
||||||
ss << "#x" << std::hex << std::setw(8) << std::setfill('0') << it->second->m_index;
|
ss << "#x" << std::hex << std::setw(8) << std::setfill('0')
|
||||||
|
<< iti->second->m_index;
|
||||||
idx = ss.str();
|
idx = ss.str();
|
||||||
} else {
|
} else {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||||
@@ -498,7 +509,7 @@ void VlRandomizer::clear() { m_constraints.clear(); }
|
|||||||
#ifdef VL_DEBUG
|
#ifdef VL_DEBUG
|
||||||
void VlRandomizer::dump() const {
|
void VlRandomizer::dump() const {
|
||||||
for (const auto& var : m_vars) {
|
for (const auto& var : m_vars) {
|
||||||
VL_PRINTF("Variable (%d): %s\n", var.second->width(), var.second->name());
|
VL_PRINTF("Variable (%d): %s\n", var.second->width(), var.second->name().c_str());
|
||||||
}
|
}
|
||||||
for (const std::string& c : m_constraints) VL_PRINTF("Constraint: %s\n", c.c_str());
|
for (const std::string& c : m_constraints) VL_PRINTF("Constraint: %s\n", c.c_str());
|
||||||
}
|
}
|
||||||
|
|||||||
+136
-51
@@ -27,8 +27,10 @@
|
|||||||
|
|
||||||
#include "verilated.h"
|
#include "verilated.h"
|
||||||
|
|
||||||
|
#include <iomanip>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <ostream>
|
#include <ostream>
|
||||||
|
#include <sstream>
|
||||||
|
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
// VlRandomExpr and subclasses represent expressions for the constraint solver.
|
||||||
@@ -38,10 +40,10 @@ public:
|
|||||||
m_name; // Name of the array variable, including index notation (e.g., arr[2][1])
|
m_name; // Name of the array variable, including index notation (e.g., arr[2][1])
|
||||||
void* const m_datap; // Reference to the array variable data
|
void* const m_datap; // Reference to the array variable data
|
||||||
const int m_index; // Flattened (1D) index of the array element
|
const int m_index; // Flattened (1D) index of the array element
|
||||||
const std::vector<size_t> m_indices; // Multi-dimensional indices of the array element
|
const std::vector<IData> m_indices; // Multi-dimensional indices of the array element
|
||||||
const std::vector<size_t> m_idxWidths; // Multi-dimensional indices' bit widths
|
const std::vector<size_t> m_idxWidths; // Multi-dimensional indices' bit widths
|
||||||
|
|
||||||
ArrayInfo(const std::string& name, void* datap, int index, const std::vector<size_t>& indices,
|
ArrayInfo(const std::string& name, void* datap, int index, const std::vector<IData>& indices,
|
||||||
const std::vector<size_t>& idxWidths)
|
const std::vector<size_t>& idxWidths)
|
||||||
: m_name(name)
|
: m_name(name)
|
||||||
, m_datap(datap)
|
, m_datap(datap)
|
||||||
@@ -52,21 +54,22 @@ public:
|
|||||||
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
using ArrayInfoMap = std::map<std::string, std::shared_ptr<const ArrayInfo>>;
|
||||||
|
|
||||||
class VlRandomVar VL_NOT_FINAL {
|
class VlRandomVar VL_NOT_FINAL {
|
||||||
const char* const m_name; // Variable name
|
std::string m_name; // Variable name
|
||||||
void* const m_datap; // Reference to variable data
|
void* const m_datap; // Reference to variable data
|
||||||
const int m_width; // Variable width in bits
|
const int m_width; // Variable width in bits
|
||||||
const int m_dimension; //Variable dimension, default is 0
|
const int m_dimension; //Variable dimension, default is 0
|
||||||
const std::uint32_t m_randModeIdx; // rand_mode index
|
const std::uint32_t m_randModeIdx; // rand_mode index
|
||||||
|
|
||||||
public:
|
public:
|
||||||
VlRandomVar(const char* name, int width, void* datap, int dimension, std::uint32_t randModeIdx)
|
VlRandomVar(const std::string& name, int width, void* datap, int dimension,
|
||||||
|
std::uint32_t randModeIdx)
|
||||||
: m_name{name}
|
: m_name{name}
|
||||||
, m_datap{datap}
|
, m_datap{datap}
|
||||||
, m_width{width}
|
, m_width{width}
|
||||||
, m_dimension{dimension}
|
, m_dimension{dimension}
|
||||||
, m_randModeIdx{randModeIdx} {}
|
, m_randModeIdx{randModeIdx} {}
|
||||||
virtual ~VlRandomVar() = default;
|
virtual ~VlRandomVar() = default;
|
||||||
const char* name() const { return m_name; }
|
std::string name() const { return m_name; }
|
||||||
int width() const { return m_width; }
|
int width() const { return m_width; }
|
||||||
int dimension() const { return m_dimension; }
|
int dimension() const { return m_dimension; }
|
||||||
virtual void* datap(int idx) const { return m_datap; }
|
virtual void* datap(int idx) const { return m_datap; }
|
||||||
@@ -97,7 +100,7 @@ public:
|
|||||||
template <typename T>
|
template <typename T>
|
||||||
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
class VlRandomArrayVarTemplate final : public VlRandomVar {
|
||||||
public:
|
public:
|
||||||
VlRandomArrayVarTemplate(const char* name, int width, void* datap, int dimension,
|
VlRandomArrayVarTemplate(const std::string& name, int width, void* datap, int dimension,
|
||||||
std::uint32_t randModeIdx)
|
std::uint32_t randModeIdx)
|
||||||
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
: VlRandomVar{name, width, datap, dimension, randModeIdx} {}
|
||||||
void* datap(int idx) const override {
|
void* datap(int idx) const override {
|
||||||
@@ -110,16 +113,31 @@ public:
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void emitSelect(std::ostream& s, const std::vector<size_t>& indices,
|
void emitHexs(std::ostream& s, const std::vector<IData>& indices, const size_t bit_width,
|
||||||
|
size_t idx) const {
|
||||||
|
for (int j = bit_width - 4; j >= 0; j -= 4) {
|
||||||
|
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void emitSelect(std::ostream& s, const std::vector<IData>& indices,
|
||||||
const std::vector<size_t>& idxWidths) const {
|
const std::vector<size_t>& idxWidths) const {
|
||||||
for (size_t idx = 0; idx < indices.size(); ++idx) s << "(select ";
|
const size_t num_indices = idxWidths.size();
|
||||||
|
size_t wide_size = 0;
|
||||||
|
|
||||||
|
for (size_t idx = 0; idx < num_indices; ++idx) s << "(select ";
|
||||||
s << name();
|
s << name();
|
||||||
for (size_t idx = 0; idx < indices.size(); ++idx) {
|
|
||||||
s << " #x";
|
for (size_t idx = 0; idx < num_indices; ++idx) {
|
||||||
const size_t bit_width = idxWidths[idx];
|
const size_t bit_width = idxWidths[idx];
|
||||||
for (int j = bit_width - 4; j >= 0; j -= 4) {
|
s << " #x";
|
||||||
s << "0123456789abcdef"[(indices[idx] >> j) & 0xf];
|
|
||||||
|
const size_t emit_count = (bit_width > 32) ? (idxWidths[idx] / 32) : 1;
|
||||||
|
|
||||||
|
for (size_t i = 0; i < emit_count; ++i) {
|
||||||
|
emitHexs(s, indices, (bit_width > 32) ? 32 : bit_width, wide_size + i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
wide_size += (idxWidths[idx] > 32) ? (idxWidths[idx] / 32) : 1;
|
||||||
s << ")";
|
s << ")";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,7 +147,7 @@ public:
|
|||||||
const std::string indexed_name = name() + std::to_string(i);
|
const std::string indexed_name = name() + std::to_string(i);
|
||||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||||
if (it != m_arrVarsRefp->end()) {
|
if (it != m_arrVarsRefp->end()) {
|
||||||
const std::vector<size_t>& indices = it->second->m_indices;
|
const std::vector<IData>& indices = it->second->m_indices;
|
||||||
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
||||||
emitSelect(s, indices, idxWidths);
|
emitSelect(s, indices, idxWidths);
|
||||||
} else {
|
} else {
|
||||||
@@ -165,7 +183,7 @@ public:
|
|||||||
const std::string indexed_name = name() + std::to_string(j);
|
const std::string indexed_name = name() + std::to_string(j);
|
||||||
const auto it = m_arrVarsRefp->find(indexed_name);
|
const auto it = m_arrVarsRefp->find(indexed_name);
|
||||||
if (it != m_arrVarsRefp->end()) {
|
if (it != m_arrVarsRefp->end()) {
|
||||||
const std::vector<size_t>& indices = it->second->m_indices;
|
const std::vector<IData>& indices = it->second->m_indices;
|
||||||
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
const std::vector<size_t>& idxWidths = it->second->m_idxWidths;
|
||||||
emitSelect(s, indices, idxWidths);
|
emitSelect(s, indices, idxWidths);
|
||||||
} else {
|
} else {
|
||||||
@@ -176,7 +194,6 @@ public:
|
|||||||
};
|
};
|
||||||
//=============================================================================
|
//=============================================================================
|
||||||
// VlRandomizer is the object holding constraints and variable references.
|
// VlRandomizer is the object holding constraints and variable references.
|
||||||
|
|
||||||
class VlRandomizer final {
|
class VlRandomizer final {
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
std::vector<std::string> m_constraints; // Solver-dependent constraints
|
std::vector<std::string> m_constraints; // Solver-dependent constraints
|
||||||
@@ -200,48 +217,93 @@ public:
|
|||||||
bool next(VlRNG& rngr);
|
bool next(VlRNG& rngr);
|
||||||
|
|
||||||
template <typename T_Key>
|
template <typename T_Key>
|
||||||
typename std::enable_if<std::is_integral<T_Key>::value>::type
|
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) <= 4)>::type
|
||||||
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index,
|
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
|
||||||
const std::string& base_name, size_t& idx_width) {
|
const std::string& base_name, size_t& idx_width) {
|
||||||
integral_index = static_cast<size_t>(key);
|
integral_index.push_back(static_cast<size_t>(key));
|
||||||
indexed_name = base_name + "[" + std::to_string(integral_index) + "]";
|
indexed_name
|
||||||
|
= base_name + "[" + std::to_string(integral_index[integral_index.size() - 1]) + "]";
|
||||||
idx_width = sizeof(T_Key) * 8;
|
idx_width = sizeof(T_Key) * 8;
|
||||||
}
|
}
|
||||||
template <typename T_Key>
|
template <typename T_Key>
|
||||||
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type
|
typename std::enable_if<std::is_integral<T_Key>::value && (sizeof(T_Key) > 4)>::type
|
||||||
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index,
|
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
|
||||||
const std::string& base_name, size_t& idx_width) {
|
const std::string& base_name, size_t& idx_width) {
|
||||||
integral_index = string_to_integral(key);
|
constexpr size_t segment_bits = 32;
|
||||||
indexed_name = base_name + "[" + std::to_string(integral_index) + "]";
|
constexpr T_Key mask = (static_cast<T_Key>(1) << segment_bits) - 1;
|
||||||
idx_width = 64; // 64-bit mask
|
integral_index.push_back(static_cast<size_t>(key >> segment_bits));
|
||||||
|
integral_index.push_back(static_cast<size_t>(key & mask));
|
||||||
|
|
||||||
|
std::ostringstream hex_stream;
|
||||||
|
hex_stream << std::hex << key;
|
||||||
|
std::string index_string = hex_stream.str();
|
||||||
|
index_string.erase(0, index_string.find_first_not_of('0'));
|
||||||
|
index_string = index_string.empty() ? "0" : index_string;
|
||||||
|
|
||||||
|
indexed_name = base_name + "[" + index_string + "]";
|
||||||
|
|
||||||
|
idx_width = sizeof(T_Key) * 8;
|
||||||
|
}
|
||||||
|
template <typename T_Key>
|
||||||
|
typename std::enable_if<VlIsVlWide<T_Key>::value>::type
|
||||||
|
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
|
||||||
|
const std::string& base_name, size_t& idx_width) {
|
||||||
|
std::ostringstream hex_stream;
|
||||||
|
for (size_t i = key.size(); i > 0; --i) {
|
||||||
|
const size_t segment_value = key.at(i - 1);
|
||||||
|
hex_stream << std::hex << segment_value;
|
||||||
|
integral_index.push_back(segment_value);
|
||||||
|
}
|
||||||
|
std::string index_string = hex_stream.str();
|
||||||
|
index_string.erase(0, index_string.find_first_not_of('0'));
|
||||||
|
index_string = index_string.empty() ? "0" : index_string;
|
||||||
|
|
||||||
|
indexed_name = base_name + "[" + index_string + "]";
|
||||||
|
idx_width = key.size() * 32;
|
||||||
|
}
|
||||||
|
template <typename T_Key>
|
||||||
|
typename std::enable_if<std::is_same<T_Key, std::string>::value>::type
|
||||||
|
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
|
||||||
|
const std::string& base_name, size_t& idx_width) {
|
||||||
|
// Convert the input string to its ASCII hexadecimal representation
|
||||||
|
std::ostringstream oss;
|
||||||
|
for (unsigned char c : key) {
|
||||||
|
oss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(c);
|
||||||
|
}
|
||||||
|
std::string hex_str = oss.str();
|
||||||
|
// Ensure the hex string is exactly 128 bits (32 hex characters)
|
||||||
|
hex_str = hex_str.size() > 32 ? hex_str.substr(0, 32)
|
||||||
|
: std::string(32 - hex_str.size(), '0') + hex_str;
|
||||||
|
|
||||||
|
// Split the hex string into 4 segments (32-bit per segment)
|
||||||
|
integral_index.clear();
|
||||||
|
for (size_t i = 0; i < hex_str.size(); i += 8) {
|
||||||
|
integral_index.push_back(std::stoul(hex_str.substr(i, 8), nullptr, 16));
|
||||||
|
}
|
||||||
|
|
||||||
|
indexed_name = base_name + "["
|
||||||
|
+ (hex_str.find_first_not_of('0') == std::string::npos
|
||||||
|
? "0"
|
||||||
|
: hex_str.substr(hex_str.find_first_not_of('0')))
|
||||||
|
+ "]";
|
||||||
|
|
||||||
|
idx_width = 128;
|
||||||
}
|
}
|
||||||
template <typename T_Key>
|
template <typename T_Key>
|
||||||
typename std::enable_if<!std::is_integral<T_Key>::value
|
typename std::enable_if<!std::is_integral<T_Key>::value
|
||||||
&& !std::is_same<T_Key, std::string>::value>::type
|
&& !std::is_same<T_Key, std::string>::value
|
||||||
process_key(const T_Key& key, std::string& indexed_name, size_t& integral_index,
|
&& !VlIsVlWide<T_Key>::value>::type
|
||||||
|
process_key(const T_Key& key, std::string& indexed_name, std::vector<size_t>& integral_index,
|
||||||
const std::string& base_name, size_t& idx_width) {
|
const std::string& base_name, size_t& idx_width) {
|
||||||
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
VL_FATAL_MT(__FILE__, __LINE__, "randomize",
|
||||||
"Unsupported: Only integral and string index of associative array is "
|
"Unsupported: Only integral and string index of associative array is "
|
||||||
"supported currently.");
|
"supported currently.");
|
||||||
}
|
}
|
||||||
|
|
||||||
uint64_t string_to_integral(const std::string& str) {
|
|
||||||
uint64_t result = 0;
|
|
||||||
for (char c : str) { result = (result << 8) | static_cast<uint64_t>(c); }
|
|
||||||
|
|
||||||
#ifdef VL_DEBUG
|
|
||||||
if (seen_values.count(result) > 0 && seen_values[result] != str)
|
|
||||||
VL_WARN_MT(__FILE__, __LINE__, "randomize",
|
|
||||||
"Conflict detected: Different strings mapped to the same 64-bit index.");
|
|
||||||
seen_values[result] = str;
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void write_var(T& var, int width, const char* name, int dimension,
|
typename std::enable_if<!VlIsCustomStruct<T>::value, void>::type
|
||||||
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
write_var(T& var, int width, const char* name, int dimension,
|
||||||
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
if (m_vars.find(name) != m_vars.end()) return;
|
if (m_vars.find(name) != m_vars.end()) return;
|
||||||
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
// TODO: make_unique once VlRandomizer is per-instance not per-ref
|
||||||
m_vars[name]
|
m_vars[name]
|
||||||
@@ -281,6 +343,21 @@ public:
|
|||||||
record_arr_table(var, name, dimension, {}, {});
|
record_arr_table(var, name, dimension, {}, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
template <typename T, std::size_t... I>
|
||||||
|
void modifyMembers(T& obj, std::index_sequence<I...>, std::string baseName) {
|
||||||
|
// Use the indices to access each member via std::get
|
||||||
|
(void)std::initializer_list<int>{
|
||||||
|
(write_var(std::get<I>(obj.getMembers(obj)), obj.memberWidth()[I],
|
||||||
|
(baseName + "." + obj.memberNames()[I]).c_str(), obj.memberDimension()[I]),
|
||||||
|
0)...};
|
||||||
|
}
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
typename std::enable_if<VlIsCustomStruct<T>::value, void>::type
|
||||||
|
write_var(T& var, int width, const char* name, int dimension,
|
||||||
|
std::uint32_t randmodeIdx = std::numeric_limits<std::uint32_t>::max()) {
|
||||||
|
modifyMembers(var, var.memberIndices(), name);
|
||||||
|
}
|
||||||
|
|
||||||
int idx;
|
int idx;
|
||||||
std::string generateKey(const std::string& name, int idx) {
|
std::string generateKey(const std::string& name, int idx) {
|
||||||
@@ -295,15 +372,16 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void record_arr_table(T& var, const std::string name, int dimension,
|
typename std::enable_if<!std::is_class<T>::value, void>::type
|
||||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
record_arr_table(T& var, const std::string name, int dimension, std::vector<IData> indices,
|
||||||
|
std::vector<size_t> idxWidths) {
|
||||||
const std::string key = generateKey(name, idx);
|
const std::string key = generateKey(name, idx);
|
||||||
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
|
m_arr_vars[key] = std::make_shared<ArrayInfo>(name, &var, idx, indices, idxWidths);
|
||||||
++idx;
|
++idx;
|
||||||
}
|
}
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
|
void record_arr_table(VlQueue<T>& var, const std::string name, int dimension,
|
||||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||||
if ((dimension > 0) && (var.size() != 0)) {
|
if ((dimension > 0) && (var.size() != 0)) {
|
||||||
idxWidths.push_back(32);
|
idxWidths.push_back(32);
|
||||||
for (size_t i = 0; i < var.size(); ++i) {
|
for (size_t i = 0; i < var.size(); ++i) {
|
||||||
@@ -316,7 +394,7 @@ public:
|
|||||||
}
|
}
|
||||||
template <typename T, std::size_t N_Depth>
|
template <typename T, std::size_t N_Depth>
|
||||||
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
|
void record_arr_table(VlUnpacked<T, N_Depth>& var, const std::string name, int dimension,
|
||||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||||
if ((dimension > 0) && (N_Depth != 0)) {
|
if ((dimension > 0) && (N_Depth != 0)) {
|
||||||
idxWidths.push_back(32);
|
idxWidths.push_back(32);
|
||||||
for (size_t i = 0; i < N_Depth; ++i) {
|
for (size_t i = 0; i < N_Depth; ++i) {
|
||||||
@@ -330,20 +408,27 @@ public:
|
|||||||
}
|
}
|
||||||
template <typename T_Key, typename T_Value>
|
template <typename T_Key, typename T_Value>
|
||||||
void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension,
|
void record_arr_table(VlAssocArray<T_Key, T_Value>& var, const std::string name, int dimension,
|
||||||
std::vector<size_t> indices, std::vector<size_t> idxWidths) {
|
std::vector<IData> indices, std::vector<size_t> idxWidths) {
|
||||||
if ((dimension > 0) && (var.size() != 0)) {
|
if ((dimension > 0) && (var.size() != 0)) {
|
||||||
for (auto it = var.begin(); it != var.end(); ++it) {
|
for (auto it = var.begin(); it != var.end(); ++it) {
|
||||||
const T_Key& key = it->first;
|
const T_Key& key = it->first;
|
||||||
const T_Value& value = it->second;
|
const T_Value& value = it->second;
|
||||||
|
|
||||||
std::string indexed_name;
|
std::string indexed_name;
|
||||||
size_t integral_index;
|
std::vector<size_t> integral_index;
|
||||||
size_t idx_width;
|
size_t idx_width = 0;
|
||||||
|
|
||||||
process_key(key, indexed_name, integral_index, name, idx_width);
|
process_key(key, indexed_name, integral_index, name, idx_width);
|
||||||
|
|
||||||
|
// Update indices and widths
|
||||||
idxWidths.push_back(idx_width);
|
idxWidths.push_back(idx_width);
|
||||||
indices.push_back(integral_index);
|
indices.insert(indices.end(), integral_index.begin(), integral_index.end());
|
||||||
|
|
||||||
record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths);
|
record_arr_table(var.at(key), indexed_name, dimension - 1, indices, idxWidths);
|
||||||
|
|
||||||
|
// Cleanup indices and widths
|
||||||
idxWidths.pop_back();
|
idxWidths.pop_back();
|
||||||
indices.pop_back();
|
indices.resize(indices.size() - integral_index.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,27 +74,41 @@ class VerilatedVarProps VL_NOT_FINAL {
|
|||||||
const uint32_t m_magic; // Magic number
|
const uint32_t m_magic; // Magic number
|
||||||
const VerilatedVarType m_vltype; // Data type
|
const VerilatedVarType m_vltype; // Data type
|
||||||
const VerilatedVarFlags m_vlflags; // Direction
|
const VerilatedVarFlags m_vlflags; // Direction
|
||||||
const int m_pdims; // Packed dimensions, 0 = none
|
|
||||||
const int m_udims; // Unpacked dimensions, 0 = none
|
|
||||||
VerilatedRange m_packed; // Packed array range
|
|
||||||
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
std::vector<VerilatedRange> m_unpacked; // Unpacked array ranges
|
||||||
void initUnpacked(const int* ulims) {
|
std::vector<VerilatedRange> m_packed; // Packed array ranges
|
||||||
for (int i = 0; i < m_udims; ++i) {
|
VerilatedRange m_packedDpi; // Flattened packed array range
|
||||||
|
void initUnpacked(int udims, const int* ulims) {
|
||||||
|
for (int i = 0; i < udims; ++i) {
|
||||||
const int uleft = ulims ? ulims[2 * i + 0] : 0;
|
const int uleft = ulims ? ulims[2 * i + 0] : 0;
|
||||||
const int uright = ulims ? ulims[2 * i + 1] : 0;
|
const int uright = ulims ? ulims[2 * i + 1] : 0;
|
||||||
m_unpacked.emplace_back(uleft, uright);
|
m_unpacked.emplace_back(uleft, uright);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void initPacked(int pdims, const int* plims) {
|
||||||
|
int packedSize = 1;
|
||||||
|
for (int i = 0; i < pdims; ++i) {
|
||||||
|
const int pleft = plims ? plims[2 * i + 0] : 0;
|
||||||
|
const int pright = plims ? plims[2 * i + 1] : 0;
|
||||||
|
m_packed.emplace_back(pleft, pright);
|
||||||
|
packedSize *= abs(pleft - pright) + 1;
|
||||||
|
}
|
||||||
|
if (pdims == 1) {
|
||||||
|
// Preserve packed array range if the packed component is 1-D
|
||||||
|
m_packedDpi = m_packed.front();
|
||||||
|
} else {
|
||||||
|
m_packedDpi = VerilatedRange{packedSize - 1, 0};
|
||||||
|
}
|
||||||
|
}
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
protected:
|
protected:
|
||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int pdims, int udims)
|
VerilatedVarProps(VerilatedVarType vltype, VerilatedVarFlags vlflags, int udims, int pdims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags{vlflags}
|
, m_vlflags{vlflags} {
|
||||||
, m_pdims{pdims}
|
// Only preallocate the ranges
|
||||||
, m_udims{udims} {
|
initUnpacked(udims, nullptr);
|
||||||
initUnpacked(nullptr);
|
initPacked(pdims, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -103,35 +117,29 @@ public:
|
|||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) {} // Need () or GCC 4.8 false warning
|
||||||
, m_pdims{0}
|
|
||||||
, m_udims{0} {}
|
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||||
, m_pdims{0}
|
initUnpacked(udims, ulims);
|
||||||
, m_udims{udims} {
|
|
||||||
initUnpacked(ulims);
|
|
||||||
}
|
}
|
||||||
// With packed
|
// With packed
|
||||||
class Packed {};
|
class Packed {};
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr)
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pdims, const int* plims)
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||||
, m_pdims{1}
|
initPacked(pdims, plims);
|
||||||
, m_udims{0}
|
}
|
||||||
, m_packed{pl, pr} {}
|
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Unpacked, int udims, const int* ulims,
|
||||||
VerilatedVarProps(VerilatedVarType vltype, int vlflags, Packed, int pl, int pr, Unpacked,
|
Packed, int pdims, const int* plims)
|
||||||
int udims, const int* ulims)
|
|
||||||
: m_magic{MAGIC}
|
: m_magic{MAGIC}
|
||||||
, m_vltype{vltype}
|
, m_vltype{vltype}
|
||||||
, m_vlflags(VerilatedVarFlags(vlflags)) // Need () or GCC 4.8 false warning
|
, m_vlflags(VerilatedVarFlags(vlflags)) { // Need () or GCC 4.8 false warning
|
||||||
, m_pdims{1}
|
initUnpacked(udims, ulims);
|
||||||
, m_udims{udims}
|
initPacked(pdims, plims);
|
||||||
, m_packed{pl, pr} {
|
|
||||||
initUnpacked(ulims);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~VerilatedVarProps() = default;
|
~VerilatedVarProps() = default;
|
||||||
@@ -142,41 +150,55 @@ public:
|
|||||||
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
return static_cast<VerilatedVarFlags>(static_cast<int>(m_vlflags) & VLVF_MASK_DIR);
|
||||||
}
|
}
|
||||||
uint32_t entSize() const VL_MT_SAFE;
|
uint32_t entSize() const VL_MT_SAFE;
|
||||||
|
uint32_t entBits() const VL_MT_SAFE {
|
||||||
|
uint32_t bits = 1;
|
||||||
|
for (auto it : m_packed) bits *= it.elements();
|
||||||
|
return bits;
|
||||||
|
}
|
||||||
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
bool isPublicRW() const { return ((m_vlflags & VLVF_PUB_RW) != 0); }
|
||||||
// DPI compatible C standard layout
|
// DPI compatible C standard layout
|
||||||
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
bool isDpiCLayout() const { return ((m_vlflags & VLVF_DPI_CLAY) != 0); }
|
||||||
int udims() const VL_MT_SAFE { return m_udims; }
|
int udims() const VL_MT_SAFE { return m_unpacked.size(); }
|
||||||
int dims() const { return m_pdims + m_udims; }
|
int pdims() const VL_MT_SAFE { return m_packed.size(); }
|
||||||
const VerilatedRange& packed() const VL_MT_SAFE { return m_packed; }
|
int dims() const VL_MT_SAFE { return pdims() + udims(); }
|
||||||
const VerilatedRange& unpacked() const { return m_unpacked[0]; }
|
const std::vector<VerilatedRange>& packedRanges() const VL_MT_SAFE { return m_packed; }
|
||||||
// DPI accessors
|
const std::vector<VerilatedRange>& unpackedRanges() const VL_MT_SAFE { return m_unpacked; }
|
||||||
|
const VerilatedRange* range(int dim) const VL_MT_SAFE {
|
||||||
|
if (dim < udims())
|
||||||
|
return &m_unpacked[dim];
|
||||||
|
else if (dim < dims())
|
||||||
|
return &m_packed[dim - udims()];
|
||||||
|
else
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
// DPI accessors (with packed dimensions flattened!)
|
||||||
int left(int dim) const VL_MT_SAFE {
|
int left(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.left()
|
return dim == 0 ? m_packedDpi.left()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].left()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int right(int dim) const VL_MT_SAFE {
|
int right(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.right()
|
return dim == 0 ? m_packedDpi.right()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].right()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int low(int dim) const VL_MT_SAFE {
|
int low(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.low()
|
return dim == 0 ? m_packedDpi.low()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].low()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int high(int dim) const VL_MT_SAFE {
|
int high(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.high()
|
return dim == 0 ? m_packedDpi.high()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].high()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int increment(int dim) const {
|
int increment(int dim) const {
|
||||||
return dim == 0 ? m_packed.increment()
|
return dim == 0 ? m_packedDpi.increment()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].increment()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
int elements(int dim) const VL_MT_SAFE {
|
int elements(int dim) const VL_MT_SAFE {
|
||||||
return dim == 0 ? m_packed.elements()
|
return dim == 0 ? m_packedDpi.elements()
|
||||||
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
: VL_LIKELY(dim >= 1 && dim <= udims()) ? m_unpacked[dim - 1].elements()
|
||||||
: 0;
|
: 0;
|
||||||
}
|
}
|
||||||
@@ -208,8 +230,7 @@ public:
|
|||||||
bool magicOk() const { return m_propsp->magicOk(); }
|
bool magicOk() const { return m_propsp->magicOk(); }
|
||||||
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
VerilatedVarType vltype() const { return m_propsp->vltype(); }
|
||||||
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
bool isDpiStdLayout() const { return m_propsp->isDpiCLayout(); }
|
||||||
const VerilatedRange& packed() const { return m_propsp->packed(); }
|
int entBits() const { return m_propsp->entBits(); }
|
||||||
const VerilatedRange& unpacked() const { return m_propsp->unpacked(); }
|
|
||||||
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
|
int udims() const VL_MT_SAFE { return m_propsp->udims(); }
|
||||||
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
|
int left(int dim) const VL_MT_SAFE { return m_propsp->left(dim); }
|
||||||
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
|
int right(int dim) const VL_MT_SAFE { return m_propsp->right(dim); }
|
||||||
@@ -236,8 +257,8 @@ protected:
|
|||||||
friend class VerilatedScope;
|
friend class VerilatedScope;
|
||||||
// CONSTRUCTORS
|
// CONSTRUCTORS
|
||||||
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
VerilatedVar(const char* namep, void* datap, VerilatedVarType vltype,
|
||||||
VerilatedVarFlags vlflags, int dims, bool isParam)
|
VerilatedVarFlags vlflags, int udims, int pdims, bool isParam)
|
||||||
: VerilatedVarProps{vltype, vlflags, (dims > 0 ? 1 : 0), ((dims > 1) ? dims - 1 : 0)}
|
: VerilatedVarProps{vltype, vlflags, udims, pdims}
|
||||||
, m_datap{datap}
|
, m_datap{datap}
|
||||||
, m_namep{namep}
|
, m_namep{namep}
|
||||||
, m_isParam{isParam} {}
|
, m_isParam{isParam} {}
|
||||||
@@ -246,8 +267,6 @@ public:
|
|||||||
~VerilatedVar() = default;
|
~VerilatedVar() = default;
|
||||||
// ACCESSORS
|
// ACCESSORS
|
||||||
void* datap() const { return m_datap; }
|
void* datap() const { return m_datap; }
|
||||||
const VerilatedRange& range() const { return packed(); } // Deprecated
|
|
||||||
const VerilatedRange& array() const { return unpacked(); } // Deprecated
|
|
||||||
const char* name() const { return m_namep; }
|
const char* name() const { return m_namep; }
|
||||||
bool isParam() const { return m_isParam; }
|
bool isParam() const { return m_isParam; }
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -451,6 +451,7 @@ struct VlWide final {
|
|||||||
// METHODS
|
// METHODS
|
||||||
const EData& at(size_t index) const { return m_storage[index]; }
|
const EData& at(size_t index) const { return m_storage[index]; }
|
||||||
EData& at(size_t index) { return m_storage[index]; }
|
EData& at(size_t index) { return m_storage[index]; }
|
||||||
|
size_t size() const { return N_Words; }
|
||||||
WData* data() { return &m_storage[0]; }
|
WData* data() { return &m_storage[0]; }
|
||||||
const WData* data() const { return &m_storage[0]; }
|
const WData* data() const { return &m_storage[0]; }
|
||||||
bool operator<(const VlWide<N_Words>& rhs) const {
|
bool operator<(const VlWide<N_Words>& rhs) const {
|
||||||
@@ -504,6 +505,12 @@ public:
|
|||||||
VlQueue& operator=(VlQueue&&) = default;
|
VlQueue& operator=(VlQueue&&) = default;
|
||||||
bool operator==(const VlQueue& rhs) const { return m_deque == rhs.m_deque; }
|
bool operator==(const VlQueue& rhs) const { return m_deque == rhs.m_deque; }
|
||||||
bool operator!=(const VlQueue& rhs) const { return m_deque != rhs.m_deque; }
|
bool operator!=(const VlQueue& rhs) const { return m_deque != rhs.m_deque; }
|
||||||
|
bool operator<(const VlQueue& rhs) const {
|
||||||
|
for (int index = 0; index < m_deque.size(); ++index) {
|
||||||
|
if (m_deque[index] < rhs.m_deque[index]) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Standard copy constructor works. Verilog: assoca = assocb
|
// Standard copy constructor works. Verilog: assoca = assocb
|
||||||
// Also must allow conversion from a different N_MaxSize queue
|
// Also must allow conversion from a different N_MaxSize queue
|
||||||
@@ -947,7 +954,7 @@ public:
|
|||||||
VlAssocArray& operator=(VlAssocArray&&) = default;
|
VlAssocArray& operator=(VlAssocArray&&) = default;
|
||||||
bool operator==(const VlAssocArray& rhs) const { return m_map == rhs.m_map; }
|
bool operator==(const VlAssocArray& rhs) const { return m_map == rhs.m_map; }
|
||||||
bool operator!=(const VlAssocArray& rhs) const { return m_map != rhs.m_map; }
|
bool operator!=(const VlAssocArray& rhs) const { return m_map != rhs.m_map; }
|
||||||
|
bool operator<(const VlAssocArray& rhs) const { return m_map < rhs.m_map; }
|
||||||
// METHODS
|
// METHODS
|
||||||
T_Value& atDefault() { return m_defaultValue; }
|
T_Value& atDefault() { return m_defaultValue; }
|
||||||
const T_Value& atDefault() const { return m_defaultValue; }
|
const T_Value& atDefault() const { return m_defaultValue; }
|
||||||
@@ -1312,7 +1319,7 @@ public:
|
|||||||
WData* data() { return &m_storage[0]; }
|
WData* data() { return &m_storage[0]; }
|
||||||
const WData* data() const { return &m_storage[0]; }
|
const WData* data() const { return &m_storage[0]; }
|
||||||
|
|
||||||
std::size_t size() const { return N_Depth; }
|
constexpr std::size_t size() const { return N_Depth; }
|
||||||
// To fit C++14
|
// To fit C++14
|
||||||
template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
|
template <std::size_t N_CurrentDimension = 0, typename U = T_Value>
|
||||||
int find_length(int dimension, std::false_type) const {
|
int find_length(int dimension, std::false_type) const {
|
||||||
@@ -1350,7 +1357,7 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
T_Value& operator[](size_t index) { return m_storage[index]; }
|
T_Value& operator[](size_t index) { return m_storage[index]; }
|
||||||
const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
constexpr const T_Value& operator[](size_t index) const { return m_storage[index]; }
|
||||||
|
|
||||||
// *this != that, which might be used for change detection/trigger computation, but avoid
|
// *this != that, which might be used for change detection/trigger computation, but avoid
|
||||||
// operator overloading in VlUnpacked for safety in other contexts.
|
// operator overloading in VlUnpacked for safety in other contexts.
|
||||||
@@ -1363,6 +1370,12 @@ public:
|
|||||||
bool neq(const T_Value that[N_Depth]) const { return neq(*this, that); }
|
bool neq(const T_Value that[N_Depth]) const { return neq(*this, that); }
|
||||||
void assign(const T_Value that[N_Depth]) { std::copy_n(that, N_Depth, m_storage); }
|
void assign(const T_Value that[N_Depth]) { std::copy_n(that, N_Depth, m_storage); }
|
||||||
void operator=(const T_Value that[N_Depth]) { assign(that); }
|
void operator=(const T_Value that[N_Depth]) { assign(that); }
|
||||||
|
bool operator<(const VlUnpacked<T_Value, N_Depth>& that) const {
|
||||||
|
for (int index = 0; index < N_Depth; ++index) {
|
||||||
|
if (m_storage[index] < that.m_storage[index]) return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// inside (set membership operator)
|
// inside (set membership operator)
|
||||||
bool inside(const T_Value& value) const {
|
bool inside(const T_Value& value) const {
|
||||||
|
|||||||
+1027
-340
File diff suppressed because it is too large
Load Diff
@@ -474,6 +474,7 @@ using ssize_t = uint32_t; ///< signed size_t; returned from read()
|
|||||||
#ifndef VL_VALUE_STRING_MAX_WORDS
|
#ifndef VL_VALUE_STRING_MAX_WORDS
|
||||||
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
#define VL_VALUE_STRING_MAX_WORDS 64 ///< Max size in words of String conversion operation
|
||||||
#endif
|
#endif
|
||||||
|
#define VL_VALUE_STRING_MAX_CHARS (VL_VALUE_STRING_MAX_WORDS) * 4
|
||||||
|
|
||||||
//=========================================================================
|
//=========================================================================
|
||||||
// Base macros
|
// Base macros
|
||||||
|
|||||||
+10
-8
@@ -349,7 +349,7 @@ public:
|
|||||||
|
|
||||||
class ActiveDlyVisitor final : public VNVisitor {
|
class ActiveDlyVisitor final : public VNVisitor {
|
||||||
public:
|
public:
|
||||||
enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL };
|
enum CheckType : uint8_t { CT_SEQ, CT_COMB, CT_INITIAL, CT_SUSPENDABLE };
|
||||||
|
|
||||||
private:
|
private:
|
||||||
// MEMBERS
|
// MEMBERS
|
||||||
@@ -358,7 +358,7 @@ private:
|
|||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstAssignDly* nodep) override {
|
void visit(AstAssignDly* nodep) override {
|
||||||
// Non-blocking assignments are OK in sequential processes
|
// Non-blocking assignments are OK in sequential processes
|
||||||
if (m_check == CT_SEQ) return;
|
if (m_check == CT_SEQ || m_check == CT_SUSPENDABLE) return;
|
||||||
|
|
||||||
// Issue appropriate warning
|
// Issue appropriate warning
|
||||||
if (m_check == CT_INITIAL) {
|
if (m_check == CT_INITIAL) {
|
||||||
@@ -477,10 +477,8 @@ class ActiveVisitor final : public VNVisitor {
|
|||||||
AstActive* const wantactivep
|
AstActive* const wantactivep
|
||||||
= !m_clockedProcess ? m_namer.getSpecialActive<AstSenItem::Combo>(nodep->fileline())
|
= !m_clockedProcess ? m_namer.getSpecialActive<AstSenItem::Combo>(nodep->fileline())
|
||||||
: oldsensesp ? m_namer.getActive(nodep->fileline(), oldsensesp)
|
: oldsensesp ? m_namer.getActive(nodep->fileline(), oldsensesp)
|
||||||
: m_namer.getSpecialActive<AstSenItem::Initial>(nodep->fileline());
|
// Clocked, no sensitivity lists, it's a suspendable, put it in initial
|
||||||
|
: m_namer.getSpecialActive<AstSenItem::Initial>(nodep->fileline());
|
||||||
// Delete sensitivity list
|
|
||||||
if (oldsensesp) VL_DO_DANGLING(oldsensesp->deleteTree(), oldsensesp);
|
|
||||||
|
|
||||||
// Move node to new active
|
// Move node to new active
|
||||||
nodep->unlinkFrBack();
|
nodep->unlinkFrBack();
|
||||||
@@ -488,10 +486,14 @@ class ActiveVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
// Warn and convert any delayed assignments
|
// Warn and convert any delayed assignments
|
||||||
{
|
{
|
||||||
ActiveDlyVisitor{nodep, m_clockedProcess ? ActiveDlyVisitor::CT_SEQ
|
ActiveDlyVisitor{nodep, !m_clockedProcess ? ActiveDlyVisitor::CT_COMB
|
||||||
: ActiveDlyVisitor::CT_COMB};
|
: oldsensesp ? ActiveDlyVisitor::CT_SEQ
|
||||||
|
: ActiveDlyVisitor::CT_SUSPENDABLE};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Delete sensitivity list
|
||||||
|
if (oldsensesp) VL_DO_DANGLING(oldsensesp->deleteTree(), oldsensesp);
|
||||||
|
|
||||||
// check combinational processes for latches
|
// check combinational processes for latches
|
||||||
if (!m_clockedProcess || kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
if (!m_clockedProcess || kwd == VAlwaysKwd::ALWAYS_LATCH) {
|
||||||
const ActiveLatchCheckVisitor latchvisitor{nodep, kwd == VAlwaysKwd::ALWAYS_LATCH};
|
const ActiveLatchCheckVisitor latchvisitor{nodep, kwd == VAlwaysKwd::ALWAYS_LATCH};
|
||||||
|
|||||||
+3
-2
@@ -534,8 +534,9 @@ class AssertVisitor final : public VNVisitor {
|
|||||||
while (monExprsp) {
|
while (monExprsp) {
|
||||||
if (AstNodeVarRef* varrefp = VN_CAST(monExprsp, NodeVarRef)) {
|
if (AstNodeVarRef* varrefp = VN_CAST(monExprsp, NodeVarRef)) {
|
||||||
AstSenItem* const senItemp
|
AstSenItem* const senItemp
|
||||||
= new AstSenItem(fl, VEdgeType::ET_CHANGED,
|
= new AstSenItem{fl, VEdgeType::ET_CHANGED,
|
||||||
new AstVarRef{fl, varrefp->varp(), VAccess::READ});
|
// Clone so get VarRef or VarXRef as needed
|
||||||
|
varrefp->cloneTree(false)};
|
||||||
if (!monSenItemsp) {
|
if (!monSenItemsp) {
|
||||||
monSenItemsp = senItemp;
|
monSenItemsp = senItemp;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
+16
-7
@@ -196,6 +196,11 @@ string AstNode::prettyName(const string& namein) VL_PURE {
|
|||||||
pos += 7;
|
pos += 7;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
if (0 == std::strncmp(pos, "__Viftop", 8)) {
|
||||||
|
pretty += "";
|
||||||
|
pos += 8;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
|
if (pos[0] == '_' && pos[1] == '_' && pos[2] == '0' && std::isxdigit(pos[3])
|
||||||
&& std::isxdigit(pos[4])) {
|
&& std::isxdigit(pos[4])) {
|
||||||
char value = 0;
|
char value = 0;
|
||||||
@@ -797,13 +802,7 @@ void AstNode::swapWith(AstNode* bp) {
|
|||||||
|
|
||||||
AstNode* AstNode::cloneTreeIter(bool needPure) {
|
AstNode* AstNode::cloneTreeIter(bool needPure) {
|
||||||
// private: Clone single node and children
|
// private: Clone single node and children
|
||||||
if (VL_UNLIKELY(needPure && !isPure())) {
|
if (needPure) purityCheck();
|
||||||
this->v3warn(SIDEEFFECT,
|
|
||||||
"Expression side effect may be mishandled\n"
|
|
||||||
<< this->warnMore()
|
|
||||||
<< "... Suggest use a temporary variable in place of this expression");
|
|
||||||
// this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused
|
|
||||||
}
|
|
||||||
AstNode* const newp = this->clone();
|
AstNode* const newp = this->clone();
|
||||||
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure));
|
if (this->m_op1p) newp->op1p(this->m_op1p->cloneTreeIterList(needPure));
|
||||||
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList(needPure));
|
if (this->m_op2p) newp->op2p(this->m_op2p->cloneTreeIterList(needPure));
|
||||||
@@ -850,6 +849,16 @@ AstNode* AstNode::cloneTree(bool cloneNextLink, bool needPure) {
|
|||||||
return newp;
|
return newp;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AstNode::purityCheck() {
|
||||||
|
if (VL_UNLIKELY(!isPure())) {
|
||||||
|
this->v3warn(SIDEEFFECT,
|
||||||
|
"Expression side effect may be mishandled\n"
|
||||||
|
<< this->warnMore()
|
||||||
|
<< "... Suggest use a temporary variable in place of this expression");
|
||||||
|
// this->v3fatalSrc("cloneTreePure debug backtrace"); // Comment in to debug where caused
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
// Delete
|
// Delete
|
||||||
|
|
||||||
|
|||||||
@@ -2077,6 +2077,7 @@ private:
|
|||||||
string instanceStr() const;
|
string instanceStr() const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
void purityCheck();
|
||||||
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
|
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
|
||||||
// cppcheck-suppress functionConst
|
// cppcheck-suppress functionConst
|
||||||
static void debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next);
|
static void debugTreeChange(const AstNode* nodep, const char* prefix, int lineno, bool next);
|
||||||
|
|||||||
+4
-2
@@ -188,8 +188,9 @@ bool AstVarRef::sameNode(const AstVarRef* samep) const {
|
|||||||
if (varScopep()) {
|
if (varScopep()) {
|
||||||
return (varScopep() == samep->varScopep() && access() == samep->access());
|
return (varScopep() == samep->varScopep() && access() == samep->access());
|
||||||
} else {
|
} else {
|
||||||
return (selfPointer() == samep->selfPointer() && varp()->name() == samep->varp()->name()
|
return (selfPointer() == samep->selfPointer()
|
||||||
&& access() == samep->access());
|
&& classOrPackagep() == samep->classOrPackagep()
|
||||||
|
&& varp()->name() == samep->varp()->name() && access() == samep->access());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
|
bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
|
||||||
@@ -197,6 +198,7 @@ bool AstVarRef::sameNoLvalue(AstVarRef* samep) const {
|
|||||||
return (varScopep() == samep->varScopep());
|
return (varScopep() == samep->varScopep());
|
||||||
} else {
|
} else {
|
||||||
return (selfPointer() == samep->selfPointer()
|
return (selfPointer() == samep->selfPointer()
|
||||||
|
&& classOrPackagep() == samep->classOrPackagep()
|
||||||
&& (!selfPointer().isEmpty() || !samep->selfPointer().isEmpty())
|
&& (!selfPointer().isEmpty() || !samep->selfPointer().isEmpty())
|
||||||
&& varp()->name() == samep->varp()->name());
|
&& varp()->name() == samep->varp()->name());
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-3
@@ -230,6 +230,7 @@ class AstNodeUOrStructDType VL_NOT_FINAL : public AstNodeDType {
|
|||||||
const int m_uniqueNum;
|
const int m_uniqueNum;
|
||||||
bool m_packed;
|
bool m_packed;
|
||||||
bool m_isFourstate = false; // V3Width computes
|
bool m_isFourstate = false; // V3Width computes
|
||||||
|
bool m_constrainedRand = false; // True if struct has constraint expression
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
|
AstNodeUOrStructDType(VNType t, FileLine* fl, VSigning numericUnpack)
|
||||||
@@ -244,7 +245,8 @@ protected:
|
|||||||
, m_name(other.m_name)
|
, m_name(other.m_name)
|
||||||
, m_uniqueNum(uniqueNumInc())
|
, m_uniqueNum(uniqueNumInc())
|
||||||
, m_packed(other.m_packed)
|
, m_packed(other.m_packed)
|
||||||
, m_isFourstate(other.m_isFourstate) {}
|
, m_isFourstate(other.m_isFourstate)
|
||||||
|
, m_constrainedRand(false) {}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
ASTGEN_MEMBERS_AstNodeUOrStructDType;
|
||||||
@@ -284,6 +286,8 @@ public:
|
|||||||
VNumRange declRange() const VL_MT_STABLE { return VNumRange{hi(), lo()}; }
|
VNumRange declRange() const VL_MT_STABLE { return VNumRange{hi(), lo()}; }
|
||||||
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
AstNodeModule* classOrPackagep() const { return m_classOrPackagep; }
|
||||||
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
void classOrPackagep(AstNodeModule* classpackagep) { m_classOrPackagep = classpackagep; }
|
||||||
|
bool isConstrainedRand() { return m_constrainedRand; }
|
||||||
|
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
// === Concrete node types =====================================================
|
// === Concrete node types =====================================================
|
||||||
@@ -905,12 +909,14 @@ class AstMemberDType final : public AstNodeDType {
|
|||||||
string m_name; // Name of variable
|
string m_name; // Name of variable
|
||||||
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
string m_tag; // Holds the string of the verilator tag -- used in XML output.
|
||||||
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
int m_lsb = -1; // Within this level's packed struct, the LSB of the first bit of the member
|
||||||
|
bool m_constrainedRand = false;
|
||||||
// UNSUP: int m_randType; // Randomization type (IEEE)
|
// UNSUP: int m_randType; // Randomization type (IEEE)
|
||||||
public:
|
public:
|
||||||
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
AstMemberDType(FileLine* fl, const string& name, VFlagChildDType, AstNodeDType* dtp,
|
||||||
AstNode* valuep)
|
AstNode* valuep)
|
||||||
: ASTGEN_SUPER_MemberDType(fl)
|
: ASTGEN_SUPER_MemberDType(fl)
|
||||||
, m_name{name} {
|
, m_name{name}
|
||||||
|
, m_constrainedRand(false) {
|
||||||
childDTypep(dtp); // Only for parser
|
childDTypep(dtp); // Only for parser
|
||||||
this->valuep(valuep);
|
this->valuep(valuep);
|
||||||
dtypep(nullptr); // V3Width will resolve
|
dtypep(nullptr); // V3Width will resolve
|
||||||
@@ -918,13 +924,16 @@ public:
|
|||||||
}
|
}
|
||||||
AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp)
|
AstMemberDType(FileLine* fl, const string& name, AstNodeDType* dtp)
|
||||||
: ASTGEN_SUPER_MemberDType(fl)
|
: ASTGEN_SUPER_MemberDType(fl)
|
||||||
, m_name{name} {
|
, m_name{name}
|
||||||
|
, m_constrainedRand(false) {
|
||||||
UASSERT(dtp, "AstMember created with no dtype");
|
UASSERT(dtp, "AstMember created with no dtype");
|
||||||
refDTypep(dtp);
|
refDTypep(dtp);
|
||||||
dtypep(this);
|
dtypep(this);
|
||||||
widthFromSub(subDTypep());
|
widthFromSub(subDTypep());
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstMemberDType;
|
ASTGEN_MEMBERS_AstMemberDType;
|
||||||
|
void dump(std::ostream& str = std::cout) const override;
|
||||||
|
void dumpJson(std::ostream& str = std::cout) const override;
|
||||||
void dumpSmall(std::ostream& str) const override;
|
void dumpSmall(std::ostream& str) const override;
|
||||||
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
string name() const override VL_MT_STABLE { return m_name; } // * = Var name
|
||||||
bool hasDType() const override VL_MT_SAFE { return true; }
|
bool hasDType() const override VL_MT_SAFE { return true; }
|
||||||
@@ -958,6 +967,8 @@ public:
|
|||||||
v3fatalSrc("call isCompound on subdata type, not reference");
|
v3fatalSrc("call isCompound on subdata type, not reference");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool isConstrainedRand() const { return m_constrainedRand; }
|
||||||
|
void markConstrainedRand(bool flag) { m_constrainedRand = flag; }
|
||||||
};
|
};
|
||||||
class AstNBACommitQueueDType final : public AstNodeDType {
|
class AstNBACommitQueueDType final : public AstNodeDType {
|
||||||
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
// @astgen ptr := m_subDTypep : AstNodeDType // Type of the corresponding variable
|
||||||
|
|||||||
+4
-4
@@ -1668,7 +1668,7 @@ class AstParseHolder final : public AstNodeExpr {
|
|||||||
// A reference to something soon to replace, used in a select at parse time
|
// A reference to something soon to replace, used in a select at parse time
|
||||||
// that needs conversion to pull the upper lvalue later
|
// that needs conversion to pull the upper lvalue later
|
||||||
public:
|
public:
|
||||||
AstParseHolder(FileLine* fl)
|
explicit AstParseHolder(FileLine* fl)
|
||||||
: ASTGEN_SUPER_ParseHolder(fl) {}
|
: ASTGEN_SUPER_ParseHolder(fl) {}
|
||||||
ASTGEN_MEMBERS_AstParseHolder;
|
ASTGEN_MEMBERS_AstParseHolder;
|
||||||
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
string emitVerilog() override { V3ERROR_NA_RETURN(""); }
|
||||||
@@ -1820,7 +1820,6 @@ public:
|
|||||||
return "VL_RANDOM_SEEDED_%nq%lq(%li)";
|
return "VL_RANDOM_SEEDED_%nq%lq(%li)";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isWide()) {
|
if (isWide()) {
|
||||||
return "VL_RANDOM_%nq(%nw, %P)";
|
return "VL_RANDOM_%nq(%nw, %P)";
|
||||||
} else {
|
} else {
|
||||||
@@ -1830,6 +1829,7 @@ public:
|
|||||||
bool cleanOut() const override { return false; }
|
bool cleanOut() const override { return false; }
|
||||||
bool isGateOptimizable() const override { return false; }
|
bool isGateOptimizable() const override { return false; }
|
||||||
bool isPredictOptimizable() const override { return false; }
|
bool isPredictOptimizable() const override { return false; }
|
||||||
|
bool isPure() override { return !m_reset && !seedp(); }
|
||||||
int instrCount() const override { return INSTR_COUNT_PLI; }
|
int instrCount() const override { return INSTR_COUNT_PLI; }
|
||||||
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
bool sameNode(const AstNode* /*samep*/) const override { return true; }
|
||||||
bool combinable(const AstRand* samep) const {
|
bool combinable(const AstRand* samep) const {
|
||||||
@@ -4151,7 +4151,7 @@ public:
|
|||||||
return new AstArraySel{fileline(), lhsp, rhsp};
|
return new AstArraySel{fileline(), lhsp, rhsp};
|
||||||
}
|
}
|
||||||
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) override {
|
||||||
V3ERROR_NA; /* How can from be a const? */
|
V3ERROR_NA; // How can from be a const?
|
||||||
}
|
}
|
||||||
string emitVerilog() override { return "%k(%l%f[%r])"; }
|
string emitVerilog() override { return "%k(%l%f[%r])"; }
|
||||||
string emitC() override { return "%li%k[%ri]"; }
|
string emitC() override { return "%li%k[%ri]"; }
|
||||||
@@ -4511,7 +4511,7 @@ public:
|
|||||||
// === AstNodeTermop ===
|
// === AstNodeTermop ===
|
||||||
class AstInferredDisable final : public AstNodeTermop {
|
class AstInferredDisable final : public AstNodeTermop {
|
||||||
public:
|
public:
|
||||||
AstInferredDisable(FileLine* fl)
|
explicit AstInferredDisable(FileLine* fl)
|
||||||
: ASTGEN_SUPER_InferredDisable(fl) {
|
: ASTGEN_SUPER_InferredDisable(fl) {
|
||||||
dtypeSetLogicSized(1, VSigning::UNSIGNED);
|
dtypeSetLogicSized(1, VSigning::UNSIGNED);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
-5
@@ -625,6 +625,7 @@ class AstCFunc final : public AstNode {
|
|||||||
bool m_isTrace : 1; // Function is related to tracing
|
bool m_isTrace : 1; // Function is related to tracing
|
||||||
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
|
bool m_dontCombine : 1; // V3Combine shouldn't compare this func tree, it's special
|
||||||
bool m_declPrivate : 1; // Declare it private
|
bool m_declPrivate : 1; // Declare it private
|
||||||
|
bool m_keepIfEmpty : 1; // Keep declaration and definition separate, even if empty
|
||||||
bool m_slow : 1; // Slow routine, called once or just at init time
|
bool m_slow : 1; // Slow routine, called once or just at init time
|
||||||
bool m_funcPublic : 1; // From user public task/function
|
bool m_funcPublic : 1; // From user public task/function
|
||||||
bool m_isConstructor : 1; // Is C class constructor
|
bool m_isConstructor : 1; // Is C class constructor
|
||||||
@@ -643,6 +644,7 @@ class AstCFunc final : public AstNode {
|
|||||||
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
bool m_dpiImportWrapper : 1; // Wrapper for invoking DPI import prototype from generated code
|
||||||
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
bool m_needProcess : 1; // Needs access to VlProcess of the caller
|
||||||
bool m_recursive : 1; // Recursive or part of recursion
|
bool m_recursive : 1; // Recursive or part of recursion
|
||||||
|
int m_cost; // Function call cost
|
||||||
public:
|
public:
|
||||||
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
AstCFunc(FileLine* fl, const string& name, AstScope* scopep, const string& rtnType = "")
|
||||||
: ASTGEN_SUPER_CFunc(fl) {
|
: ASTGEN_SUPER_CFunc(fl) {
|
||||||
@@ -654,6 +656,7 @@ public:
|
|||||||
m_isTrace = false;
|
m_isTrace = false;
|
||||||
m_dontCombine = false;
|
m_dontCombine = false;
|
||||||
m_declPrivate = false;
|
m_declPrivate = false;
|
||||||
|
m_keepIfEmpty = false;
|
||||||
m_slow = false;
|
m_slow = false;
|
||||||
m_funcPublic = false;
|
m_funcPublic = false;
|
||||||
m_isConstructor = false;
|
m_isConstructor = false;
|
||||||
@@ -671,6 +674,7 @@ public:
|
|||||||
m_dpiImportPrototype = false;
|
m_dpiImportPrototype = false;
|
||||||
m_dpiImportWrapper = false;
|
m_dpiImportWrapper = false;
|
||||||
m_recursive = false;
|
m_recursive = false;
|
||||||
|
m_cost = v3Global.opt.instrCountDpi(); // As proxy for unknown general DPI cost
|
||||||
}
|
}
|
||||||
ASTGEN_MEMBERS_AstCFunc;
|
ASTGEN_MEMBERS_AstCFunc;
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
@@ -685,9 +689,7 @@ public:
|
|||||||
}
|
}
|
||||||
//
|
//
|
||||||
void name(const string& name) override { m_name = name; }
|
void name(const string& name) override { m_name = name; }
|
||||||
int instrCount() const override {
|
int instrCount() const override { return m_cost; }
|
||||||
return dpiImportPrototype() ? v3Global.opt.instrCountDpi() : 0;
|
|
||||||
}
|
|
||||||
VBoolOrUnknown isConst() const { return m_isConst; }
|
VBoolOrUnknown isConst() const { return m_isConst; }
|
||||||
void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); }
|
void isConst(bool flag) { m_isConst.setTrueOrFalse(flag); }
|
||||||
void isConst(VBoolOrUnknown flag) { m_isConst = flag; }
|
void isConst(VBoolOrUnknown flag) { m_isConst = flag; }
|
||||||
@@ -706,6 +708,8 @@ public:
|
|||||||
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
|
bool dontInline() const { return dontCombine() || slow() || funcPublic(); }
|
||||||
bool declPrivate() const { return m_declPrivate; }
|
bool declPrivate() const { return m_declPrivate; }
|
||||||
void declPrivate(bool flag) { m_declPrivate = flag; }
|
void declPrivate(bool flag) { m_declPrivate = flag; }
|
||||||
|
bool keepIfEmpty() const VL_MT_SAFE { return m_keepIfEmpty; }
|
||||||
|
void keepIfEmpty(bool flag) { m_keepIfEmpty = flag; }
|
||||||
bool slow() const VL_MT_SAFE { return m_slow; }
|
bool slow() const VL_MT_SAFE { return m_slow; }
|
||||||
void slow(bool flag) { m_slow = flag; }
|
void slow(bool flag) { m_slow = flag; }
|
||||||
bool funcPublic() const { return m_funcPublic; }
|
bool funcPublic() const { return m_funcPublic; }
|
||||||
@@ -746,10 +750,10 @@ public:
|
|||||||
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
bool isCoroutine() const { return m_rtnType == "VlCoroutine"; }
|
||||||
void recursive(bool flag) { m_recursive = flag; }
|
void recursive(bool flag) { m_recursive = flag; }
|
||||||
bool recursive() const { return m_recursive; }
|
bool recursive() const { return m_recursive; }
|
||||||
|
void cost(int cost) { m_cost = cost; }
|
||||||
// Special methods
|
// Special methods
|
||||||
bool emptyBody() const {
|
bool emptyBody() const {
|
||||||
return argsp() == nullptr && initsp() == nullptr && stmtsp() == nullptr
|
return !keepIfEmpty() && !argsp() && !initsp() && !stmtsp() && !finalsp();
|
||||||
&& finalsp() == nullptr;
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
class AstCLocalScope final : public AstNode {
|
class AstCLocalScope final : public AstNode {
|
||||||
@@ -1248,6 +1252,7 @@ public:
|
|||||||
, m_name{name} {
|
, m_name{name} {
|
||||||
this->addVarsp(varsp);
|
this->addVarsp(varsp);
|
||||||
}
|
}
|
||||||
|
string verilogKwd() const override { return "modport"; }
|
||||||
string name() const override VL_MT_STABLE { return m_name; }
|
string name() const override VL_MT_STABLE { return m_name; }
|
||||||
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
bool maybePointedTo() const override VL_MT_SAFE { return true; }
|
||||||
ASTGEN_MEMBERS_AstModport;
|
ASTGEN_MEMBERS_AstModport;
|
||||||
|
|||||||
+60
-17
@@ -570,15 +570,28 @@ string AstVar::vlEnumDir() const {
|
|||||||
string AstVar::vlPropDecl(const string& propName) const {
|
string AstVar::vlPropDecl(const string& propName) const {
|
||||||
string out;
|
string out;
|
||||||
|
|
||||||
|
std::vector<int> plims; // Packed dimension limits
|
||||||
std::vector<int> ulims; // Unpacked dimension limits
|
std::vector<int> ulims; // Unpacked dimension limits
|
||||||
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
|
||||||
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
if (const AstBasicDType* const bdtypep = basicp()) {
|
||||||
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
for (const AstNodeDType* dtp = dtypep(); dtp;) {
|
||||||
ulims.push_back(adtypep->declRange().left());
|
dtp = dtp->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
ulims.push_back(adtypep->declRange().right());
|
if (const AstNodeArrayDType* const adtypep = VN_CAST(dtp, NodeArrayDType)) {
|
||||||
dtp = adtypep->subDTypep();
|
if (VN_IS(dtp, PackArrayDType)) {
|
||||||
} else {
|
plims.push_back(adtypep->declRange().left());
|
||||||
break; // AstBasicDType - nothing below
|
plims.push_back(adtypep->declRange().right());
|
||||||
|
} else {
|
||||||
|
ulims.push_back(adtypep->declRange().left());
|
||||||
|
ulims.push_back(adtypep->declRange().right());
|
||||||
|
}
|
||||||
|
dtp = adtypep->subDTypep();
|
||||||
|
} else {
|
||||||
|
if (bdtypep->isRanged()) {
|
||||||
|
plims.push_back(bdtypep->left());
|
||||||
|
plims.push_back(bdtypep->right());
|
||||||
|
}
|
||||||
|
break; // AstBasicDType - nothing below
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -595,23 +608,37 @@ string AstVar::vlPropDecl(const string& propName) const {
|
|||||||
out += "};\n";
|
out += "};\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!plims.empty()) {
|
||||||
|
out += "static const int " + propName + "__plims[";
|
||||||
|
out += cvtToStr(plims.size());
|
||||||
|
out += "] = {";
|
||||||
|
auto it = plims.cbegin();
|
||||||
|
out += cvtToStr(*it);
|
||||||
|
while (++it != plims.cend()) {
|
||||||
|
out += ", ";
|
||||||
|
out += cvtToStr(*it);
|
||||||
|
}
|
||||||
|
out += "};\n";
|
||||||
|
}
|
||||||
|
|
||||||
out += "static const VerilatedVarProps ";
|
out += "static const VerilatedVarProps ";
|
||||||
out += propName;
|
out += propName;
|
||||||
out += "(";
|
out += "(";
|
||||||
out += vlEnumType(); // VLVT_UINT32 etc
|
out += vlEnumType(); // VLVT_UINT32 etc
|
||||||
out += ", " + vlEnumDir(); // VLVD_IN etc
|
out += ", " + vlEnumDir(); // VLVD_IN etc
|
||||||
if (const AstBasicDType* const bdtypep = basicp()) {
|
|
||||||
out += ", VerilatedVarProps::Packed()";
|
|
||||||
out += ", " + cvtToStr(bdtypep->left());
|
|
||||||
out += ", " + cvtToStr(bdtypep->right());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ulims.empty()) {
|
if (!ulims.empty()) {
|
||||||
out += ", VerilatedVarProps::Unpacked()";
|
out += ", VerilatedVarProps::Unpacked{}";
|
||||||
out += ", " + cvtToStr(ulims.size() / 2);
|
out += ", " + cvtToStr(ulims.size() / 2);
|
||||||
out += ", " + propName + "__ulims";
|
out += ", " + propName + "__ulims";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!plims.empty()) {
|
||||||
|
out += ", VerilatedVarProps::Packed{}";
|
||||||
|
out += ", " + cvtToStr(plims.size() / 2);
|
||||||
|
out += ", " + propName + "__plims";
|
||||||
|
}
|
||||||
|
|
||||||
out += ");\n";
|
out += ");\n";
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
@@ -1760,7 +1787,7 @@ void AstClocking::dumpJson(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstDisplay::dump(std::ostream& str) const {
|
void AstDisplay::dump(std::ostream& str) const {
|
||||||
this->AstNodeStmt::dump(str);
|
this->AstNodeStmt::dump(str);
|
||||||
// str << " " << displayType().ascii();
|
str << " [" << displayType().ascii() << "]";
|
||||||
}
|
}
|
||||||
void AstDisplay::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstDisplay::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
void AstEnumDType::dump(std::ostream& str) const {
|
void AstEnumDType::dump(std::ostream& str) const {
|
||||||
@@ -1923,6 +1950,20 @@ void AstJumpLabel::dump(std::ostream& str) const {
|
|||||||
}
|
}
|
||||||
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
void AstJumpLabel::dumpJson(std::ostream& str) const { dumpJsonGen(str); }
|
||||||
|
|
||||||
|
void AstMemberDType::dump(std::ostream& str) const {
|
||||||
|
this->AstNodeDType::dump(str);
|
||||||
|
if (isConstrainedRand()) str << " [CONSTRAINEDRAND]";
|
||||||
|
if (name() != "") str << " name=" << name();
|
||||||
|
if (tag() != "") str << " tag=" << tag();
|
||||||
|
}
|
||||||
|
|
||||||
|
void AstMemberDType::dumpJson(std::ostream& str) const {
|
||||||
|
dumpJsonBoolFunc(str, isConstrainedRand);
|
||||||
|
dumpJsonStrFunc(str, name);
|
||||||
|
dumpJsonStrFunc(str, tag);
|
||||||
|
dumpJsonGen(str);
|
||||||
|
}
|
||||||
|
|
||||||
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
void AstMemberDType::dumpSmall(std::ostream& str) const {
|
||||||
this->AstNodeDType::dumpSmall(str);
|
this->AstNodeDType::dumpSmall(str);
|
||||||
str << "member";
|
str << "member";
|
||||||
@@ -2838,15 +2879,17 @@ void AstCFile::dumpJson(std::ostream& str) const {
|
|||||||
void AstCFunc::dump(std::ostream& str) const {
|
void AstCFunc::dump(std::ostream& str) const {
|
||||||
this->AstNode::dump(str);
|
this->AstNode::dump(str);
|
||||||
if (slow()) str << " [SLOW]";
|
if (slow()) str << " [SLOW]";
|
||||||
if (dpiPure()) str << " [DPIPURE]";
|
|
||||||
if (isStatic()) str << " [STATIC]";
|
if (isStatic()) str << " [STATIC]";
|
||||||
|
if (dpiContext()) str << " [DPICTX]";
|
||||||
if (dpiExportDispatcher()) str << " [DPIED]";
|
if (dpiExportDispatcher()) str << " [DPIED]";
|
||||||
if (dpiExportImpl()) str << " [DPIEI]";
|
if (dpiExportImpl()) str << " [DPIEI]";
|
||||||
if (dpiImportPrototype()) str << " [DPIIP]";
|
if (dpiImportPrototype()) str << " [DPIIP]";
|
||||||
if (dpiImportWrapper()) str << " [DPIIW]";
|
if (dpiImportWrapper()) str << " [DPIIW]";
|
||||||
if (dpiContext()) str << " [DPICTX]";
|
if (dpiPure()) str << " [DPIPURE]";
|
||||||
if (isConstructor()) str << " [CTOR]";
|
if (isConstructor()) str << " [CTOR]";
|
||||||
if (isDestructor()) str << " [DTOR]";
|
if (isDestructor()) str << " [DTOR]";
|
||||||
|
if (isMethod()) str << " [METHOD]";
|
||||||
|
if (isLoose()) str << " [LOOSE]";
|
||||||
if (isVirtual()) str << " [VIRT]";
|
if (isVirtual()) str << " [VIRT]";
|
||||||
if (isCoroutine()) str << " [CORO]";
|
if (isCoroutine()) str << " [CORO]";
|
||||||
if (needProcess()) str << " [NPRC]";
|
if (needProcess()) str << " [NPRC]";
|
||||||
|
|||||||
@@ -148,6 +148,18 @@ class BeginVisitor final : public VNVisitor {
|
|||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
m_modp = nodep;
|
m_modp = nodep;
|
||||||
|
// Rename it (e.g. class under a generate)
|
||||||
|
if (m_unnamedScope != "") {
|
||||||
|
nodep->name(dot(m_unnamedScope, nodep->name()));
|
||||||
|
UINFO(8, " rename to " << nodep->name() << endl);
|
||||||
|
m_statep->userMarkChanged(nodep);
|
||||||
|
}
|
||||||
|
VL_RESTORER(m_displayScope);
|
||||||
|
VL_RESTORER(m_namedScope);
|
||||||
|
VL_RESTORER(m_unnamedScope);
|
||||||
|
m_displayScope = "";
|
||||||
|
m_namedScope = "";
|
||||||
|
m_unnamedScope = "";
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
|
|||||||
@@ -62,6 +62,7 @@ class V3CCtorsBuilder final {
|
|||||||
AstCFunc* const funcp = new AstCFunc{m_modp->fileline(), funcName, nullptr, "void"};
|
AstCFunc* const funcp = new AstCFunc{m_modp->fileline(), funcName, nullptr, "void"};
|
||||||
funcp->isStatic(false);
|
funcp->isStatic(false);
|
||||||
funcp->isLoose(!m_type.isClass());
|
funcp->isLoose(!m_type.isClass());
|
||||||
|
funcp->keepIfEmpty(true); // TODO relax
|
||||||
funcp->declPrivate(true);
|
funcp->declPrivate(true);
|
||||||
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
|
funcp->slow(!m_type.isClass()); // Only classes construct on fast path
|
||||||
string preventUnusedStmt;
|
string preventUnusedStmt;
|
||||||
@@ -210,6 +211,7 @@ void V3CCtors::evalAsserts() {
|
|||||||
funcp->declPrivate(true);
|
funcp->declPrivate(true);
|
||||||
funcp->isStatic(false);
|
funcp->isStatic(false);
|
||||||
funcp->isLoose(true);
|
funcp->isLoose(true);
|
||||||
|
funcp->keepIfEmpty(true);
|
||||||
funcp->slow(false);
|
funcp->slow(false);
|
||||||
funcp->ifdef("VL_DEBUG");
|
funcp->ifdef("VL_DEBUG");
|
||||||
modp->addStmtsp(funcp);
|
modp->addStmtsp(funcp);
|
||||||
|
|||||||
+25
-1
@@ -533,11 +533,13 @@ public:
|
|||||||
// Resolve modules and files in the design
|
// Resolve modules and files in the design
|
||||||
|
|
||||||
class V3ConfigResolver final {
|
class V3ConfigResolver final {
|
||||||
|
enum ProfileDataMode : uint8_t { NONE = 0, MTASK = 1, HIER_DPI = 2 };
|
||||||
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
|
V3ConfigModuleResolver m_modules; // Access to module names (with wildcards)
|
||||||
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
|
V3ConfigFileResolver m_files; // Access to file names (with wildcards)
|
||||||
V3ConfigScopeTraceResolver m_scopeTraces; // Regexp to trace enables
|
V3ConfigScopeTraceResolver m_scopeTraces; // Regexp to trace enables
|
||||||
std::unordered_map<string, std::unordered_map<string, uint64_t>>
|
std::unordered_map<string, std::unordered_map<string, uint64_t>>
|
||||||
m_profileData; // Access to profile_data records
|
m_profileData; // Access to profile_data records
|
||||||
|
uint8_t m_mode = NONE;
|
||||||
FileLine* m_profileFileLine = nullptr;
|
FileLine* m_profileFileLine = nullptr;
|
||||||
|
|
||||||
V3ConfigResolver() = default;
|
V3ConfigResolver() = default;
|
||||||
@@ -552,10 +554,21 @@ public:
|
|||||||
V3ConfigFileResolver& files() { return m_files; }
|
V3ConfigFileResolver& files() { return m_files; }
|
||||||
V3ConfigScopeTraceResolver& scopeTraces() { return m_scopeTraces; }
|
V3ConfigScopeTraceResolver& scopeTraces() { return m_scopeTraces; }
|
||||||
|
|
||||||
void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost) {
|
void addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
|
||||||
|
// Empty key for hierarchical DPI wrapper costs.
|
||||||
|
addProfileData(fl, hierDpi, "", cost, HIER_DPI);
|
||||||
|
}
|
||||||
|
void addProfileData(FileLine* fl, const string& model, const string& key, uint64_t cost,
|
||||||
|
ProfileDataMode mode = MTASK) {
|
||||||
if (!m_profileFileLine) m_profileFileLine = fl;
|
if (!m_profileFileLine) m_profileFileLine = fl;
|
||||||
if (cost == 0) cost = 1; // Cost 0 means delete (or no data)
|
if (cost == 0) cost = 1; // Cost 0 means delete (or no data)
|
||||||
m_profileData[model][key] += cost;
|
m_profileData[model][key] += cost;
|
||||||
|
m_mode |= mode;
|
||||||
|
}
|
||||||
|
bool containsMTaskProfileData() const { return m_mode & MTASK; }
|
||||||
|
uint64_t getProfileData(const string& hierDpi) const {
|
||||||
|
// Empty key for hierarchical DPI wrapper costs.
|
||||||
|
return getProfileData(hierDpi, "");
|
||||||
}
|
}
|
||||||
uint64_t getProfileData(const string& model, const string& key) const {
|
uint64_t getProfileData(const string& model, const string& key) const {
|
||||||
const auto mit = m_profileData.find(model);
|
const auto mit = m_profileData.find(model);
|
||||||
@@ -619,6 +632,10 @@ void V3Config::addModulePragma(const string& module, VPragmaType pragma) {
|
|||||||
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
|
V3ConfigResolver::s().modules().at(module).addModulePragma(pragma);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void V3Config::addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost) {
|
||||||
|
V3ConfigResolver::s().addProfileData(fl, hierDpi, cost);
|
||||||
|
}
|
||||||
|
|
||||||
void V3Config::addProfileData(FileLine* fl, const string& model, const string& key,
|
void V3Config::addProfileData(FileLine* fl, const string& model, const string& key,
|
||||||
uint64_t cost) {
|
uint64_t cost) {
|
||||||
V3ConfigResolver::s().addProfileData(fl, model, key, cost);
|
V3ConfigResolver::s().addProfileData(fl, model, key, cost);
|
||||||
@@ -724,6 +741,9 @@ void V3Config::applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar
|
|||||||
if (vp) vp->apply(varp);
|
if (vp) vp->apply(varp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint64_t V3Config::getProfileData(const string& hierDpi) {
|
||||||
|
return V3ConfigResolver::s().getProfileData(hierDpi);
|
||||||
|
}
|
||||||
uint64_t V3Config::getProfileData(const string& model, const string& key) {
|
uint64_t V3Config::getProfileData(const string& model, const string& key) {
|
||||||
return V3ConfigResolver::s().getProfileData(model, key);
|
return V3ConfigResolver::s().getProfileData(model, key);
|
||||||
}
|
}
|
||||||
@@ -736,6 +756,10 @@ bool V3Config::getScopeTraceOn(const string& scope) {
|
|||||||
|
|
||||||
void V3Config::contentsPushText(const string& text) { return WildcardContents::pushText(text); }
|
void V3Config::contentsPushText(const string& text) { return WildcardContents::pushText(text); }
|
||||||
|
|
||||||
|
bool V3Config::containsMTaskProfileData() {
|
||||||
|
return V3ConfigResolver::s().containsMTaskProfileData();
|
||||||
|
}
|
||||||
|
|
||||||
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
|
bool V3Config::waive(FileLine* filelinep, V3ErrorCode code, const string& message) {
|
||||||
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
|
V3ConfigFile* filep = V3ConfigResolver::s().files().resolve(filelinep->filename());
|
||||||
if (!filep) return false;
|
if (!filep) return false;
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ public:
|
|||||||
const string& match);
|
const string& match);
|
||||||
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
static void addInline(FileLine* fl, const string& module, const string& ftask, bool on);
|
||||||
static void addModulePragma(const string& module, VPragmaType pragma);
|
static void addModulePragma(const string& module, VPragmaType pragma);
|
||||||
|
static void addProfileData(FileLine* fl, const string& hierDpi, uint64_t cost);
|
||||||
static void addProfileData(FileLine* fl, const string& model, const string& key,
|
static void addProfileData(FileLine* fl, const string& model, const string& key,
|
||||||
uint64_t cost);
|
uint64_t cost);
|
||||||
static void addScopeTraceOn(bool on, const string& scope, int levels);
|
static void addScopeTraceOn(bool on, const string& scope, int levels);
|
||||||
@@ -51,12 +52,15 @@ public:
|
|||||||
static void applyModule(AstNodeModule* modulep);
|
static void applyModule(AstNodeModule* modulep);
|
||||||
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
static void applyVarAttr(AstNodeModule* modulep, AstNodeFTask* ftaskp, AstVar* varp);
|
||||||
|
|
||||||
|
static uint64_t getProfileData(const string& hierDpi);
|
||||||
static uint64_t getProfileData(const string& model, const string& key);
|
static uint64_t getProfileData(const string& model, const string& key);
|
||||||
static FileLine* getProfileDataFileLine();
|
static FileLine* getProfileDataFileLine();
|
||||||
static bool getScopeTraceOn(const string& scope);
|
static bool getScopeTraceOn(const string& scope);
|
||||||
|
|
||||||
static void contentsPushText(const string& text);
|
static void contentsPushText(const string& text);
|
||||||
|
|
||||||
|
static bool containsMTaskProfileData();
|
||||||
|
|
||||||
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
|
static bool waive(FileLine* filelinep, V3ErrorCode code, const string& message);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
+24
-10
@@ -2266,6 +2266,19 @@ class ConstVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
bool replaceJumpGoNext(AstJumpGo* nodep, AstNode* abovep) {
|
||||||
|
// If JumpGo has an upper JumpBlock that is to same label, then
|
||||||
|
// code will by normal sequential operation do the JUMPGO and it
|
||||||
|
// can be removed.
|
||||||
|
if (nodep->nextp()) return false; // Label jumps other statements
|
||||||
|
AstJumpBlock* const aboveBlockp = VN_CAST(abovep, JumpBlock);
|
||||||
|
if (!aboveBlockp) return false;
|
||||||
|
if (aboveBlockp != nodep->labelp()->blockp()) return false;
|
||||||
|
if (aboveBlockp->endStmtsp() != nodep->labelp()) return false;
|
||||||
|
UINFO(4, "JUMPGO => last remove " << nodep << endl);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Boolean replacements
|
// Boolean replacements
|
||||||
bool operandBoolShift(const AstNode* nodep) {
|
bool operandBoolShift(const AstNode* nodep) {
|
||||||
@@ -3158,8 +3171,9 @@ class ConstVisitor final : public VNVisitor {
|
|||||||
nodep->condp(new AstLogAnd{lowerIfp->fileline(), condp, lowerCondp});
|
nodep->condp(new AstLogAnd{lowerIfp->fileline(), condp, lowerCondp});
|
||||||
lowerIfp->replaceWith(lowerThensp);
|
lowerIfp->replaceWith(lowerThensp);
|
||||||
VL_DO_DANGLING(pushDeletep(lowerIfp), lowerIfp);
|
VL_DO_DANGLING(pushDeletep(lowerIfp), lowerIfp);
|
||||||
} else if (operandBoolShift(nodep->condp())) {
|
} else {
|
||||||
replaceBoolShift(nodep->condp());
|
// Optimizations that don't reform the IF itself
|
||||||
|
if (operandBoolShift(nodep->condp())) replaceBoolShift(nodep->condp());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -3377,7 +3391,7 @@ class ConstVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
void visit(AstJumpGo* nodep) override {
|
void visit(AstJumpGo* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
// Jump to label where label immediately follows this go is not useful
|
// Jump to label where label immediately follows this JumpGo is not useful
|
||||||
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
if (nodep->labelp() == VN_CAST(nodep->nextp(), JumpLabel)) {
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
||||||
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
// Keep the label, might be other jumps pointing to it, gets cleaned later
|
||||||
@@ -3390,14 +3404,14 @@ class ConstVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
// If last statement in a jump label we have JumpLabel(...., JumpGo)
|
||||||
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
// Often caused by "return" in a Verilog function. The Go is pointless, remove.
|
||||||
|
if (replaceJumpGoNext(nodep, nodep->abovep())) return;
|
||||||
|
// Also optimize If with a then or else's final statement being this JumpGo
|
||||||
|
// We only do single ifs... Ideally we'd look at control flow and delete any
|
||||||
|
// Jumps where any following control flow point is the label
|
||||||
if (!nodep->nextp()) {
|
if (!nodep->nextp()) {
|
||||||
if (AstJumpBlock* const aboveBlockp = VN_CAST(nodep->abovep(), JumpBlock)) {
|
if (AstNodeIf* const aboveIfp = VN_CAST(nodep->abovep(), NodeIf)) {
|
||||||
if (aboveBlockp == nodep->labelp()->blockp()) {
|
if (!aboveIfp->nextp()) {
|
||||||
if (aboveBlockp->endStmtsp() == nodep->labelp()) {
|
if (replaceJumpGoNext(nodep, aboveIfp->abovep())) return;
|
||||||
UINFO(4, "JUMPGO => last remove " << nodep << endl);
|
|
||||||
VL_DO_DANGLING(pushDeletep(nodep->unlinkFrBack()), nodep);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+365
-12
@@ -28,6 +28,9 @@
|
|||||||
|
|
||||||
#include "V3Coverage.h"
|
#include "V3Coverage.h"
|
||||||
|
|
||||||
|
#include "V3EmitV.h"
|
||||||
|
|
||||||
|
#include <list>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
VL_DEFINE_DEBUG_FUNCTIONS;
|
VL_DEFINE_DEBUG_FUNCTIONS;
|
||||||
@@ -39,6 +42,18 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
// TYPES
|
// TYPES
|
||||||
using LinenoSet = std::set<int>;
|
using LinenoSet = std::set<int>;
|
||||||
|
|
||||||
|
struct CoverTerm final {
|
||||||
|
AstNodeExpr* m_exprp; // Expression branch term
|
||||||
|
bool m_objective; // Term objective
|
||||||
|
std::string m_emitV; // V3EmitV string for cover point comment
|
||||||
|
CoverTerm(AstNodeExpr* exprp, bool objective, const string& emitV)
|
||||||
|
: m_exprp{exprp}
|
||||||
|
, m_objective{objective}
|
||||||
|
, m_emitV(emitV) {}
|
||||||
|
};
|
||||||
|
using CoverExpr = std::deque<CoverTerm>;
|
||||||
|
using CoverExprs = std::list<CoverExpr>;
|
||||||
|
|
||||||
struct ToggleEnt final {
|
struct ToggleEnt final {
|
||||||
const string m_comment; // Comment for coverage dump
|
const string m_comment; // Comment for coverage dump
|
||||||
AstNodeExpr* m_varRefp; // How to get to this element
|
AstNodeExpr* m_varRefp; // How to get to this element
|
||||||
@@ -64,12 +79,20 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||||
&& v3Global.opt.coverageLine();
|
&& v3Global.opt.coverageLine();
|
||||||
}
|
}
|
||||||
|
bool exprCoverageOn(const AstNode* nodep) const {
|
||||||
|
return m_on && !m_inModOff && nodep->fileline()->coverageOn()
|
||||||
|
&& v3Global.opt.coverageExpr();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum Objective : uint8_t { NONE, SEEKING, ABORTED };
|
||||||
|
|
||||||
// NODE STATE
|
// NODE STATE
|
||||||
// Entire netlist:
|
// Entire netlist:
|
||||||
// AstIf::user1() -> bool. True indicates ifelse processed
|
// AstIf::user1() -> bool. True indicates ifelse processed
|
||||||
|
// AstIf::user2() -> bool. True indicates coverage-generated
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
const VNUser2InUse m_inuser2;
|
||||||
|
|
||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
int m_nextHandle = 0;
|
int m_nextHandle = 0;
|
||||||
@@ -77,6 +100,13 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
// STATE - for current visit position (use VL_RESTORER)
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
CheckState m_state; // State save-restored on each new coverage scope/block
|
CheckState m_state; // State save-restored on each new coverage scope/block
|
||||||
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
AstNodeModule* m_modp = nullptr; // Current module to add statement to
|
||||||
|
AstNode* m_exprStmtsp = nullptr; // Node to add expr coverage to
|
||||||
|
bool m_then = false; // Whether we're iterating the then or else branch
|
||||||
|
// when m_exprStmtps is an AstIf
|
||||||
|
CoverExprs m_exprs; // List of expressions that can reach objective
|
||||||
|
Objective m_seeking = NONE; // Seeking objective for expression coverage
|
||||||
|
bool m_objective = false; // Expression objective
|
||||||
|
bool m_ifCond = false; // Visiting if condition
|
||||||
bool m_inToggleOff = false; // In function/task etc
|
bool m_inToggleOff = false; // In function/task etc
|
||||||
string m_beginHier; // AstBegin hier name for user coverage points
|
string m_beginHier; // AstBegin hier name for user coverage points
|
||||||
|
|
||||||
@@ -160,7 +190,7 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
UINFO(9, "line create h" << m_state.m_handle << " " << nodep << endl);
|
UINFO(9, "line create h" << m_state.m_handle << " " << nodep << endl);
|
||||||
}
|
}
|
||||||
void lineTrack(const AstNode* nodep) {
|
void lineTrack(const AstNode* nodep) {
|
||||||
if (m_state.lineCoverageOn(nodep)
|
if (m_state.lineCoverageOn(nodep) && !m_ifCond
|
||||||
&& m_state.m_nodep->fileline()->filenameno() == nodep->fileline()->filenameno()) {
|
&& m_state.m_nodep->fileline()->filenameno() == nodep->fileline()->filenameno()) {
|
||||||
for (int lineno = nodep->fileline()->firstLineno();
|
for (int lineno = nodep->fileline()->firstLineno();
|
||||||
lineno <= nodep->fileline()->lastLineno(); ++lineno) {
|
lineno <= nodep->fileline()->lastLineno(); ++lineno) {
|
||||||
@@ -222,13 +252,36 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
|
void visit(AstNodeProcedure* nodep) override { iterateProcedure(nodep); }
|
||||||
void visit(AstWhile* nodep) override { iterateProcedure(nodep); }
|
// we can cover expressions in while loops, but the counting goes outside
|
||||||
|
// the while, see: "minimally-intelligent decision about ... clock domain"
|
||||||
|
// in the Toggle Coverage docs
|
||||||
|
void visit(AstWhile* nodep) override { iterateProcedure(nodep, false); }
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
if (!nodep->dpiImport()) iterateProcedure(nodep);
|
||||||
}
|
}
|
||||||
void iterateProcedure(AstNode* nodep) {
|
|
||||||
|
void insertProcStatement(AstNode* nodep, AstNode* stmtp) {
|
||||||
|
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
|
||||||
|
itemp->addStmtsp(stmtp);
|
||||||
|
} else if (AstIf* const itemp = VN_CAST(nodep, If)) {
|
||||||
|
if (m_then) {
|
||||||
|
itemp->addThensp(stmtp);
|
||||||
|
} else {
|
||||||
|
itemp->addElsesp(stmtp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
nodep->v3fatalSrc("Bad node type");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void iterateProcedure(AstNode* nodep, bool exprProc = true) {
|
||||||
VL_RESTORER(m_state);
|
VL_RESTORER(m_state);
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
VL_RESTORER(m_inToggleOff);
|
VL_RESTORER(m_inToggleOff);
|
||||||
|
if (exprProc) m_exprStmtsp = nodep;
|
||||||
m_inToggleOff = true;
|
m_inToggleOff = true;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
@@ -237,15 +290,7 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
AstNode* const newp
|
AstNode* const newp
|
||||||
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
= newCoverInc(nodep->fileline(), "", "v_line", "block", linesCov(m_state, nodep),
|
||||||
0, traceNameForLine(nodep, "block"));
|
0, traceNameForLine(nodep, "block"));
|
||||||
if (AstNodeProcedure* const itemp = VN_CAST(nodep, NodeProcedure)) {
|
insertProcStatement(nodep, newp);
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else if (AstNodeFTask* const itemp = VN_CAST(nodep, NodeFTask)) {
|
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else if (AstWhile* const itemp = VN_CAST(nodep, While)) {
|
|
||||||
itemp->addStmtsp(newp);
|
|
||||||
} else {
|
|
||||||
nodep->v3fatalSrc("Bad node type");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -404,6 +449,8 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
// VISITORS - LINE COVERAGE
|
// VISITORS - LINE COVERAGE
|
||||||
// Note not AstNodeIf; other types don't get covered
|
// Note not AstNodeIf; other types don't get covered
|
||||||
void visit(AstIf* nodep) override {
|
void visit(AstIf* nodep) override {
|
||||||
|
if (nodep->user2()) return;
|
||||||
|
|
||||||
UINFO(4, " IF: " << nodep << endl);
|
UINFO(4, " IF: " << nodep << endl);
|
||||||
if (m_state.m_on) {
|
if (m_state.m_on) {
|
||||||
// An else-if. When we iterate the if, use "elsif" marking
|
// An else-if. When we iterate the if, use "elsif" marking
|
||||||
@@ -422,6 +469,10 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
CheckState ifState;
|
CheckState ifState;
|
||||||
CheckState elseState;
|
CheckState elseState;
|
||||||
{
|
{
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
|
VL_RESTORER(m_then);
|
||||||
|
m_exprStmtsp = nodep;
|
||||||
|
m_then = true;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateAndNextNull(nodep->thensp());
|
iterateAndNextNull(nodep->thensp());
|
||||||
lineTrack(nodep);
|
lineTrack(nodep);
|
||||||
@@ -429,6 +480,10 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
m_state = lastState;
|
m_state = lastState;
|
||||||
{
|
{
|
||||||
|
VL_RESTORER(m_exprStmtsp);
|
||||||
|
VL_RESTORER(m_then);
|
||||||
|
m_exprStmtsp = nodep;
|
||||||
|
m_then = false;
|
||||||
createHandle(nodep);
|
createHandle(nodep);
|
||||||
iterateAndNextNull(nodep->elsesp());
|
iterateAndNextNull(nodep->elsesp());
|
||||||
elseState = m_state;
|
elseState = m_state;
|
||||||
@@ -478,6 +533,9 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
m_state = lastState;
|
m_state = lastState;
|
||||||
}
|
}
|
||||||
|
VL_RESTORER(m_ifCond);
|
||||||
|
m_ifCond = true;
|
||||||
|
iterateAndNextNull(nodep->condp());
|
||||||
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
|
UINFO(9, " done HANDLE " << m_state.m_handle << " for " << nodep << endl);
|
||||||
}
|
}
|
||||||
void visit(AstCaseItem* nodep) override {
|
void visit(AstCaseItem* nodep) override {
|
||||||
@@ -542,6 +600,301 @@ class CoverageVisitor final : public VNVisitor {
|
|||||||
lineTrack(nodep);
|
lineTrack(nodep);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void abortExprCoverage() {
|
||||||
|
// is possible to hit max while in NONE, see: exprReduce()
|
||||||
|
// if that happens we don't want to set ABORTED if it isn't already
|
||||||
|
// since that will bleed into other expressions
|
||||||
|
if (m_seeking != NONE) m_seeking = ABORTED;
|
||||||
|
m_exprs.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool checkMaxExprs(size_t additional = 0) {
|
||||||
|
if (m_seeking != ABORTED
|
||||||
|
&& static_cast<int>(m_exprs.size() + additional) <= v3Global.opt.coverageExprMax())
|
||||||
|
return false;
|
||||||
|
abortExprCoverage();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void addExprCoverInc(AstNodeExpr* nodep, int start = 0) {
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
int count = start;
|
||||||
|
for (CoverExpr& expr : m_exprs) {
|
||||||
|
const string name = "expr_" + std::to_string(count);
|
||||||
|
string comment = "(";
|
||||||
|
bool first = true;
|
||||||
|
AstNodeExpr* condp = nullptr;
|
||||||
|
for (CoverTerm& term : expr) {
|
||||||
|
comment += (first ? "" : " && ") + term.m_emitV
|
||||||
|
+ "==" + (term.m_objective ? "1" : "0");
|
||||||
|
AstNodeExpr* const clonep = term.m_exprp->cloneTree(true);
|
||||||
|
AstNodeExpr* const termp = term.m_objective ? clonep : new AstLogNot{fl, clonep};
|
||||||
|
if (condp) {
|
||||||
|
condp = new AstLogAnd{fl, condp, termp};
|
||||||
|
} else {
|
||||||
|
condp = termp;
|
||||||
|
}
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
comment += ") => ";
|
||||||
|
comment += (m_objective ? '1' : '0');
|
||||||
|
AstNode* const newp
|
||||||
|
= newCoverInc(fl, "", "v_expr", comment, "", 0, traceNameForLine(nodep, name));
|
||||||
|
UASSERT_OBJ(condp, nodep, "No terms in expression coverage branch");
|
||||||
|
AstIf* const ifp = new AstIf{fl, condp, newp, nullptr};
|
||||||
|
ifp->user2(true);
|
||||||
|
insertProcStatement(m_exprStmtsp, ifp);
|
||||||
|
++count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void coverExprs(AstNodeExpr* nodep) {
|
||||||
|
if (!m_state.exprCoverageOn(nodep) || nodep->dtypep()->width() != 1 || !m_exprStmtsp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UASSERT_OBJ(m_seeking == NONE, nodep, "recursively covering expressions is not expected");
|
||||||
|
UASSERT_OBJ(m_exprs.empty(), nodep, "unexpected expression coverage garbage");
|
||||||
|
VL_RESTORER(m_seeking);
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
VL_RESTORER(m_exprs);
|
||||||
|
|
||||||
|
m_seeking = SEEKING;
|
||||||
|
m_objective = false;
|
||||||
|
iterate(nodep);
|
||||||
|
CoverExprs falseExprs;
|
||||||
|
m_exprs.swap(falseExprs);
|
||||||
|
|
||||||
|
m_objective = true;
|
||||||
|
iterate(nodep);
|
||||||
|
if (checkMaxExprs(falseExprs.size())) return;
|
||||||
|
|
||||||
|
addExprCoverInc(nodep);
|
||||||
|
const int start = m_exprs.size();
|
||||||
|
m_objective = false;
|
||||||
|
m_exprs.swap(falseExprs);
|
||||||
|
addExprCoverInc(nodep, start);
|
||||||
|
}
|
||||||
|
|
||||||
|
void exprEither(AstNodeBiop* nodep, bool overrideObjective = false, bool lObjective = false,
|
||||||
|
bool rObjective = false) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
AstNodeExpr* const rhsp = nodep->rhsp();
|
||||||
|
|
||||||
|
if (overrideObjective) m_objective = lObjective;
|
||||||
|
iterate(lhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs lhsExprs;
|
||||||
|
m_exprs.swap(lhsExprs);
|
||||||
|
if (overrideObjective) m_objective = rObjective;
|
||||||
|
iterate(rhsp);
|
||||||
|
m_exprs.splice(m_exprs.end(), lhsExprs);
|
||||||
|
checkMaxExprs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void exprBoth(AstNodeBiop* nodep, bool overrideObjective = false, bool lObjective = false,
|
||||||
|
bool rObjective = false) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
AstNodeExpr* const rhsp = nodep->rhsp();
|
||||||
|
|
||||||
|
if (overrideObjective) m_objective = lObjective;
|
||||||
|
iterate(lhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs lhsExprs;
|
||||||
|
m_exprs.swap(lhsExprs);
|
||||||
|
if (overrideObjective) m_objective = rObjective;
|
||||||
|
iterate(rhsp);
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
CoverExprs rhsExprs;
|
||||||
|
m_exprs.swap(rhsExprs);
|
||||||
|
|
||||||
|
for (CoverExpr& l : lhsExprs) {
|
||||||
|
for (CoverExpr& r : rhsExprs) {
|
||||||
|
// array size 2 -> (false, true)
|
||||||
|
std::array<std::set<AstVar*>, 2> varps;
|
||||||
|
std::array<std::set<std::string>, 2> strs;
|
||||||
|
|
||||||
|
UASSERT_OBJ(!l.empty() && !r.empty(), nodep, "Empty coverage expression branch");
|
||||||
|
CoverExpr expr;
|
||||||
|
|
||||||
|
// Compare Vars for simple VarRefs otherwise compare stringified terms
|
||||||
|
// remove redundant terms and remove entire expression branches when
|
||||||
|
// terms conflict
|
||||||
|
// Equivalent terms which don't match on either of these criteria will
|
||||||
|
// not be flagged as redundant or impossible, however the results will
|
||||||
|
// still be valid, albeit messier
|
||||||
|
for (CoverTerm& term : l) {
|
||||||
|
if (AstVarRef* const refp = VN_CAST(term.m_exprp, VarRef)) {
|
||||||
|
varps[term.m_objective].insert(refp->varp());
|
||||||
|
} else {
|
||||||
|
strs[term.m_objective].insert(term.m_emitV);
|
||||||
|
}
|
||||||
|
expr.push_back(term);
|
||||||
|
}
|
||||||
|
bool impossible = false;
|
||||||
|
for (CoverTerm& term : r) {
|
||||||
|
bool redundant = false;
|
||||||
|
if (AstNodeVarRef* const refp = VN_CAST(term.m_exprp, NodeVarRef)) {
|
||||||
|
if (varps[term.m_objective].find(refp->varp())
|
||||||
|
!= varps[term.m_objective].end())
|
||||||
|
redundant = true;
|
||||||
|
if (varps[!term.m_objective].find(refp->varp())
|
||||||
|
!= varps[!term.m_objective].end())
|
||||||
|
impossible = true;
|
||||||
|
} else {
|
||||||
|
if (strs[term.m_objective].find(term.m_emitV)
|
||||||
|
!= strs[term.m_objective].end())
|
||||||
|
redundant = true;
|
||||||
|
if (strs[!term.m_objective].find(term.m_emitV)
|
||||||
|
!= strs[!term.m_objective].end())
|
||||||
|
impossible = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!redundant) expr.push_back(term);
|
||||||
|
}
|
||||||
|
if (!impossible) m_exprs.push_back(std::move(expr));
|
||||||
|
if (checkMaxExprs()) return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void orExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprEither(nodep);
|
||||||
|
} else {
|
||||||
|
exprBoth(nodep);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstLogOr* nodep) override { orExpr(nodep); }
|
||||||
|
void visit(AstOr* nodep) override { orExpr(nodep); }
|
||||||
|
|
||||||
|
void andExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprBoth(nodep);
|
||||||
|
} else {
|
||||||
|
exprEither(nodep);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstLogAnd* nodep) override { andExpr(nodep); }
|
||||||
|
void visit(AstAnd* nodep) override { andExpr(nodep); }
|
||||||
|
|
||||||
|
void xorExpr(AstNodeBiop* nodep) {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
for (const bool lObjective : {false, true}) {
|
||||||
|
CoverExprs prevExprs;
|
||||||
|
m_exprs.swap(prevExprs);
|
||||||
|
const bool rObjective = lObjective ^ m_objective;
|
||||||
|
exprBoth(nodep, true, lObjective, rObjective);
|
||||||
|
m_exprs.splice(m_exprs.end(), prevExprs);
|
||||||
|
if (checkMaxExprs()) break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
void visit(AstXor* nodep) override { xorExpr(nodep); }
|
||||||
|
|
||||||
|
void exprNot(AstNodeExpr* nodep) {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
m_objective = !m_objective;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstNot* nodep) override { exprNot(nodep); }
|
||||||
|
void visit(AstLogNot* nodep) override { exprNot(nodep); }
|
||||||
|
|
||||||
|
template <typename T_Oper>
|
||||||
|
void exprReduce(AstNodeUniop* nodep) {
|
||||||
|
if (m_seeking != ABORTED) {
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
AstNodeExpr* const lhsp = nodep->lhsp();
|
||||||
|
const int width = lhsp->dtypep()->width();
|
||||||
|
const size_t expected = std::is_same<T_Oper, AstXor>::value ? 0x1 << width : width + 1;
|
||||||
|
if (checkMaxExprs(expected)) return;
|
||||||
|
AstNodeExpr* unrolledp = new AstSel{fl, lhsp->cloneTree(true),
|
||||||
|
new AstConst{fl, static_cast<uint32_t>(width - 1)},
|
||||||
|
new AstConst{fl, 1}};
|
||||||
|
for (int bit = width - 2; bit >= 0; bit--) {
|
||||||
|
AstSel* const selp = new AstSel{fl, lhsp->cloneTree(true),
|
||||||
|
new AstConst{fl, static_cast<uint32_t>(bit)},
|
||||||
|
new AstConst{fl, 1}};
|
||||||
|
unrolledp = new T_Oper{fl, selp, unrolledp};
|
||||||
|
}
|
||||||
|
iterate(unrolledp);
|
||||||
|
pushDeletep(unrolledp);
|
||||||
|
} else {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstRedOr* nodep) override { exprReduce<AstOr>(nodep); }
|
||||||
|
void visit(AstRedAnd* nodep) override { exprReduce<AstAnd>(nodep); }
|
||||||
|
void visit(AstRedXor* nodep) override { exprReduce<AstXor>(nodep); }
|
||||||
|
|
||||||
|
void visit(AstLogIf* nodep) override {
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else if (m_objective) {
|
||||||
|
exprEither(nodep, true, false, true);
|
||||||
|
} else {
|
||||||
|
exprBoth(nodep, true, true, false);
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstLogEq* nodep) override {
|
||||||
|
VL_RESTORER(m_objective);
|
||||||
|
if (m_seeking == NONE) {
|
||||||
|
coverExprs(nodep);
|
||||||
|
} else {
|
||||||
|
m_objective = !m_objective;
|
||||||
|
xorExpr(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstCond* nodep) override {
|
||||||
|
if (m_seeking == NONE) coverExprs(nodep->condp());
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Lambdas not supported for expression coverage
|
||||||
|
void visit(AstWith* nodep) override {
|
||||||
|
VL_RESTORER(m_seeking);
|
||||||
|
if (m_seeking == SEEKING) abortExprCoverage();
|
||||||
|
m_seeking = ABORTED;
|
||||||
|
iterateChildren(nodep);
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
|
void visit(AstNodeExpr* nodep) override {
|
||||||
|
if (m_seeking != SEEKING) {
|
||||||
|
iterateChildren(nodep);
|
||||||
|
} else {
|
||||||
|
std::stringstream emitV;
|
||||||
|
V3EmitV::verilogForTree(nodep, emitV);
|
||||||
|
// Add new expression with a single term
|
||||||
|
CoverExpr expr;
|
||||||
|
expr.emplace_back(nodep, m_objective, emitV.str());
|
||||||
|
m_exprs.push_back(std::move(expr));
|
||||||
|
checkMaxExprs();
|
||||||
|
}
|
||||||
|
lineTrack(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS - BOTH
|
// VISITORS - BOTH
|
||||||
void visit(AstNode* nodep) override {
|
void visit(AstNode* nodep) override {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|||||||
+19
-5
@@ -62,7 +62,8 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
const bool m_elimCells; // Allow removal of Cells
|
const bool m_elimCells; // Allow removal of Cells
|
||||||
// List of all encountered to avoid another loop through tree
|
// List of all encountered to avoid another loop through tree
|
||||||
std::vector<AstVar*> m_varsp;
|
std::vector<AstVar*> m_varsp;
|
||||||
std::vector<AstNode*> m_dtypesp;
|
std::vector<AstNode*> m_dtypeElimsp; // Data types might eliminate
|
||||||
|
std::map<AstNodeDType*, AstNodeModule*> m_dtypePkgsp; // Data type's containing package
|
||||||
std::vector<AstVarScope*> m_vscsp;
|
std::vector<AstVarScope*> m_vscsp;
|
||||||
std::vector<AstScope*> m_scopesp;
|
std::vector<AstScope*> m_scopesp;
|
||||||
std::vector<AstCell*> m_cellsp;
|
std::vector<AstCell*> m_cellsp;
|
||||||
@@ -73,6 +74,7 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
// STATE - for current visit position (use VL_RESTORER)
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
bool m_inAssign = false; // Currently in an assign
|
bool m_inAssign = false; // Currently in an assign
|
||||||
|
AstNodeDType* m_curDTypep = nullptr; // Current NodeDType
|
||||||
AstNodeModule* m_modp = nullptr; // Current module
|
AstNodeModule* m_modp = nullptr; // Current module
|
||||||
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
|
AstSelLoopVars* m_selloopvarsp = nullptr; // Current loop vars
|
||||||
|
|
||||||
@@ -84,8 +86,11 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void checkAll(AstNode* nodep) {
|
void checkAll(AstNode* nodep) {
|
||||||
if (nodep != nodep->dtypep()) { // NodeDTypes reference themselves
|
if (AstNode* const subnodep = nodep->dtypep()) {
|
||||||
if (AstNode* const subnodep = nodep->dtypep()) subnodep->user1Inc();
|
if (nodep != subnodep // Not NodeDTypes reference themselves
|
||||||
|
&& m_curDTypep != subnodep) { // Not EnumItem referencing parent Enum
|
||||||
|
subnodep->user1Inc();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (AstNode* const subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
if (AstNode* const subnodep = nodep->getChildDTypep()) subnodep->user1Inc();
|
||||||
}
|
}
|
||||||
@@ -98,8 +103,9 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
&& !VN_IS(nodep, MemberDType) // Keep member names iff upper type exists
|
&& !VN_IS(nodep, MemberDType) // Keep member names iff upper type exists
|
||||||
&& !nodep->undead() // VoidDType or something Netlist points to
|
&& !nodep->undead() // VoidDType or something Netlist points to
|
||||||
) {
|
) {
|
||||||
m_dtypesp.push_back(nodep);
|
m_dtypeElimsp.push_back(nodep);
|
||||||
}
|
}
|
||||||
|
if (VN_IS(m_modp, Package) || VN_IS(m_modp, Class)) m_dtypePkgsp.emplace(nodep, m_modp);
|
||||||
if (AstNode* const subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
if (AstNode* const subnodep = nodep->virtRefDTypep()) subnodep->user1Inc();
|
||||||
if (AstNode* const subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
|
if (AstNode* const subnodep = nodep->virtRefDType2p()) subnodep->user1Inc();
|
||||||
}
|
}
|
||||||
@@ -212,6 +218,8 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
if (nodep->ifaceViaCellp()) nodep->ifaceViaCellp()->user1Inc();
|
if (nodep->ifaceViaCellp()) nodep->ifaceViaCellp()->user1Inc();
|
||||||
}
|
}
|
||||||
void visit(AstNodeDType* nodep) override {
|
void visit(AstNodeDType* nodep) override {
|
||||||
|
VL_RESTORER(m_curDTypep);
|
||||||
|
m_curDTypep = nodep;
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
checkDType(nodep);
|
checkDType(nodep);
|
||||||
checkAll(nodep);
|
checkAll(nodep);
|
||||||
@@ -442,7 +450,8 @@ class DeadVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (std::vector<AstNode*>::iterator it = m_dtypesp.begin(); it != m_dtypesp.end(); ++it) {
|
for (std::vector<AstNode*>::iterator it = m_dtypeElimsp.begin(); it != m_dtypeElimsp.end();
|
||||||
|
++it) {
|
||||||
if ((*it)->user1() == 0) {
|
if ((*it)->user1() == 0) {
|
||||||
// It's possible that there if a reference to each individual member, but
|
// It's possible that there if a reference to each individual member, but
|
||||||
// not to the dtype itself. Check and don't remove the parent dtype if
|
// not to the dtype itself. Check and don't remove the parent dtype if
|
||||||
@@ -517,6 +526,11 @@ public:
|
|||||||
vscp->varp()->user1Inc();
|
vscp->varp()->user1Inc();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// If data type has a reference in another package, then keep defining package around
|
||||||
|
for (auto& itr : m_dtypePkgsp) {
|
||||||
|
if (itr.first->user1()) itr.second->user1Inc();
|
||||||
|
}
|
||||||
|
|
||||||
deadCheckTypedefs();
|
deadCheckTypedefs();
|
||||||
deadCheckVar();
|
deadCheckVar();
|
||||||
// We only eliminate scopes when in a flattened structure
|
// We only eliminate scopes when in a flattened structure
|
||||||
|
|||||||
+27
-13
@@ -208,6 +208,7 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
// NODE STATE
|
// NODE STATE
|
||||||
// AstVar::user1() -> bool. Set true if already issued MULTIDRIVEN warning
|
// AstVar::user1() -> bool. Set true if already issued MULTIDRIVEN warning
|
||||||
// AstVarRef::user1() -> bool. Set true if target of NBA
|
// AstVarRef::user1() -> bool. Set true if target of NBA
|
||||||
|
// AstAssignDly::user1() -> bool. Set true if already visited
|
||||||
// AstNodeModule::user1p() -> std::unorded_map<std::string, AstVar*> temp map via m_varMap
|
// AstNodeModule::user1p() -> std::unorded_map<std::string, AstVar*> temp map via m_varMap
|
||||||
// AstVarScope::user1p() -> VarScopeInfo via m_vscpInfo
|
// AstVarScope::user1p() -> VarScopeInfo via m_vscpInfo
|
||||||
// AstVarScope::user2p() -> AstVarRef*: First write reference to the Variable
|
// AstVarScope::user2p() -> AstVarRef*: First write reference to the Variable
|
||||||
@@ -909,6 +910,9 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
}
|
}
|
||||||
void visit(AstAssignDly* nodep) override {
|
void visit(AstAssignDly* nodep) override {
|
||||||
|
// Prevent double processing due to AstExprStmt being moved before this node
|
||||||
|
if (nodep->user1SetOnce()) return;
|
||||||
|
|
||||||
if (m_cfuncp) {
|
if (m_cfuncp) {
|
||||||
if (!v3Global.rootp()->nbaEventp()) {
|
if (!v3Global.rootp()->nbaEventp()) {
|
||||||
nodep->v3warn(
|
nodep->v3warn(
|
||||||
@@ -922,21 +926,31 @@ class DelayedVisitor final : public VNVisitor {
|
|||||||
UASSERT_OBJ(m_inSuspendableOrFork || m_activep->hasClocked(), nodep,
|
UASSERT_OBJ(m_inSuspendableOrFork || m_activep->hasClocked(), nodep,
|
||||||
"<= assignment in non-clocked block, should have been converted in V3Active");
|
"<= assignment in non-clocked block, should have been converted in V3Active");
|
||||||
|
|
||||||
// Grab the reference to the target of the NBA
|
// Grab the reference to the target of the NBA, also lift ExprStmt statements on the LHS
|
||||||
VL_RESTORER(m_currNbaLhsRefp);
|
VL_RESTORER(m_currNbaLhsRefp);
|
||||||
UASSERT_OBJ(!m_currNbaLhsRefp, nodep, "NBAs should not nest");
|
UASSERT_OBJ(!m_currNbaLhsRefp, nodep, "NBAs should not nest");
|
||||||
nodep->lhsp()->foreach([&](AstVarRef* nodep) {
|
nodep->lhsp()->foreach([&](AstNode* currp) {
|
||||||
// Ignore reads (e.g.: '_[*here*] <= _')
|
if (AstExprStmt* const exprp = VN_CAST(currp, ExprStmt)) {
|
||||||
if (nodep->access().isReadOnly()) return;
|
// Move statements before the NBA
|
||||||
// A RW ref on the LHS (e.g.: '_[preInc(*here*)] <= _') is asking for trouble at this
|
nodep->addHereThisAsNext(exprp->stmtsp()->unlinkFrBackWithNext());
|
||||||
// point. These should be lowered in an earlier pass into sequenced temporaries.
|
// Replace with result
|
||||||
UASSERT_OBJ(!nodep->access().isRW(), nodep, "RW ref on LHS of NBA");
|
currp->replaceWith(exprp->resultp()->unlinkFrBack());
|
||||||
// Multiple target variables
|
// Get rid of the AstExprStmt
|
||||||
// (e.g.: '{*here*, *and here*} <= _',or '*here*[*and here* = _] <= _').
|
VL_DO_DANGLING(pushDeletep(currp), currp);
|
||||||
// These should be lowered in an earlier pass into sequenced statements.
|
} else if (AstVarRef* const refp = VN_CAST(currp, VarRef)) {
|
||||||
UASSERT_OBJ(!m_currNbaLhsRefp, nodep, "Multiple Write refs on LHS of NBA");
|
// Ignore reads (e.g.: '_[*here*] <= _')
|
||||||
// Hold on to it
|
if (refp->access().isReadOnly()) return;
|
||||||
m_currNbaLhsRefp = nodep;
|
// A RW ref on the LHS (e.g.: '_[preInc(*here*)] <= _') is asking for trouble at
|
||||||
|
// this point. These should be lowered in an earlier pass into sequenced
|
||||||
|
// temporaries.
|
||||||
|
UASSERT_OBJ(!refp->access().isRW(), refp, "RW ref on LHS of NBA");
|
||||||
|
// Multiple target variables
|
||||||
|
// (e.g.: '{*here*, *and here*} <= _',or '*here*[*and here* = _] <= _').
|
||||||
|
// These should be lowered in an earlier pass into sequenced statements.
|
||||||
|
UASSERT_OBJ(!m_currNbaLhsRefp, refp, "Multiple Write refs on LHS of NBA");
|
||||||
|
// Hold on to it
|
||||||
|
m_currNbaLhsRefp = refp;
|
||||||
|
}
|
||||||
});
|
});
|
||||||
// The target variable of the NBA (there can only be one per NBA at this point)
|
// The target variable of the NBA (there can only be one per NBA at this point)
|
||||||
AstVarScope* const vscp = m_currNbaLhsRefp->varScopep();
|
AstVarScope* const vscp = m_currNbaLhsRefp->varScopep();
|
||||||
|
|||||||
+5
-1
@@ -171,7 +171,11 @@ void EmitCBaseVisitorConst::emitCFuncDecl(const AstCFunc* funcp, const AstNodeMo
|
|||||||
putns(funcp, "virtual ");
|
putns(funcp, "virtual ");
|
||||||
}
|
}
|
||||||
emitCFuncHeader(funcp, modp, /* withScope: */ false);
|
emitCFuncHeader(funcp, modp, /* withScope: */ false);
|
||||||
putns(funcp, ";\n");
|
if (funcp->emptyBody() && !funcp->isLoose() && !cLinkage) {
|
||||||
|
putns(funcp, " {}\n");
|
||||||
|
} else {
|
||||||
|
putns(funcp, ";\n");
|
||||||
|
}
|
||||||
if (!funcp->ifdef().empty()) putns(funcp, "#endif // " + funcp->ifdef() + "\n");
|
if (!funcp->ifdef().empty()) putns(funcp, "#endif // " + funcp->ifdef() + "\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+9
-6
@@ -456,9 +456,7 @@ void EmitCFunc::emitDereference(AstNode* nodep, const string& pointer) {
|
|||||||
|
|
||||||
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
|
void EmitCFunc::emitCvtPackStr(AstNode* nodep) {
|
||||||
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
if (const AstConst* const constp = VN_CAST(nodep, Const)) {
|
||||||
putnbs(nodep, "std::string{");
|
emitConstantString(constp);
|
||||||
putsQuoted(constp->num().toString());
|
|
||||||
puts("}");
|
|
||||||
} else if (VN_IS(nodep->dtypep(), StreamDType)) {
|
} else if (VN_IS(nodep->dtypep(), StreamDType)) {
|
||||||
putnbs(nodep, "VL_CVT_PACK_STR_ND(");
|
putnbs(nodep, "VL_CVT_PACK_STR_ND(");
|
||||||
iterateAndNextConstNull(nodep);
|
iterateAndNextConstNull(nodep);
|
||||||
@@ -494,9 +492,7 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
|||||||
} else if (nodep->num().isFourState()) {
|
} else if (nodep->num().isFourState()) {
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: 4-state numbers in this context");
|
||||||
} else if (nodep->num().isString()) {
|
} else if (nodep->num().isString()) {
|
||||||
putnbs(nodep, "std::string{");
|
emitConstantString(nodep);
|
||||||
putsQuoted(nodep->num().toString());
|
|
||||||
puts("}");
|
|
||||||
} else if (nodep->isWide()) {
|
} else if (nodep->isWide()) {
|
||||||
int upWidth = nodep->num().widthMin();
|
int upWidth = nodep->num().widthMin();
|
||||||
int chunks = 0;
|
int chunks = 0;
|
||||||
@@ -594,6 +590,13 @@ void EmitCFunc::emitConstant(AstConst* nodep, AstVarRef* assigntop, const string
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void EmitCFunc::emitConstantString(const AstConst* nodep) {
|
||||||
|
putnbs(nodep, "std::string{");
|
||||||
|
const string str = nodep->num().toString();
|
||||||
|
if (!str.empty()) putsQuoted(str);
|
||||||
|
puts("}");
|
||||||
|
}
|
||||||
|
|
||||||
void EmitCFunc::emitSetVarConstant(const string& assignString, AstConst* constp) {
|
void EmitCFunc::emitSetVarConstant(const string& assignString, AstConst* constp) {
|
||||||
if (!constp->isWide()) {
|
if (!constp->isWide()) {
|
||||||
puts(assignString);
|
puts(assignString);
|
||||||
|
|||||||
+24
-21
@@ -208,6 +208,7 @@ public:
|
|||||||
void emitCvtPackStr(AstNode* nodep);
|
void emitCvtPackStr(AstNode* nodep);
|
||||||
void emitCvtWideArray(AstNode* nodep, AstNode* fromp);
|
void emitCvtWideArray(AstNode* nodep, AstNode* fromp);
|
||||||
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString);
|
void emitConstant(AstConst* nodep, AstVarRef* assigntop, const string& assignString);
|
||||||
|
void emitConstantString(const AstConst* nodep);
|
||||||
void emitSetVarConstant(const string& assignString, AstConst* constp);
|
void emitSetVarConstant(const string& assignString, AstConst* constp);
|
||||||
void emitVarReset(AstVar* varp);
|
void emitVarReset(AstVar* varp);
|
||||||
string emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
|
string emitVarResetRecurse(const AstVar* varp, const string& varNameProtected,
|
||||||
@@ -279,6 +280,7 @@ public:
|
|||||||
// VISITORS
|
// VISITORS
|
||||||
using EmitCConstInit::visit;
|
using EmitCConstInit::visit;
|
||||||
void visit(AstCFunc* nodep) override {
|
void visit(AstCFunc* nodep) override {
|
||||||
|
if (nodep->emptyBody() && !nodep->isLoose()) return;
|
||||||
VL_RESTORER(m_useSelfForThis);
|
VL_RESTORER(m_useSelfForThis);
|
||||||
VL_RESTORER(m_cfuncp);
|
VL_RESTORER(m_cfuncp);
|
||||||
VL_RESTORER(m_instantiatesOwnProcess)
|
VL_RESTORER(m_instantiatesOwnProcess)
|
||||||
@@ -303,15 +305,6 @@ public:
|
|||||||
}
|
}
|
||||||
puts(" {\n");
|
puts(" {\n");
|
||||||
|
|
||||||
if (nodep->isLoose()) {
|
|
||||||
m_lazyDecls.declared(nodep); // Defined here, so no longer needs declaration
|
|
||||||
if (!nodep->isStatic()) { // Standard prologue
|
|
||||||
m_useSelfForThis = true;
|
|
||||||
puts("(void)vlSelf; // Prevent unused variable warning\n");
|
|
||||||
if (!VN_IS(m_modp, Class)) puts(symClassAssign());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// "+" in the debug indicates a print from the model
|
// "+" in the debug indicates a print from the model
|
||||||
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ ");
|
puts("VL_DEBUG_IF(VL_DBG_MSGF(\"+ ");
|
||||||
for (int i = 0; i < m_modp->level(); ++i) puts(" ");
|
for (int i = 0; i < m_modp->level(); ++i) puts(" ");
|
||||||
@@ -319,6 +312,18 @@ public:
|
|||||||
puts(nodep->isLoose() ? "__" : "::");
|
puts(nodep->isLoose() ? "__" : "::");
|
||||||
puts(nodep->nameProtect() + "\\n\"); );\n");
|
puts(nodep->nameProtect() + "\\n\"); );\n");
|
||||||
|
|
||||||
|
if (nodep->isLoose()) {
|
||||||
|
m_lazyDecls.declared(nodep); // Defined here, so no longer needs declaration
|
||||||
|
if (!nodep->isStatic()) { // Standard prologue
|
||||||
|
m_useSelfForThis = true;
|
||||||
|
if (!VN_IS(m_modp, Class)) {
|
||||||
|
puts(symClassAssign()); // Uses vlSelf
|
||||||
|
} else {
|
||||||
|
puts("(void)vlSelf; // Prevent unused variable warning\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Instantiate a process class if it's going to be needed somewhere later
|
// Instantiate a process class if it's going to be needed somewhere later
|
||||||
nodep->forall([&](const AstNodeCCall* ccallp) -> bool {
|
nodep->forall([&](const AstNodeCCall* ccallp) -> bool {
|
||||||
if (ccallp->funcp()->needProcess()
|
if (ccallp->funcp()->needProcess()
|
||||||
@@ -344,16 +349,14 @@ public:
|
|||||||
|
|
||||||
if (m_useSelfForThis) {
|
if (m_useSelfForThis) {
|
||||||
m_usevlSelfRef = true;
|
m_usevlSelfRef = true;
|
||||||
/*
|
// Using reference to the vlSelf pointer will help the C++
|
||||||
* Using reference to the vlSelf pointer will help the C++
|
// compiler to have dereferenceable hints, which can help to
|
||||||
* compiler to have dereferenceable hints, which can help to
|
// reduce the need for branch instructions in the generated
|
||||||
* reduce the need for branch instructions in the generated
|
// code to allow the compiler to generate load store after the
|
||||||
* code to allow the compiler to generate load store after the
|
// if condition (including short-circuit evaluation)
|
||||||
* if condition (including short-circuit evaluation)
|
// speculatively and also reduce the data cache pollution when
|
||||||
* speculatively and also reduce the data cache pollution when
|
// executing in the wrong path to make verilator-generated code
|
||||||
* executing in the wrong path to make verilator-generated code
|
// run faster.
|
||||||
* run faster.
|
|
||||||
*/
|
|
||||||
puts("auto& vlSelfRef = std::ref(*vlSelf).get();\n");
|
puts("auto& vlSelfRef = std::ref(*vlSelf).get();\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -968,10 +971,10 @@ public:
|
|||||||
putns(nodep, "if (");
|
putns(nodep, "if (");
|
||||||
if (!nodep->branchPred().unknown()) {
|
if (!nodep->branchPred().unknown()) {
|
||||||
puts(nodep->branchPred().ascii());
|
puts(nodep->branchPred().ascii());
|
||||||
puts("(");
|
puts("(("); // Two parens, so that VL_UNLIKELY((class<foo,bar>)) works
|
||||||
}
|
}
|
||||||
iterateAndNextConstNull(nodep->condp());
|
iterateAndNextConstNull(nodep->condp());
|
||||||
if (!nodep->branchPred().unknown()) puts(")");
|
if (!nodep->branchPred().unknown()) puts("))");
|
||||||
puts(") {\n");
|
puts(") {\n");
|
||||||
iterateAndNextConstNull(nodep->thensp());
|
iterateAndNextConstNull(nodep->thensp());
|
||||||
puts("}");
|
puts("}");
|
||||||
|
|||||||
@@ -240,6 +240,45 @@ class EmitCHeader final : public EmitCConstInit {
|
|||||||
emitUnpackedUOrSBody(sdtypep);
|
emitUnpackedUOrSBody(sdtypep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
enum class AttributeType { Width, Dimension };
|
||||||
|
// Get member attribute based on type
|
||||||
|
int getNodeAttribute(const AstMemberDType* itemp, AttributeType type) {
|
||||||
|
const bool isArrayType
|
||||||
|
= VN_IS(itemp->dtypep(), UnpackArrayDType) || VN_IS(itemp->dtypep(), DynArrayDType)
|
||||||
|
|| VN_IS(itemp->dtypep(), QueueDType) || VN_IS(itemp->dtypep(), AssocArrayDType);
|
||||||
|
switch (type) {
|
||||||
|
case AttributeType::Width: {
|
||||||
|
if (isArrayType) {
|
||||||
|
// For arrays, get innermost element width
|
||||||
|
AstNodeDType* dtype = itemp->dtypep();
|
||||||
|
while (dtype->subDTypep()) dtype = dtype->subDTypep();
|
||||||
|
return dtype->width();
|
||||||
|
}
|
||||||
|
return itemp->width();
|
||||||
|
}
|
||||||
|
case AttributeType::Dimension: {
|
||||||
|
// Return array dimension or 0 for non-arrays
|
||||||
|
return isArrayType ? itemp->dtypep()->dimensions(true).second : 0;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
template <AttributeType T>
|
||||||
|
void emitMemberVector(const AstNodeUOrStructDType* sdtypep) {
|
||||||
|
puts("return {");
|
||||||
|
bool needComma = false;
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (!itemp->isConstrainedRand()) continue;
|
||||||
|
// Comma handling: add before element except first
|
||||||
|
if (needComma) puts(",\n");
|
||||||
|
putns(itemp, std::to_string(getNodeAttribute(itemp, T)));
|
||||||
|
needComma = true;
|
||||||
|
}
|
||||||
|
puts("};\n}\n");
|
||||||
|
}
|
||||||
void emitUnpackedUOrSBody(AstNodeUOrStructDType* sdtypep) {
|
void emitUnpackedUOrSBody(AstNodeUOrStructDType* sdtypep) {
|
||||||
putns(sdtypep, sdtypep->verilogKwd()); // "struct"/"union"
|
putns(sdtypep, sdtypep->verilogKwd()); // "struct"/"union"
|
||||||
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
|
puts(" " + EmitCBase::prefixNameProtect(sdtypep) + " {\n");
|
||||||
@@ -248,7 +287,51 @@ class EmitCHeader final : public EmitCConstInit {
|
|||||||
putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
putns(itemp, itemp->dtypep()->cType(itemp->nameProtect(), false, false));
|
||||||
puts(";\n");
|
puts(";\n");
|
||||||
}
|
}
|
||||||
|
// Three helper functions for struct constrained randomization:
|
||||||
|
// - memberNames: Get member names
|
||||||
|
// - getMembers: Access member references
|
||||||
|
// - memberIndices: Retrieve member indices
|
||||||
|
// - memberWidth: Retrieve member width
|
||||||
|
// - memberDimension: Retrieve member dimension
|
||||||
|
if (sdtypep->isConstrainedRand()) {
|
||||||
|
putns(sdtypep, "\nstd::vector<std::string> memberNames(void) const {\n");
|
||||||
|
puts("return {");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand()) putns(itemp, "\"" + itemp->shortName() + "\"");
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(",\n");
|
||||||
|
}
|
||||||
|
puts("};\n}\n");
|
||||||
|
|
||||||
|
putns(sdtypep, "\nstd::vector<int> memberWidth(void) const {\n");
|
||||||
|
emitMemberVector<AttributeType::Width>(sdtypep);
|
||||||
|
|
||||||
|
putns(sdtypep, "\nstd::vector<int> memberDimension(void) const {\n");
|
||||||
|
emitMemberVector<AttributeType::Dimension>(sdtypep);
|
||||||
|
|
||||||
|
putns(sdtypep, "\nauto memberIndices(void) const {\n");
|
||||||
|
puts("return std::index_sequence_for<");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand())
|
||||||
|
putns(itemp, itemp->dtypep()->cType("", false, false));
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(",\n");
|
||||||
|
}
|
||||||
|
puts(">{};\n}\n");
|
||||||
|
|
||||||
|
putns(sdtypep, "\ntemplate <typename T>");
|
||||||
|
putns(sdtypep, "\nauto getMembers(T& obj) {\n");
|
||||||
|
puts("return std::tie(");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp->isConstrainedRand()) putns(itemp, "obj." + itemp->nameProtect());
|
||||||
|
if (itemp->nextp() && VN_AS(itemp->nextp(), MemberDType)->isConstrainedRand())
|
||||||
|
puts(", ");
|
||||||
|
}
|
||||||
|
puts(");\n}\n");
|
||||||
|
}
|
||||||
putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
|
putns(sdtypep, "\nbool operator==(const " + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
+ "& rhs) const {\n");
|
+ "& rhs) const {\n");
|
||||||
puts("return ");
|
puts("return ");
|
||||||
@@ -262,7 +345,27 @@ class EmitCHeader final : public EmitCConstInit {
|
|||||||
putns(sdtypep, "bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep)
|
putns(sdtypep, "bool operator!=(const " + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
+ "& rhs) const {\n");
|
+ "& rhs) const {\n");
|
||||||
puts("return !(*this == rhs);\n}\n");
|
puts("return !(*this == rhs);\n}\n");
|
||||||
|
putns(sdtypep, "\nbool operator<(const " + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
|
+ "& rhs) const {\n");
|
||||||
|
puts("return ");
|
||||||
|
puts("std::tie(");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp != sdtypep->membersp()) puts(", ");
|
||||||
|
putns(itemp, itemp->nameProtect());
|
||||||
|
}
|
||||||
|
puts(")\n < std::tie(");
|
||||||
|
for (const AstMemberDType* itemp = sdtypep->membersp(); itemp;
|
||||||
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
if (itemp != sdtypep->membersp()) puts(", ");
|
||||||
|
putns(itemp, "rhs." + itemp->nameProtect());
|
||||||
|
}
|
||||||
|
puts(");\n");
|
||||||
|
puts("}\n");
|
||||||
puts("};\n");
|
puts("};\n");
|
||||||
|
puts("template <>\n");
|
||||||
|
putns(sdtypep, "struct VlIsCustomStruct<" + EmitCBase::prefixNameProtect(sdtypep)
|
||||||
|
+ "> : public std::true_type {};\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// getfunc: VL_ASSIGNSEL_XX(rbits, obits, off, lhsdata, rhsdata);
|
// getfunc: VL_ASSIGNSEL_XX(rbits, obits, off, lhsdata, rhsdata);
|
||||||
|
|||||||
+39
-39
@@ -106,7 +106,8 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
std::vector<ModVarPair> m_modVars; // Each public {mod,var}
|
||||||
std::map<const std::string, ScopeFuncData> m_scopeFuncs; // Each {scope,dpi-export-func}
|
std::map<const std::string, ScopeFuncData> m_scopeFuncs; // Each {scope,dpi-export-func}
|
||||||
std::map<const std::string, ScopeVarData> m_scopeVars; // Each {scope,public-var}
|
std::map<const std::string, ScopeVarData> m_scopeVars; // Each {scope,public-var}
|
||||||
ScopeNames m_scopeNames; // Each unique AstScopeName
|
ScopeNames m_scopeNames; // Each unique AstScopeName. Dpi scopes added later
|
||||||
|
ScopeNames m_dpiScopeNames; // Each unique AstScopeName for DPI export
|
||||||
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
ScopeNames m_vpiScopeCandidates; // All scopes for VPI
|
||||||
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
|
ScopeNameHierarchy m_vpiScopeHierarchy; // The actual hierarchy of scopes
|
||||||
int m_coverBins = 0; // Coverage bin number
|
int m_coverBins = 0; // Coverage bin number
|
||||||
@@ -181,7 +182,6 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
/// Then add/update entry in m_scopeNames if not already there
|
/// Then add/update entry in m_scopeNames if not already there
|
||||||
void varHierarchyScopes(string scp) {
|
void varHierarchyScopes(string scp) {
|
||||||
|
|
||||||
// we want no result to be -1, so use ints
|
|
||||||
string::size_type prd_pos = scp.rfind('.');
|
string::size_type prd_pos = scp.rfind('.');
|
||||||
string::size_type dot_pos = scp.rfind("__DOT__");
|
string::size_type dot_pos = scp.rfind("__DOT__");
|
||||||
|
|
||||||
@@ -195,7 +195,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// resize and advance pointers
|
// resize and advance pointers
|
||||||
if (prd_pos < dot_pos && dot_pos != string::npos) {
|
if ((prd_pos < dot_pos || prd_pos == string::npos) && dot_pos != string::npos) {
|
||||||
scp.resize(dot_pos);
|
scp.resize(dot_pos);
|
||||||
dot_pos = scp.rfind("__DOT__");
|
dot_pos = scp.rfind("__DOT__");
|
||||||
} else {
|
} else {
|
||||||
@@ -209,7 +209,7 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
void varsExpand() {
|
void varsExpand() {
|
||||||
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
|
// We didn't have all m_scopes loaded when we encountered variables, so expand them now
|
||||||
// It would be less code if each module inserted its own variables.
|
// It would be less code if each module inserted its own variables.
|
||||||
// Someday. For now public isn't common.
|
// Someday.
|
||||||
for (std::vector<ScopeModPair>::iterator itsc = m_scopes.begin(); itsc != m_scopes.end();
|
for (std::vector<ScopeModPair>::iterator itsc = m_scopes.begin(); itsc != m_scopes.end();
|
||||||
++itsc) {
|
++itsc) {
|
||||||
AstScope* const scopep = itsc->first;
|
AstScope* const scopep = itsc->first;
|
||||||
@@ -283,6 +283,15 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
|
|
||||||
if (v3Global.opt.vpi()) buildVpiHierarchy();
|
if (v3Global.opt.vpi()) buildVpiHierarchy();
|
||||||
|
|
||||||
|
if (v3Global.dpi()) {
|
||||||
|
// add dpi scopes to m_scopeNames if not already there
|
||||||
|
for (const auto& scp : m_dpiScopeNames) {
|
||||||
|
if (m_scopeNames.find(scp.first) == m_scopeNames.end()) {
|
||||||
|
m_scopeNames.emplace(scp.first, scp.second);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Sort by names, so line/process order matters less
|
// Sort by names, so line/process order matters less
|
||||||
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
|
||||||
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
|
stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
|
||||||
@@ -331,7 +340,8 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
const int timeunit = m_modp->timeunit().powerOfTen();
|
const int timeunit = m_modp->timeunit().powerOfTen();
|
||||||
m_vpiScopeCandidates.emplace(scopeSymString(nodep->name()),
|
m_vpiScopeCandidates.emplace(scopeSymString(nodep->name()),
|
||||||
ScopeData{nodep, scopeSymString(nodep->name()),
|
ScopeData{nodep, scopeSymString(nodep->name()),
|
||||||
name_pretty, "<null>", timeunit, type});
|
name_pretty, nodep->modp()->origName(),
|
||||||
|
timeunit, type});
|
||||||
}
|
}
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
}
|
}
|
||||||
@@ -340,26 +350,27 @@ class EmitCSyms final : EmitCBaseVisitorConst {
|
|||||||
// UINFO(9, "scnameins sp " << nodep->name() << " sp " << nodep->scopePrettySymName()
|
// UINFO(9, "scnameins sp " << nodep->name() << " sp " << nodep->scopePrettySymName()
|
||||||
// << " ss" << name << endl);
|
// << " ss" << name << endl);
|
||||||
const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0;
|
const int timeunit = m_modp ? m_modp->timeunit().powerOfTen() : 0;
|
||||||
m_scopeNames.emplace(name, ScopeData{nodep, name, nodep->scopePrettySymName(), "<null>",
|
m_dpiScopeNames.emplace(name, ScopeData{nodep, name, nodep->scopePrettySymName(), "<null>",
|
||||||
timeunit, "SCOPE_OTHER"});
|
timeunit, "SCOPE_OTHER"});
|
||||||
if (nodep->dpiExport()) {
|
if (nodep->dpiExport()) {
|
||||||
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
|
UASSERT_OBJ(m_cfuncp, nodep, "ScopeName not under DPI function");
|
||||||
m_scopeFuncs.emplace(name + " " + m_cfuncp->name(),
|
m_scopeFuncs.emplace(name + " " + m_cfuncp->name(),
|
||||||
ScopeFuncData(nodep, m_cfuncp, m_modp));
|
ScopeFuncData(nodep, m_cfuncp, m_modp));
|
||||||
} else {
|
} else {
|
||||||
if (m_scopeNames.find(nodep->scopeDpiName()) == m_scopeNames.end()) {
|
if (m_dpiScopeNames.find(nodep->scopeDpiName()) == m_dpiScopeNames.end()) {
|
||||||
// cppcheck-suppress stlFindInsert
|
// cppcheck-suppress stlFindInsert
|
||||||
m_scopeNames.emplace(nodep->scopeDpiName(),
|
m_dpiScopeNames.emplace(nodep->scopeDpiName(),
|
||||||
ScopeData{nodep, nodep->scopeDpiName(),
|
ScopeData{nodep, nodep->scopeDpiName(),
|
||||||
nodep->scopePrettyDpiName(), "<null>", timeunit,
|
nodep->scopePrettyDpiName(), "<null>", timeunit,
|
||||||
"SCOPE_OTHER"});
|
"SCOPE_OTHER"});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstVar* nodep) override {
|
void visit(AstVar* nodep) override {
|
||||||
nameCheck(nodep);
|
nameCheck(nodep);
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
if (nodep->isSigUserRdPublic() && !m_cfuncp) m_modVars.emplace_back(m_modp, nodep);
|
if ((nodep->isSigUserRdPublic() || nodep->isSigUserRWPublic()) && !m_cfuncp)
|
||||||
|
m_modVars.emplace_back(m_modp, nodep);
|
||||||
}
|
}
|
||||||
void visit(AstVarScope* nodep) override {
|
void visit(AstVarScope* nodep) override {
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
@@ -929,21 +940,11 @@ void EmitCSyms::emitSymImp() {
|
|||||||
checkSplit(true);
|
checkSplit(true);
|
||||||
AstScope* const scopep = it->second.m_scopep;
|
AstScope* const scopep = it->second.m_scopep;
|
||||||
AstVar* const varp = it->second.m_varp;
|
AstVar* const varp = it->second.m_varp;
|
||||||
//
|
|
||||||
int pwidth = 1;
|
|
||||||
int pdim = 0;
|
int pdim = 0;
|
||||||
int udim = 0;
|
int udim = 0;
|
||||||
string bounds;
|
string bounds;
|
||||||
if (AstBasicDType* const basicp = varp->basicp()) {
|
if (AstBasicDType* const basicp = varp->basicp()) {
|
||||||
// Range is always first, it's not in "C" order
|
// Range is always first, it's not in "C" order
|
||||||
if (basicp->isRanged()) {
|
|
||||||
bounds += " ,";
|
|
||||||
bounds += cvtToStr(basicp->hi());
|
|
||||||
bounds += ",";
|
|
||||||
bounds += cvtToStr(basicp->lo());
|
|
||||||
pdim++;
|
|
||||||
pwidth *= basicp->elements();
|
|
||||||
}
|
|
||||||
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
|
for (AstNodeDType* dtypep = varp->dtypep(); dtypep;) {
|
||||||
dtypep
|
dtypep
|
||||||
= dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
= dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
|
||||||
@@ -952,28 +953,24 @@ void EmitCSyms::emitSymImp() {
|
|||||||
bounds += cvtToStr(adtypep->left());
|
bounds += cvtToStr(adtypep->left());
|
||||||
bounds += ",";
|
bounds += ",";
|
||||||
bounds += cvtToStr(adtypep->right());
|
bounds += cvtToStr(adtypep->right());
|
||||||
if (VN_IS(dtypep, PackArrayDType)) {
|
if (VN_IS(dtypep, PackArrayDType))
|
||||||
pdim++;
|
pdim++;
|
||||||
pwidth *= adtypep->elementsConst();
|
else
|
||||||
} else {
|
|
||||||
udim++;
|
udim++;
|
||||||
}
|
|
||||||
dtypep = adtypep->subDTypep();
|
dtypep = adtypep->subDTypep();
|
||||||
} else {
|
} else {
|
||||||
|
if (basicp->isRanged()) {
|
||||||
|
bounds += " ,";
|
||||||
|
bounds += cvtToStr(basicp->hi());
|
||||||
|
bounds += ",";
|
||||||
|
bounds += cvtToStr(basicp->lo());
|
||||||
|
pdim++;
|
||||||
|
}
|
||||||
break; // AstBasicDType - nothing below, 1
|
break; // AstBasicDType - nothing below, 1
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// TODO: actually expose packed arrays as vpiRegArray
|
|
||||||
if (pdim > 1 && udim == 0) {
|
|
||||||
bounds = ", ";
|
|
||||||
bounds += cvtToStr(pwidth - 1);
|
|
||||||
bounds += ",0";
|
|
||||||
pdim = 1;
|
|
||||||
}
|
|
||||||
if (pdim > 1 || udim > 1) {
|
|
||||||
puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays
|
|
||||||
}
|
|
||||||
putns(scopep, protect("__Vscope_" + it->second.m_scopeName));
|
putns(scopep, protect("__Vscope_" + it->second.m_scopeName));
|
||||||
putns(varp, ".varInsert(__Vfinal,");
|
putns(varp, ".varInsert(__Vfinal,");
|
||||||
putsQuoted(protect(it->second.m_varBasePretty));
|
putsQuoted(protect(it->second.m_varBasePretty));
|
||||||
@@ -983,7 +980,8 @@ void EmitCSyms::emitSymImp() {
|
|||||||
varName += protect(varp->name());
|
varName += protect(varp->name());
|
||||||
|
|
||||||
if (varp->isParam()) {
|
if (varp->isParam()) {
|
||||||
if (varp->vlEnumType() == "VLVT_STRING") {
|
if (varp->vlEnumType() == "VLVT_STRING"
|
||||||
|
&& !VN_IS(varp->subDTypep(), UnpackArrayDType)) {
|
||||||
puts(", const_cast<void*>(static_cast<const void*>(");
|
puts(", const_cast<void*>(static_cast<const void*>(");
|
||||||
puts(varName);
|
puts(varName);
|
||||||
puts(".c_str())), ");
|
puts(".c_str())), ");
|
||||||
@@ -1004,7 +1002,9 @@ void EmitCSyms::emitSymImp() {
|
|||||||
puts(",");
|
puts(",");
|
||||||
puts(varp->vlEnumDir()); // VLVD_IN etc
|
puts(varp->vlEnumDir()); // VLVD_IN etc
|
||||||
puts(",");
|
puts(",");
|
||||||
puts(cvtToStr(pdim + udim));
|
puts(cvtToStr(udim));
|
||||||
|
puts(",");
|
||||||
|
puts(cvtToStr(pdim));
|
||||||
puts(bounds);
|
puts(bounds);
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
++m_numStmts;
|
++m_numStmts;
|
||||||
|
|||||||
+37
-30
@@ -96,7 +96,7 @@ private:
|
|||||||
std::sort(sortedScores.begin(), sortedScores.end());
|
std::sort(sortedScores.begin(), sortedScores.end());
|
||||||
|
|
||||||
const int64_t topScore = sortedScores.back();
|
const int64_t topScore = sortedScores.back();
|
||||||
os << "Top score: " << topScore << endl;
|
os << "Top score: " << topScore << '\n';
|
||||||
const int maxScoreWidth = std::to_string(topScore).length();
|
const int maxScoreWidth = std::to_string(topScore).length();
|
||||||
|
|
||||||
const int64_t intervalsNum = std::min<int64_t>(topScore + 1, MAX_INTERVALS_NUM);
|
const int64_t intervalsNum = std::min<int64_t>(topScore + 1, MAX_INTERVALS_NUM);
|
||||||
@@ -123,7 +123,7 @@ private:
|
|||||||
for (const Interval& iv : intervals)
|
for (const Interval& iv : intervals)
|
||||||
topIntervalSize = std::max(topIntervalSize, iv.m_size);
|
topIntervalSize = std::max(topIntervalSize, iv.m_size);
|
||||||
|
|
||||||
os << "Input files' scores histogram:" << endl;
|
os << "Input files' scores histogram:\n";
|
||||||
|
|
||||||
for (const Interval& iv : intervals) {
|
for (const Interval& iv : intervals) {
|
||||||
const int scaledSize = iv.m_size * (MAX_BAR_LENGTH + 1) / topIntervalSize;
|
const int scaledSize = iv.m_size * (MAX_BAR_LENGTH + 1) / topIntervalSize;
|
||||||
@@ -132,14 +132,14 @@ private:
|
|||||||
os << std::setw(maxScoreWidth) << iv.m_lowerBound << line << " " << iv.m_size << '\n';
|
os << std::setw(maxScoreWidth) << iv.m_lowerBound << line << " " << iv.m_size << '\n';
|
||||||
}
|
}
|
||||||
os << std::setw(maxScoreWidth) << (topScore + 1) << '\n';
|
os << std::setw(maxScoreWidth) << (topScore + 1) << '\n';
|
||||||
os << endl;
|
os << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// PRIVATE METHODS
|
// PRIVATE METHODS
|
||||||
|
|
||||||
// Debug logging: dumps Work Lists and their lists of files
|
// Debug logging: dumps Work Lists and their lists of files
|
||||||
void dumpWorkLists(std::ostream& os) {
|
void dumpWorkLists(std::ostream& os) {
|
||||||
os << "Initial Work Lists with their concatenation eligibility status:" << endl;
|
os << "Initial Work Lists with their concatenation eligibility status:\n";
|
||||||
for (const WorkList& list : m_workLists) {
|
for (const WorkList& list : m_workLists) {
|
||||||
os << "+ [" << (list.m_isConcatenable ? 'x' : ' ') << "] Work List #" << list.m_dbgId
|
os << "+ [" << (list.m_isConcatenable ? 'x' : ' ') << "] Work List #" << list.m_dbgId
|
||||||
<< " (num of files: " << list.m_files.size()
|
<< " (num of files: " << list.m_files.size()
|
||||||
@@ -157,13 +157,13 @@ private:
|
|||||||
os << "| + " << last.m_filename << " (score: " << last.m_score << ")\n";
|
os << "| + " << last.m_filename << " (score: " << last.m_score << ")\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
os << endl;
|
os << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
// Debug logging: dumps list of output files. List of grouped files is additionally printed
|
// Debug logging: dumps list of output files. List of grouped files is additionally printed
|
||||||
// for each concatenating file.
|
// for each concatenating file.
|
||||||
void dumpOutputList(std::ostream& os) const {
|
void dumpOutputList(std::ostream& os) const {
|
||||||
os << "List of output files after execution of concatenation:" << endl;
|
os << "List of output files after execution of concatenation:\n";
|
||||||
|
|
||||||
for (const FileOrConcatenatedFilesList& entry : m_outputFiles) {
|
for (const FileOrConcatenatedFilesList& entry : m_outputFiles) {
|
||||||
if (entry.isConcatenatingFile()) {
|
if (entry.isConcatenatingFile()) {
|
||||||
@@ -182,15 +182,16 @@ private:
|
|||||||
const int totalBucketsNum = v3Global.opt.outputGroups();
|
const int totalBucketsNum = v3Global.opt.outputGroups();
|
||||||
// Return early if there's nothing to do.
|
// Return early if there's nothing to do.
|
||||||
bool groupingRedundant = false;
|
bool groupingRedundant = false;
|
||||||
if (inputFilesCount < MIN_FILES_COUNT) {
|
if (inputFilesCount < MIN_FILES_COUNT
|
||||||
UINFO(4, "File concatenation skipped: Too few files ("
|
&& inputFilesCount <= static_cast<size_t>(totalBucketsNum)) {
|
||||||
<< m_inputFiles.size() << " < " << MIN_FILES_COUNT << ")" << endl);
|
UINFO(4, "File concatenation skipped: Too few files (" << m_inputFiles.size() << " < "
|
||||||
|
<< MIN_FILES_COUNT << ")\n");
|
||||||
groupingRedundant = true;
|
groupingRedundant = true;
|
||||||
}
|
}
|
||||||
if (inputFilesCount < (MIN_FILES_PER_BUCKET * totalBucketsNum)) {
|
if (inputFilesCount < (MIN_FILES_PER_BUCKET * totalBucketsNum)) {
|
||||||
UINFO(4, "File concatenation skipped: Too few files per bucket ("
|
UINFO(4, "File concatenation skipped: Too few files per bucket ("
|
||||||
<< m_inputFiles.size() << " < " << MIN_FILES_PER_BUCKET << " - "
|
<< m_inputFiles.size() << " < " << MIN_FILES_PER_BUCKET << " - "
|
||||||
<< totalBucketsNum << ")" << endl);
|
<< totalBucketsNum << ")\n");
|
||||||
groupingRedundant = true;
|
groupingRedundant = true;
|
||||||
}
|
}
|
||||||
if (!groupingRedundant) return false;
|
if (!groupingRedundant) return false;
|
||||||
@@ -212,13 +213,12 @@ private:
|
|||||||
V3Stats::addStat("Concatenation max score", concatenableFileMaxScore);
|
V3Stats::addStat("Concatenation max score", concatenableFileMaxScore);
|
||||||
int nextWorkListId = 0;
|
int nextWorkListId = 0;
|
||||||
|
|
||||||
if (m_logp) *m_logp << "Input files with their concatenation eligibility status:" << endl;
|
if (m_logp) *m_logp << "Input files with their concatenation eligibility status:\n";
|
||||||
for (const FilenameWithScore& inputFile : m_inputFiles) {
|
for (const FilenameWithScore& inputFile : m_inputFiles) {
|
||||||
const bool fileIsConcatenable = (inputFile.m_score <= concatenableFileMaxScore);
|
const bool fileIsConcatenable = (inputFile.m_score <= concatenableFileMaxScore);
|
||||||
if (m_logp)
|
if (m_logp)
|
||||||
*m_logp << " + [" << (fileIsConcatenable ? 'x' : ' ') << "] "
|
*m_logp << " + [" << (fileIsConcatenable ? 'x' : ' ') << "] "
|
||||||
<< inputFile.m_filename << " (score: " << inputFile.m_score << ")"
|
<< inputFile.m_filename << " (score: " << inputFile.m_score << ")\n";
|
||||||
<< endl;
|
|
||||||
V3Stats::addStatSum(fileIsConcatenable ? "Concatenation total grouped score"
|
V3Stats::addStatSum(fileIsConcatenable ? "Concatenation total grouped score"
|
||||||
: "Concatenation total non-grouped score",
|
: "Concatenation total non-grouped score",
|
||||||
inputFile.m_score);
|
inputFile.m_score);
|
||||||
@@ -233,7 +233,7 @@ private:
|
|||||||
list.m_files.push_back({inputFile.m_filename, inputFile.m_score});
|
list.m_files.push_back({inputFile.m_filename, inputFile.m_score});
|
||||||
list.m_totalScore += inputFile.m_score;
|
list.m_totalScore += inputFile.m_score;
|
||||||
}
|
}
|
||||||
if (m_logp) *m_logp << endl;
|
if (m_logp) *m_logp << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
void assignBuckets(uint64_t concatenableFilesTotalScore) {
|
void assignBuckets(uint64_t concatenableFilesTotalScore) {
|
||||||
@@ -248,8 +248,7 @@ private:
|
|||||||
// Debugging: Log which work lists will be kept
|
// Debugging: Log which work lists will be kept
|
||||||
if (m_logp) {
|
if (m_logp) {
|
||||||
*m_logp << "More Work Lists than buckets; "
|
*m_logp << "More Work Lists than buckets; "
|
||||||
"Work Lists with statuses indicating whether the list will be kept:"
|
"Work Lists with statuses indicating whether the list will be kept:\n";
|
||||||
<< endl;
|
|
||||||
// Only lists that will be kept. List that will be removed are logged below.
|
// Only lists that will be kept. List that will be removed are logged below.
|
||||||
std::for_each(m_concatenableListsByDescSize.begin(),
|
std::for_each(m_concatenableListsByDescSize.begin(),
|
||||||
m_concatenableListsByDescSize.begin() + totalBucketsNum,
|
m_concatenableListsByDescSize.begin() + totalBucketsNum,
|
||||||
@@ -269,7 +268,7 @@ private:
|
|||||||
<< " (num of files: " << listp->m_files.size()
|
<< " (num of files: " << listp->m_files.size()
|
||||||
<< "; total score: " << listp->m_totalScore << ")\n";
|
<< "; total score: " << listp->m_totalScore << ")\n";
|
||||||
});
|
});
|
||||||
if (m_logp) *m_logp << endl;
|
if (m_logp) *m_logp << '\n';
|
||||||
|
|
||||||
m_concatenableListsByDescSize.resize(totalBucketsNum);
|
m_concatenableListsByDescSize.resize(totalBucketsNum);
|
||||||
// Recalculate stats
|
// Recalculate stats
|
||||||
@@ -283,7 +282,7 @@ private:
|
|||||||
|
|
||||||
V3Stats::addStat("Concatenation ideal bucket score", idealBucketScore);
|
V3Stats::addStat("Concatenation ideal bucket score", idealBucketScore);
|
||||||
|
|
||||||
if (m_logp) *m_logp << "Buckets assigned to Work Lists:" << endl;
|
if (m_logp) *m_logp << "Buckets assigned to Work Lists:\n";
|
||||||
int availableBuckets = v3Global.opt.outputGroups();
|
int availableBuckets = v3Global.opt.outputGroups();
|
||||||
for (WorkList* listp : m_concatenableListsByDescSize) {
|
for (WorkList* listp : m_concatenableListsByDescSize) {
|
||||||
if (availableBuckets > 0) {
|
if (availableBuckets > 0) {
|
||||||
@@ -301,7 +300,7 @@ private:
|
|||||||
<< std::right << " (excluding from concatenation)\n";
|
<< std::right << " (excluding from concatenation)\n";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_logp) *m_logp << endl;
|
if (m_logp) *m_logp << '\n';
|
||||||
}
|
}
|
||||||
|
|
||||||
void buildOutputList() {
|
void buildOutputList() {
|
||||||
@@ -395,19 +394,19 @@ private:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void process() {
|
void process() {
|
||||||
UINFO(4, __FUNCTION__ << ":" << endl);
|
UINFO(4, __FUNCTION__ << " group file prefix: " << m_groupFilePrefix << '\n');
|
||||||
UINFO(5, "Number of input files: " << m_inputFiles.size() << endl);
|
UINFO(5, "Number of input files: " << m_inputFiles.size() << '\n');
|
||||||
UINFO(5, "Total score: " << m_totalScore << endl);
|
UINFO(5, "Total score: " << m_totalScore << '\n');
|
||||||
UINFO(5, "Group file prefix: " << m_groupFilePrefix << endl);
|
|
||||||
|
|
||||||
const int totalBucketsNum = v3Global.opt.outputGroups();
|
const int totalBucketsNum = v3Global.opt.outputGroups();
|
||||||
UINFO(5, "Number of buckets: " << totalBucketsNum << endl);
|
UINFO(5, "Number of buckets: " << totalBucketsNum << '\n');
|
||||||
UASSERT(totalBucketsNum > 0, "More than 0 buckets required");
|
UASSERT(totalBucketsNum > 0, "More than 0 buckets required");
|
||||||
|
|
||||||
if (fallbackNoGrouping(m_inputFiles.size())) return;
|
if (fallbackNoGrouping(m_inputFiles.size())) return;
|
||||||
|
|
||||||
if (dumpLevel() >= 6) {
|
if (debug() >= 6 || dumpLevel() >= 6) {
|
||||||
const string filename = v3Global.debugFilename("outputgroup") + ".txt";
|
const string filename = v3Global.debugFilename("outputgroup") + ".txt";
|
||||||
|
UINFO(5, "Dumping " << filename << endl);
|
||||||
m_logp = std::unique_ptr<std::ofstream>{V3File::new_ofstream(filename)};
|
m_logp = std::unique_ptr<std::ofstream>{V3File::new_ofstream(filename)};
|
||||||
if (m_logp->fail()) v3fatal("Can't write " << filename);
|
if (m_logp->fail()) v3fatal("Can't write " << filename);
|
||||||
}
|
}
|
||||||
@@ -417,7 +416,6 @@ private:
|
|||||||
createWorkLists();
|
createWorkLists();
|
||||||
|
|
||||||
// Collect stats and mark lists with only one file as non-concatenable
|
// Collect stats and mark lists with only one file as non-concatenable
|
||||||
|
|
||||||
size_t concatenableFilesCount = 0;
|
size_t concatenableFilesCount = 0;
|
||||||
int64_t concatenableFilesTotalScore = 0;
|
int64_t concatenableFilesTotalScore = 0;
|
||||||
|
|
||||||
@@ -479,6 +477,9 @@ class EmitMk final {
|
|||||||
using FileOrConcatenatedFilesList = EmitGroup::FileOrConcatenatedFilesList;
|
using FileOrConcatenatedFilesList = EmitGroup::FileOrConcatenatedFilesList;
|
||||||
using FilenameWithScore = EmitGroup::FilenameWithScore;
|
using FilenameWithScore = EmitGroup::FilenameWithScore;
|
||||||
|
|
||||||
|
// MEMBERS
|
||||||
|
double m_putClassCount = 0; // Number of classEntries printed
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
@@ -494,6 +495,7 @@ public:
|
|||||||
|
|
||||||
void putMakeClassEntry(V3OutMkFile& of, const string& name) {
|
void putMakeClassEntry(V3OutMkFile& of, const string& name) {
|
||||||
of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n");
|
of.puts("\t" + V3Os::filenameNonDirExt(name) + " \\\n");
|
||||||
|
++m_putClassCount;
|
||||||
}
|
}
|
||||||
|
|
||||||
void emitClassMake() {
|
void emitClassMake() {
|
||||||
@@ -577,9 +579,12 @@ public:
|
|||||||
} else {
|
} else {
|
||||||
of.puts(", fast-path, compile with highest optimization\n");
|
of.puts(", fast-path, compile with highest optimization\n");
|
||||||
}
|
}
|
||||||
of.puts(support == 2 ? "VM_GLOBAL" : support == 1 ? "VM_SUPPORT" : "VM_CLASSES");
|
const string targetVar = (support == 2 ? "VM_GLOBAL"s
|
||||||
of.puts(slow ? "_SLOW" : "_FAST");
|
: support == 1 ? "VM_SUPPORT"s
|
||||||
of.puts(" += \\\n");
|
: "VM_CLASSES"s)
|
||||||
|
+ (slow ? "_SLOW" : "_FAST");
|
||||||
|
m_putClassCount = 0;
|
||||||
|
of.puts(targetVar + " += \\\n");
|
||||||
if (support == 2 && v3Global.opt.hierChild()) {
|
if (support == 2 && v3Global.opt.hierChild()) {
|
||||||
// Do nothing because VM_GLOBAL is necessary per executable. Top module will
|
// Do nothing because VM_GLOBAL is necessary per executable. Top module will
|
||||||
// have them.
|
// have them.
|
||||||
@@ -605,7 +610,7 @@ public:
|
|||||||
const std::vector<FileOrConcatenatedFilesList>& list
|
const std::vector<FileOrConcatenatedFilesList>& list
|
||||||
= slow ? vmClassesSlowList : vmClassesFastList;
|
= slow ? vmClassesSlowList : vmClassesFastList;
|
||||||
for (const FileOrConcatenatedFilesList& entry : list) {
|
for (const FileOrConcatenatedFilesList& entry : list) {
|
||||||
if (entry.isConcatenatingFile()) { emitConcatenatingFile(entry); }
|
if (entry.isConcatenatingFile()) emitConcatenatingFile(entry);
|
||||||
putMakeClassEntry(of, entry.m_filename);
|
putMakeClassEntry(of, entry.m_filename);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -619,6 +624,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
of.puts("\n");
|
of.puts("\n");
|
||||||
|
V3Stats::addStat("Makefile targets, " + targetVar, m_putClassCount);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -808,6 +814,7 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|
||||||
class EmitMkHierVerilation final {
|
class EmitMkHierVerilation final {
|
||||||
const V3HierBlockPlan* const m_planp;
|
const V3HierBlockPlan* const m_planp;
|
||||||
const string m_makefile; // path of this makefile
|
const string m_makefile; // path of this makefile
|
||||||
|
|||||||
+205
-66
@@ -28,13 +28,17 @@ VL_DEFINE_DEBUG_FUNCTIONS;
|
|||||||
// Emit statements and expressions
|
// Emit statements and expressions
|
||||||
|
|
||||||
class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
||||||
// MEMBERS
|
// STATE - across all visitors
|
||||||
bool m_suppressSemi = false;
|
|
||||||
const bool m_suppressUnknown = false;
|
const bool m_suppressUnknown = false;
|
||||||
|
|
||||||
|
// STATE - for current visit position (use VL_RESTORER)
|
||||||
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
AstSenTree* m_sensesp; // Domain for printing one a ALWAYS under a ACTIVE
|
||||||
|
bool m_suppressSemi = false; // Non-statement, don't print ;
|
||||||
|
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
||||||
|
bool m_arrayPost = false; // Print array information that goes after identifier (vs after)
|
||||||
|
std::deque<AstNodeArrayDType*> m_packedps; // Packed arrays to print with BasicDType
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
virtual void puts(const string& str) = 0;
|
virtual void puts(const string& str) = 0;
|
||||||
virtual void putbs(const string& str) = 0;
|
virtual void putbs(const string& str) = 0;
|
||||||
virtual void putfs(AstNode* nodep, const string& str) = 0; // Fileline and node %% mark
|
virtual void putfs(AstNode* nodep, const string& str) = 0; // Fileline and node %% mark
|
||||||
@@ -49,6 +53,20 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
putsNoTracking("\"");
|
putsNoTracking("\"");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void iterateAndCommaConstNull(AstNode* nodep) {
|
||||||
|
for (; nodep; nodep = nodep->nextp()) {
|
||||||
|
iterateConst(nodep);
|
||||||
|
if (nodep->nextp()) puts(", ");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void emitPacked() {
|
||||||
|
for (AstNodeArrayDType* packedp : m_packedps) {
|
||||||
|
puts(" ");
|
||||||
|
iterateConstNull(packedp->rangep());
|
||||||
|
}
|
||||||
|
m_packedps.clear();
|
||||||
|
}
|
||||||
|
|
||||||
// VISITORS
|
// VISITORS
|
||||||
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
void visit(AstNetlist* nodep) override { iterateAndNextConstNull(nodep->modulesp()); }
|
||||||
void visit(AstNodeModule* nodep) override {
|
void visit(AstNodeModule* nodep) override {
|
||||||
@@ -58,13 +76,14 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
void visit(AstPort* nodep) override {}
|
void visit(AstPort* nodep) override {}
|
||||||
void visit(AstNodeFTask* nodep) override {
|
void visit(AstNodeFTask* nodep) override {
|
||||||
putfs(nodep, nodep->isFunction() ? "function" : "task");
|
const bool func = nodep->isFunction() || nodep->name() == "new";
|
||||||
|
putfs(nodep, func ? "function" : "task");
|
||||||
puts(" ");
|
puts(" ");
|
||||||
puts(nodep->prettyName());
|
puts(nodep->prettyName());
|
||||||
puts(";\n");
|
puts(";\n");
|
||||||
// Only putfs the first time for each visitor; later for same node is putqs
|
// Only putfs the first time for each visitor; later for same node is putqs
|
||||||
iterateAndNextConstNull(nodep->stmtsp());
|
iterateAndNextConstNull(nodep->stmtsp());
|
||||||
putfs(nodep, nodep->isFunction() ? "endfunction\n" : "endtask\n");
|
putfs(nodep, func ? "endfunction\n" : "endtask\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void visit(AstBegin* nodep) override {
|
void visit(AstBegin* nodep) override {
|
||||||
@@ -169,7 +188,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
void visit(AstSenItem* nodep) override {
|
void visit(AstSenItem* nodep) override {
|
||||||
putfs(nodep, "");
|
putfs(nodep, "");
|
||||||
puts(nodep->edgeType().verilogKwd());
|
if (nodep->edgeType() != VEdgeType::ET_CHANGED) puts(nodep->edgeType().verilogKwd());
|
||||||
if (nodep->sensp()) puts(" ");
|
if (nodep->sensp()) puts(" ");
|
||||||
iterateChildrenConst(nodep);
|
iterateChildrenConst(nodep);
|
||||||
}
|
}
|
||||||
@@ -216,18 +235,30 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
void visit(AstCoverInc*) override {} // N/A
|
void visit(AstCoverInc*) override {} // N/A
|
||||||
void visit(AstCoverToggle*) override {} // N/A
|
void visit(AstCoverToggle*) override {} // N/A
|
||||||
|
|
||||||
|
void visit(AstTestPlusArgs* nodep) override {
|
||||||
|
putfs(nodep, nodep->verilogKwd());
|
||||||
|
putbs("(");
|
||||||
|
iterateChildrenConst(nodep);
|
||||||
|
puts(")");
|
||||||
|
}
|
||||||
|
void visit(AstValuePlusArgs* nodep) override {
|
||||||
|
putfs(nodep, nodep->verilogKwd());
|
||||||
|
putbs("(");
|
||||||
|
iterateChildrenConst(nodep);
|
||||||
|
puts(")");
|
||||||
|
}
|
||||||
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
void visitNodeDisplay(AstNode* nodep, AstNode* fileOrStrgp, const string& text,
|
||||||
AstNode* exprsp) {
|
AstNode* exprsp) {
|
||||||
putfs(nodep, nodep->verilogKwd());
|
putfs(nodep, nodep->verilogKwd());
|
||||||
putbs("(");
|
putbs("(");
|
||||||
if (fileOrStrgp) {
|
if (fileOrStrgp) {
|
||||||
iterateAndNextConstNull(fileOrStrgp);
|
iterateConstNull(fileOrStrgp);
|
||||||
putbs(", ");
|
putbs(", ");
|
||||||
}
|
}
|
||||||
putsQuoted(text);
|
putsQuoted(text);
|
||||||
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
for (AstNode* expp = exprsp; expp; expp = expp->nextp()) {
|
||||||
puts(", ");
|
puts(", ");
|
||||||
iterateAndNextConstNull(expp);
|
iterateConstNull(expp);
|
||||||
}
|
}
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
@@ -393,7 +424,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
void visit(AstTextBlock* nodep) override {
|
void visit(AstTextBlock* nodep) override {
|
||||||
visit(static_cast<AstNodeSimpleText*>(nodep));
|
visit(static_cast<AstNodeSimpleText*>(nodep));
|
||||||
VL_RESTORER(m_suppressSemi);
|
VL_RESTORER(m_suppressVarSemi);
|
||||||
m_suppressVarSemi = nodep->commas();
|
m_suppressVarSemi = nodep->commas();
|
||||||
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
for (AstNode* childp = nodep->nodesp(); childp; childp = childp->nextp()) {
|
||||||
iterateConst(childp);
|
iterateConst(childp);
|
||||||
@@ -403,17 +434,17 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
void visit(AstScopeName* nodep) override {}
|
void visit(AstScopeName* nodep) override {}
|
||||||
void visit(AstCStmt* nodep) override {
|
void visit(AstCStmt* nodep) override {
|
||||||
putfs(nodep, "$_CSTMT(");
|
putfs(nodep, "$_CSTMT(");
|
||||||
iterateAndNextConstNull(nodep->exprsp());
|
iterateAndCommaConstNull(nodep->exprsp());
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
void visit(AstCExpr* nodep) override {
|
void visit(AstCExpr* nodep) override {
|
||||||
putfs(nodep, "$_CEXPR(");
|
putfs(nodep, "$_CEXPR(");
|
||||||
iterateAndNextConstNull(nodep->exprsp());
|
iterateAndCommaConstNull(nodep->exprsp());
|
||||||
puts(")");
|
puts(")");
|
||||||
}
|
}
|
||||||
void visit(AstUCStmt* nodep) override {
|
void visit(AstUCStmt* nodep) override {
|
||||||
putfs(nodep, "$c(");
|
putfs(nodep, "$c(");
|
||||||
iterateAndNextConstNull(nodep->exprsp());
|
iterateAndCommaConstNull(nodep->exprsp());
|
||||||
puts(");\n");
|
puts(");\n");
|
||||||
}
|
}
|
||||||
void visit(AstUCFunc* nodep) override {
|
void visit(AstUCFunc* nodep) override {
|
||||||
@@ -431,19 +462,13 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
void visit(AstCMethodHard* nodep) override {
|
void visit(AstCMethodHard* nodep) override {
|
||||||
iterateConst(nodep->fromp());
|
iterateConst(nodep->fromp());
|
||||||
puts("." + nodep->name() + "(");
|
puts("." + nodep->name() + "(");
|
||||||
for (AstNode* pinp = nodep->pinsp(); pinp; pinp = pinp->nextp()) {
|
iterateAndCommaConstNull(nodep->pinsp());
|
||||||
if (pinp != nodep->pinsp()) puts(", ");
|
|
||||||
iterateConst(pinp);
|
|
||||||
}
|
|
||||||
puts(")");
|
puts(")");
|
||||||
}
|
}
|
||||||
void visit(AstCMethodCall* nodep) override {
|
void visit(AstCMethodCall* nodep) override {
|
||||||
iterateConst(nodep->fromp());
|
iterateConst(nodep->fromp());
|
||||||
puts("." + nodep->name() + "(");
|
puts("." + nodep->name() + "(");
|
||||||
for (AstNode* pinp = nodep->argsp(); pinp; pinp = pinp->nextp()) {
|
iterateAndCommaConstNull(nodep->argsp());
|
||||||
if (pinp != nodep->argsp()) puts(", ");
|
|
||||||
iterateConst(pinp);
|
|
||||||
}
|
|
||||||
puts(")");
|
puts(")");
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -463,7 +488,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
bool inPct = false;
|
bool inPct = false;
|
||||||
putbs("");
|
putbs("");
|
||||||
for (const char c : format) {
|
for (const char c : format) {
|
||||||
if (c == '%') {
|
if (!inPct && c == '%') {
|
||||||
inPct = true;
|
inPct = true;
|
||||||
} else if (!inPct) { // Normal text
|
} else if (!inPct) { // Normal text
|
||||||
string s;
|
string s;
|
||||||
@@ -565,32 +590,40 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
puts(cvtToStr(nodep->leftConst()));
|
puts(cvtToStr(nodep->leftConst()));
|
||||||
puts(":");
|
puts(":");
|
||||||
puts(cvtToStr(nodep->rightConst()));
|
puts(cvtToStr(nodep->rightConst()));
|
||||||
puts("]");
|
|
||||||
} else {
|
} else {
|
||||||
iterateAndNextConstNull(nodep->leftp());
|
iterateAndNextConstNull(nodep->leftp());
|
||||||
puts(":");
|
puts(":");
|
||||||
iterateAndNextConstNull(nodep->rightp());
|
iterateAndNextConstNull(nodep->rightp());
|
||||||
puts("]");
|
|
||||||
}
|
}
|
||||||
|
puts("]");
|
||||||
|
}
|
||||||
|
void visit(AstRand* nodep) override {
|
||||||
|
emitVerilogFormat(nodep, nodep->emitVerilog(), nodep->seedp());
|
||||||
}
|
}
|
||||||
void visit(AstSel* nodep) override {
|
void visit(AstSel* nodep) override {
|
||||||
iterateAndNextConstNull(nodep->fromp());
|
iterateAndNextConstNull(nodep->fromp());
|
||||||
|
int offset = 0;
|
||||||
|
AstNodeDType* const dtypep = nodep->fromp()->dtypep();
|
||||||
|
if (VN_IS(dtypep, BasicDType)) {
|
||||||
|
AstBasicDType* const basicDtypep = VN_AS(dtypep, BasicDType);
|
||||||
|
offset = basicDtypep->lo();
|
||||||
|
}
|
||||||
puts("[");
|
puts("[");
|
||||||
if (VN_IS(nodep->lsbp(), Const)) {
|
if (VN_IS(nodep->lsbp(), Const)) {
|
||||||
if (nodep->widthp()->isOne()) {
|
if (nodep->widthp()->isOne()) {
|
||||||
if (VN_IS(nodep->lsbp(), Const)) {
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt() + offset));
|
||||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
|
|
||||||
} else {
|
|
||||||
iterateAndNextConstNull(nodep->lsbp());
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()
|
||||||
+ VN_AS(nodep->widthp(), Const)->toSInt() - 1));
|
+ VN_AS(nodep->widthp(), Const)->toSInt() + offset - 1));
|
||||||
puts(":");
|
puts(":");
|
||||||
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt()));
|
puts(cvtToStr(VN_AS(nodep->lsbp(), Const)->toSInt() + offset));
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
iterateAndNextConstNull(nodep->lsbp());
|
iterateAndNextConstNull(nodep->lsbp());
|
||||||
|
if (offset != 0) {
|
||||||
|
puts(" + ");
|
||||||
|
puts(cvtToStr(offset));
|
||||||
|
}
|
||||||
putfs(nodep, "+:");
|
putfs(nodep, "+:");
|
||||||
iterateAndNextConstNull(nodep->widthp());
|
iterateAndNextConstNull(nodep->widthp());
|
||||||
puts("]");
|
puts("]");
|
||||||
@@ -603,14 +636,31 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
void visit(AstTypedef* nodep) override {
|
void visit(AstTypedef* nodep) override {
|
||||||
putfs(nodep, "typedef ");
|
putfs(nodep, "typedef ");
|
||||||
iterateAndNextConstNull(nodep->subDTypep());
|
iterateConstNull(nodep->subDTypep());
|
||||||
puts(" ");
|
puts(" ");
|
||||||
puts(nodep->prettyName());
|
puts(nodep->prettyName());
|
||||||
puts(";\n");
|
puts(";\n");
|
||||||
}
|
}
|
||||||
|
void visit(AstAssocArrayDType* nodep) override {
|
||||||
|
if (!m_arrayPost) {
|
||||||
|
iterateConst(nodep->subDTypep());
|
||||||
|
} else {
|
||||||
|
VL_RESTORER(m_arrayPost);
|
||||||
|
m_arrayPost = false;
|
||||||
|
puts("[");
|
||||||
|
iterateConst(nodep->keyDTypep());
|
||||||
|
puts("]");
|
||||||
|
m_arrayPost = true;
|
||||||
|
iterateConst(nodep->subDTypep()); // For post's key
|
||||||
|
}
|
||||||
|
}
|
||||||
void visit(AstBasicDType* nodep) override {
|
void visit(AstBasicDType* nodep) override {
|
||||||
|
if (m_arrayPost) return;
|
||||||
putfs(nodep, nodep->prettyName());
|
putfs(nodep, nodep->prettyName());
|
||||||
if (nodep->isSigned()) putfs(nodep, " signed");
|
if (nodep->isSigned() && !nodep->keyword().isDouble()) putfs(nodep, " signed");
|
||||||
|
// Do not emit ranges for integer atoms.
|
||||||
|
if (nodep->keyword().isIntNumeric() && !nodep->keyword().isBitLogic()) return;
|
||||||
|
emitPacked();
|
||||||
if (nodep->rangep()) {
|
if (nodep->rangep()) {
|
||||||
puts(" ");
|
puts(" ");
|
||||||
iterateAndNextConstNull(nodep->rangep());
|
iterateAndNextConstNull(nodep->rangep());
|
||||||
@@ -624,12 +674,70 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstConstDType* nodep) override {
|
void visit(AstConstDType* nodep) override {
|
||||||
|
if (m_arrayPost) return;
|
||||||
putfs(nodep, "const ");
|
putfs(nodep, "const ");
|
||||||
iterateConst(nodep->subDTypep());
|
iterateConst(nodep->subDTypep());
|
||||||
}
|
}
|
||||||
void visit(AstNodeArrayDType* nodep) override {
|
void visit(AstDynArrayDType* nodep) override {
|
||||||
|
if (!m_arrayPost) {
|
||||||
|
iterateConst(nodep->subDTypep());
|
||||||
|
} else {
|
||||||
|
puts("[]");
|
||||||
|
iterateConst(nodep->subDTypep()); // For post's key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstEnumDType* nodep) override {
|
||||||
|
if (m_arrayPost) return;
|
||||||
|
putfs(nodep, "enum ");
|
||||||
iterateConst(nodep->subDTypep());
|
iterateConst(nodep->subDTypep());
|
||||||
iterateAndNextConstNull(nodep->rangep());
|
puts("{\n");
|
||||||
|
iterateAndNextConstNull(nodep->itemsp());
|
||||||
|
puts("}");
|
||||||
|
}
|
||||||
|
void visit(AstEnumItemRef* nodep) override {
|
||||||
|
if (AstNodeModule* const classOrPackagep = nodep->classOrPackagep()) {
|
||||||
|
putfs(nodep, classOrPackagep->prettyName());
|
||||||
|
puts("::");
|
||||||
|
}
|
||||||
|
putfs(nodep, nodep->name());
|
||||||
|
}
|
||||||
|
void visit(AstEnumItem* nodep) override {
|
||||||
|
putfs(nodep, nodep->name());
|
||||||
|
iterateConstNull(nodep->rangep());
|
||||||
|
puts(" = ");
|
||||||
|
iterateConstNull(nodep->valuep());
|
||||||
|
if (nodep->nextp()) puts(",");
|
||||||
|
puts("\n");
|
||||||
|
}
|
||||||
|
void visit(AstNodeArrayDType* nodep) override {
|
||||||
|
if (!m_arrayPost) {
|
||||||
|
if (VN_IS(nodep, PackArrayDType)) {
|
||||||
|
// Unpacked ranges handled in BasicDType, as they print "backwards"
|
||||||
|
m_packedps.push_back(nodep);
|
||||||
|
}
|
||||||
|
iterateConst(nodep->subDTypep());
|
||||||
|
} else {
|
||||||
|
if (VN_IS(nodep, UnpackArrayDType)) {
|
||||||
|
VL_RESTORER(m_arrayPost);
|
||||||
|
m_arrayPost = false;
|
||||||
|
iterateAndNextConstNull(nodep->rangep());
|
||||||
|
m_arrayPost = true;
|
||||||
|
}
|
||||||
|
iterateConst(nodep->subDTypep()); // For post's key
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void visit(AstIfaceRefDType* nodep) override {
|
||||||
|
if (m_arrayPost) {
|
||||||
|
puts(" (");
|
||||||
|
if (nodep->cellp()) {
|
||||||
|
iterateConst(nodep->cellp());
|
||||||
|
} else {
|
||||||
|
puts("????");
|
||||||
|
}
|
||||||
|
puts(")");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
puts(nodep->ifaceName());
|
||||||
}
|
}
|
||||||
void visit(AstRefDType* nodep) override {
|
void visit(AstRefDType* nodep) override {
|
||||||
if (nodep->subDTypep()) {
|
if (nodep->subDTypep()) {
|
||||||
@@ -638,22 +746,68 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
puts("\n???? // "s + nodep->prettyTypeName() + " -> UNLINKED\n");
|
puts("\n???? // "s + nodep->prettyTypeName() + " -> UNLINKED\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void visit(AstModport* nodep) override {
|
||||||
|
puts(nodep->verilogKwd());
|
||||||
|
puts(" ");
|
||||||
|
puts(nodep->prettyName());
|
||||||
|
puts(" (\n");
|
||||||
|
if (nodep->varsp()) {
|
||||||
|
iterateConst(nodep->varsp());
|
||||||
|
} else {
|
||||||
|
puts("????");
|
||||||
|
}
|
||||||
|
puts(");\n");
|
||||||
|
}
|
||||||
|
void visit(AstModportVarRef* nodep) override {
|
||||||
|
puts(nodep->direction().verilogKwd());
|
||||||
|
puts(" ");
|
||||||
|
if (nodep->varp()) {
|
||||||
|
VL_RESTORER(m_suppressVarSemi);
|
||||||
|
m_suppressVarSemi = true;
|
||||||
|
iterateConst(nodep->varp());
|
||||||
|
} else {
|
||||||
|
puts(nodep->prettyName());
|
||||||
|
}
|
||||||
|
if (nodep->nextp()) puts(", ");
|
||||||
|
}
|
||||||
void visit(AstNodeUOrStructDType* nodep) override {
|
void visit(AstNodeUOrStructDType* nodep) override {
|
||||||
|
if (m_arrayPost) return;
|
||||||
puts(nodep->verilogKwd() + " ");
|
puts(nodep->verilogKwd() + " ");
|
||||||
if (nodep->packed()) puts("packed ");
|
if (nodep->packed()) puts("packed ");
|
||||||
puts("\n");
|
{
|
||||||
puts("{");
|
puts("{\n");
|
||||||
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
VL_RESTORER(m_packedps);
|
||||||
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
m_packedps.clear();
|
||||||
iterateConst(itemp);
|
for (AstMemberDType* itemp = nodep->membersp(); itemp;
|
||||||
puts(";");
|
itemp = VN_AS(itemp->nextp(), MemberDType)) {
|
||||||
|
iterateConst(itemp);
|
||||||
|
}
|
||||||
|
puts("}");
|
||||||
}
|
}
|
||||||
puts("}");
|
emitPacked();
|
||||||
}
|
}
|
||||||
void visit(AstMemberDType* nodep) override {
|
void visit(AstMemberDType* nodep) override {
|
||||||
|
if (m_arrayPost) return;
|
||||||
iterateConst(nodep->subDTypep());
|
iterateConst(nodep->subDTypep());
|
||||||
puts(" ");
|
puts(" ");
|
||||||
puts(nodep->name());
|
puts(nodep->name());
|
||||||
|
puts(";\n");
|
||||||
|
}
|
||||||
|
void visit(AstQueueDType* nodep) override {
|
||||||
|
if (!m_arrayPost) {
|
||||||
|
iterateConst(nodep->subDTypep());
|
||||||
|
} else {
|
||||||
|
VL_RESTORER(m_arrayPost);
|
||||||
|
m_arrayPost = false;
|
||||||
|
puts("[$");
|
||||||
|
if (nodep->boundp()) {
|
||||||
|
puts(":");
|
||||||
|
iterateConst(nodep->boundp());
|
||||||
|
}
|
||||||
|
puts("]");
|
||||||
|
m_arrayPost = true;
|
||||||
|
iterateConst(nodep->subDTypep()); // For post's key
|
||||||
|
}
|
||||||
}
|
}
|
||||||
void visit(AstNodeFTaskRef* nodep) override {
|
void visit(AstNodeFTaskRef* nodep) override {
|
||||||
if (nodep->dotted() != "") {
|
if (nodep->dotted() != "") {
|
||||||
@@ -698,7 +852,7 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstVarXRef* nodep) override {
|
void visit(AstVarXRef* nodep) override {
|
||||||
putfs(nodep, nodep->dotted());
|
putfs(nodep, nodep->prettyName(nodep->dotted()));
|
||||||
puts(".");
|
puts(".");
|
||||||
if (nodep->varp()) {
|
if (nodep->varp()) {
|
||||||
puts(nodep->varp()->prettyName());
|
puts(nodep->varp()->prettyName());
|
||||||
@@ -716,37 +870,23 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
putfs(nodep, nodep->verilogKwd());
|
putfs(nodep, nodep->verilogKwd());
|
||||||
puts(" ");
|
puts(" ");
|
||||||
}
|
}
|
||||||
std::vector<const AstUnpackArrayDType*> unpackps;
|
VL_RESTORER(m_arrayPost);
|
||||||
for (AstNodeDType* dtypep = nodep->dtypep(); dtypep;) {
|
m_arrayPost = false;
|
||||||
dtypep = dtypep->skipRefp();
|
iterateConstNull(nodep->dtypep()); // Dtype part before identifier
|
||||||
if (const AstUnpackArrayDType* const unpackp = VN_CAST(dtypep, UnpackArrayDType)) {
|
puts(" ");
|
||||||
unpackps.push_back(unpackp);
|
puts(nodep->prettyName());
|
||||||
dtypep = unpackp->subDTypep();
|
m_arrayPost = true;
|
||||||
} else {
|
iterateConstNull(nodep->dtypep()); // Dtype part after identifier
|
||||||
iterateConst(dtypep);
|
|
||||||
puts(" ");
|
|
||||||
puts(nodep->prettyName());
|
|
||||||
dtypep = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// If nodep is an unpacked array, append unpacked dimensions
|
|
||||||
for (const auto& unpackp : unpackps) {
|
|
||||||
puts("[");
|
|
||||||
puts(cvtToStr(unpackp->rangep()->leftConst()));
|
|
||||||
puts(":");
|
|
||||||
puts(cvtToStr(unpackp->rangep()->rightConst()));
|
|
||||||
puts("]");
|
|
||||||
}
|
|
||||||
puts(m_suppressVarSemi ? "\n" : ";\n");
|
puts(m_suppressVarSemi ? "\n" : ";\n");
|
||||||
}
|
}
|
||||||
void visit(AstActive* nodep) override {
|
void visit(AstActive* nodep) override {
|
||||||
|
VL_RESTORER(m_sensesp);
|
||||||
m_sensesp = nodep->sensesp();
|
m_sensesp = nodep->sensesp();
|
||||||
iterateAndNextConstNull(nodep->stmtsp());
|
iterateAndNextConstNull(nodep->stmtsp());
|
||||||
m_sensesp = nullptr;
|
|
||||||
}
|
}
|
||||||
void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
|
void visit(AstParseRef* nodep) override { puts(nodep->prettyName()); }
|
||||||
void visit(AstVarScope*) override {}
|
|
||||||
void visit(AstNodeText*) override {}
|
void visit(AstNodeText*) override {}
|
||||||
|
void visit(AstVarScope*) override {}
|
||||||
void visit(AstTraceDecl*) override {}
|
void visit(AstTraceDecl*) override {}
|
||||||
void visit(AstTraceInc*) override {}
|
void visit(AstTraceInc*) override {}
|
||||||
// NOPs
|
// NOPs
|
||||||
@@ -764,7 +904,6 @@ class EmitVBaseVisitorConst VL_NOT_FINAL : public EmitCBaseVisitorConst {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
bool m_suppressVarSemi = false; // Suppress emitting semicolon for AstVars
|
|
||||||
explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp)
|
explicit EmitVBaseVisitorConst(bool suppressUnknown, AstSenTree* domainp)
|
||||||
: m_suppressUnknown{suppressUnknown}
|
: m_suppressUnknown{suppressUnknown}
|
||||||
, m_sensesp{domainp} {}
|
, m_sensesp{domainp} {}
|
||||||
|
|||||||
+1
-1
@@ -154,7 +154,7 @@ void V3ErrorGuarded::v3errorEnd(std::ostringstream& sstr, const string& extra)
|
|||||||
}
|
}
|
||||||
// Suppress duplicate messages
|
// Suppress duplicate messages
|
||||||
if (!m_messages.insert(msg).second) return;
|
if (!m_messages.insert(msg).second) return;
|
||||||
if (!extra.empty()) {
|
if (!extra.empty() && !m_errorSuppressed) {
|
||||||
const string extraMsg = warnMore() + extra + "\n";
|
const string extraMsg = warnMore() + extra + "\n";
|
||||||
const size_t pos = msg.find('\n');
|
const size_t pos = msg.find('\n');
|
||||||
msg.insert(pos + 1, extraMsg);
|
msg.insert(pos + 1, extraMsg);
|
||||||
|
|||||||
+2
-1
@@ -88,6 +88,7 @@ public:
|
|||||||
COMBDLY, // Combinatorial delayed assignment
|
COMBDLY, // Combinatorial delayed assignment
|
||||||
CONSTRAINTIGN, // Constraint ignored
|
CONSTRAINTIGN, // Constraint ignored
|
||||||
CONTASSREG, // Continuous assignment on reg
|
CONTASSREG, // Continuous assignment on reg
|
||||||
|
COVERIGN, // Coverage ignored
|
||||||
DECLFILENAME, // Declaration doesn't match filename
|
DECLFILENAME, // Declaration doesn't match filename
|
||||||
DEFPARAM, // Style: Defparam
|
DEFPARAM, // Style: Defparam
|
||||||
DEPRECATED, // Feature will be deprecated
|
DEPRECATED, // Feature will be deprecated
|
||||||
@@ -194,7 +195,7 @@ public:
|
|||||||
"ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
"ALWCOMBORDER", "ASCRANGE", "ASSIGNDLY", "ASSIGNIN", "BADSTDPRAGMA",
|
||||||
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
"BLKANDNBLK", "BLKLOOPINIT", "BLKSEQ", "BSSPACE",
|
||||||
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CASTCONST", "CDCRSTLOGIC", "CLKDATA",
|
||||||
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG",
|
"CMPCONST", "COLONPLUS", "COMBDLY", "CONSTRAINTIGN", "CONTASSREG", "COVERIGN",
|
||||||
"DECLFILENAME", "DEFPARAM", "DEPRECATED",
|
"DECLFILENAME", "DEFPARAM", "DEPRECATED",
|
||||||
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK",
|
"ENCAPSULATED", "ENDLABEL", "ENUMVALUE", "EOFNEWLINE", "GENCLK",
|
||||||
"GENUNNAMED", "HIERBLOCK",
|
"GENUNNAMED", "HIERBLOCK",
|
||||||
|
|||||||
+5
-3
@@ -528,9 +528,11 @@ void fillinCosts(V3Graph* execMTaskGraphp) {
|
|||||||
|
|
||||||
if (missingProfiles) {
|
if (missingProfiles) {
|
||||||
if (FileLine* const fl = V3Config::getProfileDataFileLine()) {
|
if (FileLine* const fl = V3Config::getProfileDataFileLine()) {
|
||||||
fl->v3warn(PROFOUTOFDATE, "Profile data for mtasks may be out of date. "
|
if (V3Config::containsMTaskProfileData()) {
|
||||||
<< missingProfiles << " of " << totalEstimates
|
fl->v3warn(PROFOUTOFDATE, "Profile data for mtasks may be out of date. "
|
||||||
<< " mtasks had no data");
|
<< missingProfiles << " of " << totalEstimates
|
||||||
|
<< " mtasks had no data");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -183,6 +183,19 @@ public:
|
|||||||
, m_filenameno{singleton().nameToNumber(filename)}
|
, m_filenameno{singleton().nameToNumber(filename)}
|
||||||
, m_waive{false}
|
, m_waive{false}
|
||||||
, m_contentLineno{0} {}
|
, m_contentLineno{0} {}
|
||||||
|
explicit FileLine(const FileLine& from)
|
||||||
|
: m_msgEnIdx{from.m_msgEnIdx}
|
||||||
|
, m_filenameno{from.m_filenameno}
|
||||||
|
, m_waive{from.m_waive}
|
||||||
|
, m_contentLineno{from.m_contentLineno}
|
||||||
|
, m_firstLineno{from.m_firstLineno}
|
||||||
|
, m_firstColumn{from.m_firstColumn}
|
||||||
|
, m_lastLineno{from.m_lastLineno}
|
||||||
|
, m_lastColumn{from.m_lastColumn}
|
||||||
|
, m_contentp{from.m_contentp}
|
||||||
|
, m_parent{from.m_parent} {
|
||||||
|
if (m_contentp) m_contentp->refInc();
|
||||||
|
}
|
||||||
explicit FileLine(FileLine* fromp)
|
explicit FileLine(FileLine* fromp)
|
||||||
: m_msgEnIdx{fromp->m_msgEnIdx}
|
: m_msgEnIdx{fromp->m_msgEnIdx}
|
||||||
, m_filenameno{fromp->m_filenameno}
|
, m_filenameno{fromp->m_filenameno}
|
||||||
@@ -275,6 +288,7 @@ public:
|
|||||||
warnOn(V3ErrorCode::WIDTHEXPAND, flag);
|
warnOn(V3ErrorCode::WIDTHEXPAND, flag);
|
||||||
warnOn(V3ErrorCode::WIDTHXZEXPAND, flag);
|
warnOn(V3ErrorCode::WIDTHXZEXPAND, flag);
|
||||||
}
|
}
|
||||||
|
if (code == V3ErrorCode::E_UNSUPPORTED) warnOn(V3ErrorCode::COVERIGN, flag);
|
||||||
m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, code, flag);
|
m_msgEnIdx = singleton().msgEnSetBit(m_msgEnIdx, code, flag);
|
||||||
}
|
}
|
||||||
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
|
void warnOff(V3ErrorCode code, bool flag) { warnOn(code, !flag); }
|
||||||
|
|||||||
+1
-1
@@ -104,7 +104,7 @@ void V3Global::readFiles() {
|
|||||||
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));
|
// v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("parse.tree"));
|
||||||
V3Error::abortIfErrors();
|
V3Error::abortIfErrors();
|
||||||
|
|
||||||
if (!v3Global.opt.preprocOnly()) {
|
if (!v3Global.opt.preprocOnly() || v3Global.opt.preprocResolve()) {
|
||||||
// Resolve all modules cells refer to
|
// Resolve all modules cells refer to
|
||||||
V3LinkCells::link(v3Global.rootp(), &filter, &parseSyms);
|
V3LinkCells::link(v3Global.rootp(), &filter, &parseSyms);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -56,7 +56,6 @@ private:
|
|||||||
inline void V3LanguageWords::Singleton::init() {
|
inline void V3LanguageWords::Singleton::init() {
|
||||||
// C++ keywords
|
// C++ keywords
|
||||||
// clang-format off
|
// clang-format off
|
||||||
addKwd("nullptr", "C++ common word");
|
|
||||||
addKwd("abort", "C++ common word");
|
addKwd("abort", "C++ common word");
|
||||||
addKwd("alignas", "C++11 keyword");
|
addKwd("alignas", "C++11 keyword");
|
||||||
addKwd("alignof", "C++11 keyword");
|
addKwd("alignof", "C++11 keyword");
|
||||||
@@ -91,7 +90,6 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("decltype", "C++11 keyword");
|
addKwd("decltype", "C++11 keyword");
|
||||||
addKwd("default", "C++ keyword");
|
addKwd("default", "C++ keyword");
|
||||||
addKwd("delete", "C++ keyword");
|
addKwd("delete", "C++ keyword");
|
||||||
addKwd("deque", "C++ common word");
|
|
||||||
addKwd("do", "C++ keyword");
|
addKwd("do", "C++ keyword");
|
||||||
addKwd("double", "C++ keyword");
|
addKwd("double", "C++ keyword");
|
||||||
addKwd("dynamic_cast", "C++ keyword");
|
addKwd("dynamic_cast", "C++ keyword");
|
||||||
@@ -113,12 +111,8 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("int", "C++ keyword");
|
addKwd("int", "C++ keyword");
|
||||||
addKwd("interrupt", "C++ common word");
|
addKwd("interrupt", "C++ common word");
|
||||||
addKwd("iterator", "C++ common word");
|
addKwd("iterator", "C++ common word");
|
||||||
addKwd("list", "C++ common word");
|
|
||||||
addKwd("long", "C++ keyword");
|
addKwd("long", "C++ keyword");
|
||||||
addKwd("map", "C++ common word");
|
|
||||||
addKwd("module", "C++ modules TS keyword");
|
addKwd("module", "C++ modules TS keyword");
|
||||||
addKwd("std::multimap", "C++ common word");
|
|
||||||
addKwd("std::multiset", "C++ common word");
|
|
||||||
addKwd("mutable", "C++ keyword");
|
addKwd("mutable", "C++ keyword");
|
||||||
addKwd("namespace", "C++ keyword");
|
addKwd("namespace", "C++ keyword");
|
||||||
addKwd("near", "C++ common word");
|
addKwd("near", "C++ common word");
|
||||||
@@ -126,6 +120,7 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("noexcept", "C++11 keyword");
|
addKwd("noexcept", "C++11 keyword");
|
||||||
addKwd("not", "C++ keyword");
|
addKwd("not", "C++ keyword");
|
||||||
addKwd("not_eq", "C++ keyword");
|
addKwd("not_eq", "C++ keyword");
|
||||||
|
addKwd("nullptr", "C++ common word");
|
||||||
addKwd("nullptr", "C++11 keyword");
|
addKwd("nullptr", "C++11 keyword");
|
||||||
addKwd("operator", "C++ keyword");
|
addKwd("operator", "C++ keyword");
|
||||||
addKwd("or", "C++ keyword");
|
addKwd("or", "C++ keyword");
|
||||||
@@ -142,7 +137,6 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("requires", "C++20 keyword");
|
addKwd("requires", "C++20 keyword");
|
||||||
addKwd("restrict", "C++ keyword");
|
addKwd("restrict", "C++ keyword");
|
||||||
addKwd("return", "C++ keyword");
|
addKwd("return", "C++ keyword");
|
||||||
addKwd("set", "C++ common word");
|
|
||||||
addKwd("short", "C++ keyword");
|
addKwd("short", "C++ keyword");
|
||||||
addKwd("signed", "C++ keyword");
|
addKwd("signed", "C++ keyword");
|
||||||
addKwd("sizeof", "C++ keyword");
|
addKwd("sizeof", "C++ keyword");
|
||||||
@@ -150,6 +144,13 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("static", "C++ keyword");
|
addKwd("static", "C++ keyword");
|
||||||
addKwd("static_assert", "C++11 keyword");
|
addKwd("static_assert", "C++11 keyword");
|
||||||
addKwd("static_cast", "C++ keyword");
|
addKwd("static_cast", "C++ keyword");
|
||||||
|
addKwd("std::deque", "C++ common word");
|
||||||
|
addKwd("std::list", "C++ common word");
|
||||||
|
addKwd("std::map", "C++ common word");
|
||||||
|
addKwd("std::multimap", "C++ common word");
|
||||||
|
addKwd("std::multiset", "C++ common word");
|
||||||
|
addKwd("std::set", "C++ common word");
|
||||||
|
addKwd("std::vector", "C++ common word");
|
||||||
addKwd("struct", "C++ keyword");
|
addKwd("struct", "C++ keyword");
|
||||||
addKwd("switch", "C++ keyword");
|
addKwd("switch", "C++ keyword");
|
||||||
addKwd("synchronized", "C++ TM TS keyword");
|
addKwd("synchronized", "C++ TM TS keyword");
|
||||||
@@ -171,7 +172,6 @@ inline void V3LanguageWords::Singleton::init() {
|
|||||||
addKwd("union", "C++ keyword");
|
addKwd("union", "C++ keyword");
|
||||||
addKwd("unsigned", "C++ keyword");
|
addKwd("unsigned", "C++ keyword");
|
||||||
addKwd("using", "C++ keyword");
|
addKwd("using", "C++ keyword");
|
||||||
addKwd("vector", "C++ common word");
|
|
||||||
addKwd("virtual", "C++ keyword");
|
addKwd("virtual", "C++ keyword");
|
||||||
addKwd("void", "C++ keyword");
|
addKwd("void", "C++ keyword");
|
||||||
addKwd("volatile", "C++ keyword");
|
addKwd("volatile", "C++ keyword");
|
||||||
|
|||||||
+2
-2
@@ -287,8 +287,8 @@ class LifeVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstNodeAssign* nodep) override {
|
void visit(AstNodeAssign* nodep) override {
|
||||||
if (nodep->isTimingControl()) {
|
if (nodep->isTimingControl() || VN_IS(nodep, AssignForce)) {
|
||||||
// V3Life doesn't understand time sense - don't optimize
|
// V3Life doesn't understand time sense nor force assigns - don't optimize
|
||||||
setNoopt();
|
setNoopt();
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
return;
|
return;
|
||||||
|
|||||||
+44
-15
@@ -986,8 +986,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
if (nodep->hierParams()) {
|
if (nodep->hierParams()) {
|
||||||
UINFO(1, "Found module with hier type parameters" << endl);
|
UINFO(1, "Found module with hier type parameters" << endl);
|
||||||
m_hierParamsName = nodep->name();
|
m_hierParamsName = nodep->name();
|
||||||
for (const AstNode* node = nodep->op2p(); node; node = node->nextp()) {
|
for (const AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
|
||||||
if (const AstTypedef* const tdef = VN_CAST(node, Typedef)) {
|
if (const AstTypedef* const tdef = VN_CAST(stmtp, Typedef)) {
|
||||||
UINFO(1, "Inserting hier type parameter typedef: " << tdef << endl);
|
UINFO(1, "Inserting hier type parameter typedef: " << tdef << endl);
|
||||||
VSymEnt* const upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp();
|
VSymEnt* const upperSymp = m_curSymp ? m_curSymp : m_statep->rootEntp();
|
||||||
m_curSymp = m_modSymp = m_statep->insertBlock(upperSymp, nodep->name(),
|
m_curSymp = m_modSymp = m_statep->insertBlock(upperSymp, nodep->name(),
|
||||||
@@ -1013,6 +1013,7 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
VL_RESTORER(m_modBlockNum);
|
VL_RESTORER(m_modBlockNum);
|
||||||
VL_RESTORER(m_modWithNum);
|
VL_RESTORER(m_modWithNum);
|
||||||
VL_RESTORER(m_modArgNum);
|
VL_RESTORER(m_modArgNum);
|
||||||
|
VL_RESTORER(m_explicitNew);
|
||||||
{
|
{
|
||||||
UINFO(4, " Link Class: " << nodep << endl);
|
UINFO(4, " Link Class: " << nodep << endl);
|
||||||
VSymEnt* const upperSymp = m_curSymp;
|
VSymEnt* const upperSymp = m_curSymp;
|
||||||
@@ -1176,12 +1177,39 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
// Change to appropriate package if extern declaration (vs definition)
|
// Change to appropriate package if extern declaration (vs definition)
|
||||||
if (nodep->classOrPackagep()) {
|
if (nodep->classOrPackagep()) {
|
||||||
|
// class-in-class
|
||||||
|
AstDot* const dotp = VN_CAST(nodep->classOrPackagep(), Dot);
|
||||||
AstClassOrPackageRef* const cpackagerefp
|
AstClassOrPackageRef* const cpackagerefp
|
||||||
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
|
= VN_CAST(nodep->classOrPackagep(), ClassOrPackageRef);
|
||||||
if (!cpackagerefp) {
|
if (dotp) {
|
||||||
nodep->v3warn(E_UNSUPPORTED,
|
AstClassOrPackageRef* const lhsp = VN_AS(dotp->lhsp(), ClassOrPackageRef);
|
||||||
"Unsupported: extern function definition with class-in-class");
|
m_statep->resolveClassOrPackage(m_curSymp, lhsp, false,
|
||||||
} else {
|
"External definition :: reference");
|
||||||
|
AstClass* const lhsclassp = VN_CAST(lhsp->classOrPackageSkipp(), Class);
|
||||||
|
if (!lhsclassp) {
|
||||||
|
nodep->v3error("Extern declaration's scope is not a defined class");
|
||||||
|
} else {
|
||||||
|
m_curSymp = m_statep->getNodeSym(lhsclassp);
|
||||||
|
upSymp = m_curSymp;
|
||||||
|
AstClassOrPackageRef* const rhsp = VN_AS(dotp->rhsp(), ClassOrPackageRef);
|
||||||
|
m_statep->resolveClassOrPackage(m_curSymp, rhsp, false,
|
||||||
|
"External definition :: reference");
|
||||||
|
AstClass* const rhsclassp = VN_CAST(rhsp->classOrPackageSkipp(), Class);
|
||||||
|
if (!rhsclassp) {
|
||||||
|
nodep->v3error("Extern declaration's scope is not a defined class");
|
||||||
|
} else {
|
||||||
|
m_curSymp = m_statep->getNodeSym(rhsclassp);
|
||||||
|
upSymp = m_curSymp;
|
||||||
|
if (!nodep->isExternDef()) {
|
||||||
|
// Move it to proper spot under the target class
|
||||||
|
nodep->unlinkFrBack();
|
||||||
|
rhsclassp->addStmtsp(nodep);
|
||||||
|
nodep->isExternDef(true); // So we check there's a matching extern
|
||||||
|
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (cpackagerefp) {
|
||||||
if (!cpackagerefp->classOrPackageSkipp()) {
|
if (!cpackagerefp->classOrPackageSkipp()) {
|
||||||
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false,
|
m_statep->resolveClassOrPackage(m_curSymp, cpackagerefp, false,
|
||||||
"External definition :: reference");
|
"External definition :: reference");
|
||||||
@@ -1200,6 +1228,8 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
nodep->classOrPackagep()->unlinkFrBack()->deleteTree();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
v3fatalSrc("Unhandled extern function definition package");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Set the class as package for iteration
|
// Set the class as package for iteration
|
||||||
@@ -1501,9 +1531,9 @@ class LinkDotFindVisitor final : public VNVisitor {
|
|||||||
if (const VSymEnt* const typedefEntp = m_curSymp->findIdFallback(m_hierParamsName)) {
|
if (const VSymEnt* const typedefEntp = m_curSymp->findIdFallback(m_hierParamsName)) {
|
||||||
const AstModule* modp = VN_CAST(typedefEntp->nodep(), Module);
|
const AstModule* modp = VN_CAST(typedefEntp->nodep(), Module);
|
||||||
|
|
||||||
for (const AstNode* node = modp ? modp->stmtsp() : nullptr; node;
|
for (const AstNode* stmtp = modp ? modp->stmtsp() : nullptr; stmtp;
|
||||||
node = node->nextp()) {
|
stmtp = stmtp->nextp()) {
|
||||||
const AstTypedef* tdefp = VN_CAST(node, Typedef);
|
const AstTypedef* tdefp = VN_CAST(stmtp, Typedef);
|
||||||
|
|
||||||
if (tdefp && tdefp->name() == nodep->name() && m_statep->forPrimary()) {
|
if (tdefp && tdefp->name() == nodep->name() && m_statep->forPrimary()) {
|
||||||
UINFO(8, "Replacing type of" << nodep << endl
|
UINFO(8, "Replacing type of" << nodep << endl
|
||||||
@@ -2336,11 +2366,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||||||
nodep->addStmtsp(superNewStmtp);
|
nodep->addStmtsp(superNewStmtp);
|
||||||
return superNewStmtp;
|
return superNewStmtp;
|
||||||
}
|
}
|
||||||
void taskFuncSwapCheck(AstNodeFTaskRef* nodep) {
|
|
||||||
if (nodep->taskp() && VN_IS(nodep->taskp(), Task) && VN_IS(nodep, FuncRef)) {
|
|
||||||
nodep->v3error("Illegal call of a task as a function: " << nodep->prettyNameQ());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void checkNoDot(AstNode* nodep) {
|
void checkNoDot(AstNode* nodep) {
|
||||||
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
|
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
|
||||||
// UINFO(9, indent() << "ds=" << m_ds.ascii() << endl);
|
// UINFO(9, indent() << "ds=" << m_ds.ascii() << endl);
|
||||||
@@ -3779,7 +3804,6 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||||||
okSymp->cellErrorScopes(nodep);
|
okSymp->cellErrorScopes(nodep);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
taskFuncSwapCheck(nodep);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstSelBit* nodep) override {
|
void visit(AstSelBit* nodep) override {
|
||||||
@@ -4013,6 +4037,11 @@ class LinkDotResolveVisitor final : public VNVisitor {
|
|||||||
LINKDOT_VISIT_START();
|
LINKDOT_VISIT_START();
|
||||||
UINFO(5, indent() << "visit " << nodep << endl);
|
UINFO(5, indent() << "visit " << nodep << endl);
|
||||||
checkNoDot(nodep);
|
checkNoDot(nodep);
|
||||||
|
AstClass* const topclassp = VN_CAST(m_modp, Class);
|
||||||
|
if (nodep->isInterfaceClass() && topclassp && topclassp->isInterfaceClass()) {
|
||||||
|
nodep->v3error("Interface class shall not be nested within another interface class."
|
||||||
|
" (IEEE 1800-2023 8.26)");
|
||||||
|
}
|
||||||
VL_RESTORER(m_curSymp);
|
VL_RESTORER(m_curSymp);
|
||||||
VL_RESTORER(m_modSymp);
|
VL_RESTORER(m_modSymp);
|
||||||
VL_RESTORER(m_modp);
|
VL_RESTORER(m_modp);
|
||||||
|
|||||||
+67
-3
@@ -27,6 +27,7 @@
|
|||||||
// Create a temporary __VIncrementX variable, assign the value of
|
// Create a temporary __VIncrementX variable, assign the value of
|
||||||
// of the current variable (after the operation) to it. Substitute
|
// of the current variable (after the operation) to it. Substitute
|
||||||
// The original variable with the temporary one in the statement.
|
// The original variable with the temporary one in the statement.
|
||||||
|
//
|
||||||
// prepost_stmt_visit
|
// prepost_stmt_visit
|
||||||
// PREADD/PRESUB/POSTADD/POSTSUB
|
// PREADD/PRESUB/POSTADD/POSTSUB
|
||||||
// Increment/decrement the current variable by the given value.
|
// Increment/decrement the current variable by the given value.
|
||||||
@@ -34,6 +35,12 @@
|
|||||||
// the pre/post operations are treated equally and there is no
|
// the pre/post operations are treated equally and there is no
|
||||||
// need for a temporary variable.
|
// need for a temporary variable.
|
||||||
//
|
//
|
||||||
|
// prepost_stmt_sel_visit
|
||||||
|
// For e.g. 'array[something_with_side_eff]++', common in UVM etc
|
||||||
|
// PREADD/PRESUB/POSTADD/POSTSUB
|
||||||
|
// Create temporary with array index.
|
||||||
|
// Increment/decrement using index of the temporary.
|
||||||
|
//
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
|
|
||||||
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
#include "V3PchAstNoMT.h" // VL_MT_DISABLED_CODE_UNIT
|
||||||
@@ -205,12 +212,69 @@ class LinkIncVisitor final : public VNVisitor {
|
|||||||
void visit(AstPropSpec* nodep) override { unsupported_visit(nodep); }
|
void visit(AstPropSpec* nodep) override { unsupported_visit(nodep); }
|
||||||
void prepost_visit(AstNodeTriop* nodep) {
|
void prepost_visit(AstNodeTriop* nodep) {
|
||||||
// Check if we are underneath a statement
|
// Check if we are underneath a statement
|
||||||
if (!m_insStmtp) {
|
AstSelBit* const selbitp = VN_CAST(nodep->thsp(), SelBit);
|
||||||
prepost_stmt_visit(nodep);
|
if (!m_insStmtp && selbitp && VN_IS(selbitp->fromp(), NodeVarRef)
|
||||||
|
&& !selbitp->bitp()->isPure()) {
|
||||||
|
prepost_stmt_sel_visit(nodep);
|
||||||
} else {
|
} else {
|
||||||
prepost_expr_visit(nodep);
|
// Purity check was deferred at creation in verilog.y, check now
|
||||||
|
nodep->thsp()->purityCheck();
|
||||||
|
if (!m_insStmtp) {
|
||||||
|
prepost_stmt_visit(nodep);
|
||||||
|
} else {
|
||||||
|
prepost_expr_visit(nodep);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
void prepost_stmt_sel_visit(AstNodeTriop* nodep) {
|
||||||
|
// Special case array[something]++, see comments at file top
|
||||||
|
// if (debug() >= 9) nodep->dumpTree("-pp-stmt-sel-in: ");
|
||||||
|
iterateChildren(nodep);
|
||||||
|
AstConst* const constp = VN_AS(nodep->lhsp(), Const);
|
||||||
|
UASSERT_OBJ(nodep, constp, "Expecting CONST");
|
||||||
|
AstConst* const newconstp = constp->cloneTree(true);
|
||||||
|
|
||||||
|
AstSelBit* const rdSelbitp = VN_CAST(nodep->rhsp(), SelBit);
|
||||||
|
AstNodeExpr* const rdFromp = rdSelbitp->fromp()->unlinkFrBack();
|
||||||
|
AstNodeExpr* const rdBitp = rdSelbitp->bitp()->unlinkFrBack();
|
||||||
|
AstSelBit* const wrSelbitp = VN_CAST(nodep->thsp(), SelBit);
|
||||||
|
AstNodeExpr* const wrFromp = wrSelbitp->fromp()->unlinkFrBack();
|
||||||
|
|
||||||
|
// Prepare a temporary variable
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
const string name = "__VincIndex"s + cvtToStr(++m_modIncrementsNum);
|
||||||
|
AstVar* const varp = new AstVar{
|
||||||
|
fl, VVarType::BLOCKTEMP, name, VFlagChildDType{},
|
||||||
|
new AstRefDType{fl, AstRefDType::FlagTypeOfExpr{}, rdBitp->cloneTree(true)}};
|
||||||
|
if (m_ftaskp) varp->funcLocal(true);
|
||||||
|
|
||||||
|
// Declare the variable
|
||||||
|
insertOnTop(varp);
|
||||||
|
|
||||||
|
// Define what operation will we be doing
|
||||||
|
AstAssign* const varAssignp
|
||||||
|
= new AstAssign{fl, new AstVarRef{fl, varp, VAccess::WRITE}, rdBitp};
|
||||||
|
AstNode* const newp = varAssignp;
|
||||||
|
|
||||||
|
AstNodeExpr* const valuep
|
||||||
|
= new AstSelBit{fl, rdFromp, new AstVarRef{fl, varp, VAccess::READ}};
|
||||||
|
AstNodeExpr* const storeTop
|
||||||
|
= new AstSelBit{fl, wrFromp, new AstVarRef{fl, varp, VAccess::READ}};
|
||||||
|
|
||||||
|
AstAssign* assignp;
|
||||||
|
if (VN_IS(nodep, PreSub) || VN_IS(nodep, PostSub)) {
|
||||||
|
assignp = new AstAssign{nodep->fileline(), storeTop,
|
||||||
|
new AstSub{nodep->fileline(), valuep, newconstp}};
|
||||||
|
} else {
|
||||||
|
assignp = new AstAssign{nodep->fileline(), storeTop,
|
||||||
|
new AstAdd{nodep->fileline(), valuep, newconstp}};
|
||||||
|
}
|
||||||
|
newp->addNext(assignp);
|
||||||
|
|
||||||
|
// if (debug() >= 9) newp->dumpTreeAndNext("-pp-stmt-sel-new: ");
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
|
}
|
||||||
void prepost_stmt_visit(AstNodeTriop* nodep) {
|
void prepost_stmt_visit(AstNodeTriop* nodep) {
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
AstConst* const constp = VN_AS(nodep->lhsp(), Const);
|
AstConst* const constp = VN_AS(nodep->lhsp(), Const);
|
||||||
|
|||||||
+19
-13
@@ -340,22 +340,20 @@ class LinkParseVisitor final : public VNVisitor {
|
|||||||
// Maybe this variable has a signal attribute
|
// Maybe this variable has a signal attribute
|
||||||
V3Config::applyVarAttr(m_modp, m_ftaskp, nodep);
|
V3Config::applyVarAttr(m_modp, m_ftaskp, nodep);
|
||||||
|
|
||||||
if (v3Global.opt.publicFlatRW()
|
if (v3Global.opt.anyPublicFlat() && nodep->varType().isVPIAccessible()) {
|
||||||
|| (v3Global.opt.publicDepth() && m_modp
|
if (v3Global.opt.publicFlatRW()) {
|
||||||
&& (m_modp->level() - 1) <= v3Global.opt.publicDepth())) {
|
nodep->sigUserRWPublic(true);
|
||||||
|
} else if (v3Global.opt.publicParams() && nodep->isParam()) {
|
||||||
switch (nodep->varType()) {
|
nodep->sigUserRWPublic(true);
|
||||||
case VVarType::VAR: // FALLTHRU
|
} else if (m_modp && v3Global.opt.publicDepth()) {
|
||||||
case VVarType::GPARAM: // FALLTHRU
|
if ((m_modp->level() - 1) <= v3Global.opt.publicDepth()) {
|
||||||
case VVarType::LPARAM: // FALLTHRU
|
nodep->sigUserRWPublic(true);
|
||||||
case VVarType::PORT: // FALLTHRU
|
} else if (VN_IS(m_modp, Package) && nodep->isParam()) {
|
||||||
case VVarType::WIRE: nodep->sigUserRWPublic(true); break;
|
nodep->sigUserRWPublic(true);
|
||||||
default: break;
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (v3Global.opt.publicParams() && nodep->isParam()) nodep->sigUserRWPublic(true);
|
|
||||||
|
|
||||||
// We used modTrace before leveling, and we may now
|
// We used modTrace before leveling, and we may now
|
||||||
// want to turn it off now that we know the levelizations
|
// want to turn it off now that we know the levelizations
|
||||||
if (v3Global.opt.traceDepth() && m_modp
|
if (v3Global.opt.traceDepth() && m_modp
|
||||||
@@ -720,6 +718,7 @@ class LinkParseVisitor final : public VNVisitor {
|
|||||||
nodep->name(newName);
|
nodep->name(newName);
|
||||||
nodep->origName(newName);
|
nodep->origName(newName);
|
||||||
}
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
void visit(AstGenCase* nodep) override {
|
void visit(AstGenCase* nodep) override {
|
||||||
++m_genblkNum;
|
++m_genblkNum;
|
||||||
@@ -895,6 +894,13 @@ class LinkParseVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
}
|
}
|
||||||
|
void visit(AstPackageImport* nodep) override {
|
||||||
|
cleanFileline(nodep);
|
||||||
|
if (m_modp && !m_ftaskp && VN_IS(m_modp, Class)) {
|
||||||
|
nodep->v3error("Import statement directly within a class scope is illegal");
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
}
|
||||||
|
|
||||||
void visit(AstNode* nodep) override {
|
void visit(AstNode* nodep) override {
|
||||||
// Default: Just iterate
|
// Default: Just iterate
|
||||||
|
|||||||
@@ -221,7 +221,8 @@ class LinkResolveVisitor final : public VNVisitor {
|
|||||||
letp->user2(false);
|
letp->user2(false);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (nodep->taskp() && (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) {
|
if (nodep->taskp() && !nodep->scopeNamep()
|
||||||
|
&& (nodep->taskp()->dpiContext() || nodep->taskp()->dpiExport())) {
|
||||||
nodep->scopeNamep(new AstScopeName{nodep->fileline(), false});
|
nodep->scopeNamep(new AstScopeName{nodep->fileline(), false});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+70
-42
@@ -99,8 +99,10 @@ public:
|
|||||||
}
|
}
|
||||||
void addLangExt(const string& langext, const V3LangCode& lc) {
|
void addLangExt(const string& langext, const V3LangCode& lc) {
|
||||||
// New language extension replaces any pre-existing one.
|
// New language extension replaces any pre-existing one.
|
||||||
(void)m_langExts.erase(langext);
|
string addext = langext;
|
||||||
m_langExts[langext] = lc;
|
if (addext[0] == '.') addext = addext.substr(1);
|
||||||
|
(void)m_langExts.erase(addext);
|
||||||
|
m_langExts[addext] = lc;
|
||||||
}
|
}
|
||||||
|
|
||||||
void addLibExtV(const string& libext) {
|
void addLibExtV(const string& libext) {
|
||||||
@@ -953,9 +955,6 @@ void V3Options::notify() VL_MT_DISABLED {
|
|||||||
cmdfl->v3error("Unsupported: --timing and --savable not supported together");
|
cmdfl->v3error("Unsupported: --timing and --savable not supported together");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Mark options as available
|
|
||||||
m_available = true;
|
|
||||||
|
|
||||||
// --dump-tree-dot will turn on tree dumping.
|
// --dump-tree-dot will turn on tree dumping.
|
||||||
if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) {
|
if (!m_dumpLevel.count("tree") && m_dumpLevel.count("tree-dot")) {
|
||||||
m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
|
m_dumpLevel["tree"] = m_dumpLevel["tree-dot"];
|
||||||
@@ -963,9 +962,15 @@ void V3Options::notify() VL_MT_DISABLED {
|
|||||||
|
|
||||||
// Sanity check of expected configuration
|
// Sanity check of expected configuration
|
||||||
UASSERT(threads() >= 1, "'threads()' must return a value >= 1");
|
UASSERT(threads() >= 1, "'threads()' must return a value >= 1");
|
||||||
|
if (m_buildJobs == -1) m_buildJobs = 1;
|
||||||
|
if (m_verilateJobs == -1) m_verilateJobs = 1;
|
||||||
|
|
||||||
// Preprocessor defines based on options used
|
// Preprocessor defines based on options used
|
||||||
if (timing().isSetTrue()) V3PreShell::defineCmdLine("VERILATOR_TIMING", "1");
|
if (timing().isSetTrue()) V3PreShell::defineCmdLine("VERILATOR_TIMING", "1");
|
||||||
|
|
||||||
|
// === Leave last
|
||||||
|
// Mark options as available
|
||||||
|
m_available = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
@@ -1127,8 +1132,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
// Plus options
|
// Plus options
|
||||||
DECL_OPTION("+define+", CbPartialMatch,
|
DECL_OPTION("+define+", CbPartialMatch,
|
||||||
[this](const char* optp) VL_MT_DISABLED { addDefine(optp, true); });
|
[this](const char* optp) VL_MT_DISABLED { addDefine(optp, true); });
|
||||||
DECL_OPTION("+incdir+", CbPartialMatch,
|
DECL_OPTION("+incdir+", CbPartialMatch, [this, &optdir](const char* optp) {
|
||||||
[this, &optdir](const char* optp) { addIncDirUser(parseFileArg(optdir, optp)); });
|
string dirs = optp;
|
||||||
|
string::size_type pos;
|
||||||
|
while ((pos = dirs.find('+')) != string::npos) {
|
||||||
|
addIncDirUser(parseFileArg(optdir, dirs.substr(0, pos)));
|
||||||
|
dirs = dirs.substr(pos + 1);
|
||||||
|
}
|
||||||
|
addIncDirUser(parseFileArg(optdir, dirs));
|
||||||
|
});
|
||||||
DECL_OPTION("+libext+", CbPartialMatch, [this](const char* optp) {
|
DECL_OPTION("+libext+", CbPartialMatch, [this](const char* optp) {
|
||||||
string exts = optp;
|
string exts = optp;
|
||||||
string::size_type pos;
|
string::size_type pos;
|
||||||
@@ -1224,8 +1236,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
DECL_OPTION("-compiler-include", CbVal, callStrSetter(&V3Options::addCompilerIncludes));
|
DECL_OPTION("-compiler-include", CbVal, callStrSetter(&V3Options::addCompilerIncludes));
|
||||||
DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
|
|
||||||
DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
|
DECL_OPTION("-converge-limit", Set, &m_convergeLimit);
|
||||||
|
DECL_OPTION("-coverage", CbOnOff, [this](bool flag) { coverage(flag); });
|
||||||
|
DECL_OPTION("-coverage-expr", OnOff, &m_coverageExpr);
|
||||||
|
DECL_OPTION("-coverage-expr-max", Set, &m_coverageExprMax);
|
||||||
DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
|
DECL_OPTION("-coverage-line", OnOff, &m_coverageLine);
|
||||||
DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
|
DECL_OPTION("-coverage-max-width", Set, &m_coverageMaxWidth);
|
||||||
DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
|
DECL_OPTION("-coverage-toggle", OnOff, &m_coverageToggle);
|
||||||
@@ -1268,8 +1282,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
DECL_OPTION("-dumpi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
|
DECL_OPTION("-dumpi-", CbPartialMatchVal, [this](const char* optp, const char* valp) {
|
||||||
m_dumpLevel[optp] = std::atoi(valp);
|
m_dumpLevel[optp] = std::atoi(valp);
|
||||||
});
|
});
|
||||||
DECL_OPTION("-json-edit-nums", OnOff, &m_jsonEditNums);
|
|
||||||
DECL_OPTION("-json-ids", OnOff, &m_jsonIds);
|
|
||||||
DECL_OPTION("-E", CbOnOff, [this](bool flag) {
|
DECL_OPTION("-E", CbOnOff, [this](bool flag) {
|
||||||
if (flag) {
|
if (flag) {
|
||||||
m_stdPackage = false;
|
m_stdPackage = false;
|
||||||
@@ -1302,6 +1315,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
DECL_OPTION("-fconst", FOnOff, &m_fConst);
|
DECL_OPTION("-fconst", FOnOff, &m_fConst);
|
||||||
DECL_OPTION("-fconst-before-dfg", FOnOff, &m_fConstBeforeDfg);
|
DECL_OPTION("-fconst-before-dfg", FOnOff, &m_fConstBeforeDfg);
|
||||||
DECL_OPTION("-fconst-bit-op-tree", FOnOff, &m_fConstBitOpTree);
|
DECL_OPTION("-fconst-bit-op-tree", FOnOff, &m_fConstBitOpTree);
|
||||||
|
DECL_OPTION("-fdead-assigns", FOnOff, &m_fDeadAssigns);
|
||||||
|
DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells);
|
||||||
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
DECL_OPTION("-fdedup", FOnOff, &m_fDedupe);
|
||||||
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) {
|
DECL_OPTION("-fdfg", CbFOnOff, [this](bool flag) {
|
||||||
m_fDfgPreInline = flag;
|
m_fDfgPreInline = flag;
|
||||||
@@ -1316,8 +1331,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
});
|
});
|
||||||
DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline);
|
DECL_OPTION("-fdfg-pre-inline", FOnOff, &m_fDfgPreInline);
|
||||||
DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline);
|
DECL_OPTION("-fdfg-post-inline", FOnOff, &m_fDfgPostInline);
|
||||||
DECL_OPTION("-fdead-assigns", FOnOff, &m_fDeadAssigns);
|
|
||||||
DECL_OPTION("-fdead-cells", FOnOff, &m_fDeadCells);
|
|
||||||
DECL_OPTION("-fexpand", FOnOff, &m_fExpand);
|
DECL_OPTION("-fexpand", FOnOff, &m_fExpand);
|
||||||
DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { //
|
DECL_OPTION("-ffunc-opt", CbFOnOff, [this](bool flag) { //
|
||||||
m_fFuncSplitCat = flag;
|
m_fFuncSplitCat = flag;
|
||||||
@@ -1379,6 +1392,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
if (m_instrCountDpi < 0) fl->v3fatal("--instr-count-dpi must be non-negative: " << val);
|
if (m_instrCountDpi < 0) fl->v3fatal("--instr-count-dpi must be non-negative: " << val);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
DECL_OPTION("-json-edit-nums", OnOff, &m_jsonEditNums);
|
||||||
|
DECL_OPTION("-json-ids", OnOff, &m_jsonIds);
|
||||||
|
DECL_OPTION("-json-only", OnOff, &m_jsonOnly);
|
||||||
|
DECL_OPTION("-json-only-meta-output", CbVal, [this](const char* valp) {
|
||||||
|
m_jsonOnlyMetaOutput = valp;
|
||||||
|
m_jsonOnly = true;
|
||||||
|
});
|
||||||
|
DECL_OPTION("-json-only-output", CbVal, [this](const char* valp) {
|
||||||
|
m_jsonOnlyOutput = valp;
|
||||||
|
m_jsonOnly = true;
|
||||||
|
});
|
||||||
|
|
||||||
DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs));
|
DECL_OPTION("-LDFLAGS", CbVal, callStrSetter(&V3Options::addLdLibs));
|
||||||
DECL_OPTION("-l2-name", Set, &m_l2Name);
|
DECL_OPTION("-l2-name", Set, &m_l2Name);
|
||||||
DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical
|
DECL_OPTION("-no-l2name", CbCall, [this]() { m_l2Name = ""; }).undocumented(); // Historical
|
||||||
@@ -1403,7 +1428,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
});
|
});
|
||||||
DECL_OPTION("-lint-only", OnOff, &m_lintOnly);
|
DECL_OPTION("-lint-only", OnOff, &m_lintOnly);
|
||||||
DECL_OPTION("-localize-max-size", Set, &m_localizeMaxSize);
|
DECL_OPTION("-localize-max-size", Set, &m_localizeMaxSize);
|
||||||
DECL_OPTION("-main-top-name", Set, &m_mainTopName);
|
|
||||||
|
|
||||||
DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags));
|
DECL_OPTION("-MAKEFLAGS", CbVal, callStrSetter(&V3Options::addMakeFlags));
|
||||||
DECL_OPTION("-MMD", OnOff, &m_makeDepend);
|
DECL_OPTION("-MMD", OnOff, &m_makeDepend);
|
||||||
@@ -1413,6 +1437,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
addIncDirFallback(m_makeDir); // Need to find generated files there too
|
addIncDirFallback(m_makeDir); // Need to find generated files there too
|
||||||
});
|
});
|
||||||
DECL_OPTION("-main", OnOff, &m_main);
|
DECL_OPTION("-main", OnOff, &m_main);
|
||||||
|
DECL_OPTION("-main-top-name", Set, &m_mainTopName);
|
||||||
DECL_OPTION("-make", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-make", CbVal, [this, fl](const char* valp) {
|
||||||
if (!std::strcmp(valp, "cmake")) {
|
if (!std::strcmp(valp, "cmake")) {
|
||||||
m_cmake = true;
|
m_cmake = true;
|
||||||
@@ -1437,6 +1462,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
DECL_OPTION("-order-clock-delay", CbOnOff, [fl](bool /*flag*/) {
|
DECL_OPTION("-order-clock-delay", CbOnOff, [fl](bool /*flag*/) {
|
||||||
fl->v3warn(DEPRECATED, "Option order-clock-delay is deprecated and has no effect.");
|
fl->v3warn(DEPRECATED, "Option order-clock-delay is deprecated and has no effect.");
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-output-groups", CbVal, [this, fl](const char* valp) {
|
||||||
|
m_outputGroups = std::atoi(valp);
|
||||||
|
if (m_outputGroups < 0) { fl->v3error("--output-groups must be >= 0: " << valp); }
|
||||||
|
});
|
||||||
DECL_OPTION("-output-split", Set, &m_outputSplit);
|
DECL_OPTION("-output-split", Set, &m_outputSplit);
|
||||||
DECL_OPTION("-output-split-cfuncs", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-output-split-cfuncs", CbVal, [this, fl](const char* valp) {
|
||||||
m_outputSplitCFuncs = std::atoi(valp);
|
m_outputSplitCFuncs = std::atoi(valp);
|
||||||
@@ -1450,20 +1479,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
fl->v3error("--output-split-ctrace must be >= 0: " << valp);
|
fl->v3error("--output-split-ctrace must be >= 0: " << valp);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
DECL_OPTION("-output-groups", CbVal, [this, fl](const char* valp) {
|
|
||||||
m_outputGroups = std::atoi(valp);
|
|
||||||
if (m_outputGroups < 0) { fl->v3error("--output-groups must be >= 0: " << valp); }
|
|
||||||
});
|
|
||||||
|
|
||||||
DECL_OPTION("-P", Set, &m_preprocNoLine);
|
DECL_OPTION("-P", Set, &m_preprocNoLine);
|
||||||
DECL_OPTION("-pvalue+", CbPartialMatch,
|
|
||||||
[this](const char* varp) { addParameter(varp, false); });
|
|
||||||
DECL_OPTION("-pins64", CbCall, [this]() { m_pinsBv = 65; });
|
DECL_OPTION("-pins64", CbCall, [this]() { m_pinsBv = 65; });
|
||||||
DECL_OPTION("-no-pins64", CbCall, [this]() { m_pinsBv = 33; });
|
DECL_OPTION("-no-pins64", CbCall, [this]() { m_pinsBv = 33; });
|
||||||
DECL_OPTION("-pins-bv", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-pins-bv", CbVal, [this, fl](const char* valp) {
|
||||||
m_pinsBv = std::atoi(valp);
|
m_pinsBv = std::atoi(valp);
|
||||||
if (m_pinsBv > 65) fl->v3fatal("--pins-bv maximum is 65: " << valp);
|
if (m_pinsBv > 65) fl->v3fatal("--pins-bv maximum is 65: " << valp);
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-pins-inout-enables", OnOff, &m_pinsInoutEnables);
|
||||||
DECL_OPTION("-pins-sc-uint", CbOnOff, [this](bool flag) {
|
DECL_OPTION("-pins-sc-uint", CbOnOff, [this](bool flag) {
|
||||||
m_pinsScUint = flag;
|
m_pinsScUint = flag;
|
||||||
if (!m_pinsScBigUint) m_pinsBv = 65;
|
if (!m_pinsScBigUint) m_pinsBv = 65;
|
||||||
@@ -1473,7 +1497,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
m_pinsScBigUint = flag;
|
m_pinsScBigUint = flag;
|
||||||
m_pinsBv = 513;
|
m_pinsBv = 513;
|
||||||
});
|
});
|
||||||
DECL_OPTION("-pins-inout-enables", OnOff, &m_pinsInoutEnables);
|
|
||||||
DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8);
|
DECL_OPTION("-pins-uint8", OnOff, &m_pinsUint8);
|
||||||
DECL_OPTION("-pipe-filter", Set, &m_pipeFilter);
|
DECL_OPTION("-pipe-filter", Set, &m_pipeFilter);
|
||||||
DECL_OPTION("-pp-comments", OnOff, &m_ppComments);
|
DECL_OPTION("-pp-comments", OnOff, &m_ppComments);
|
||||||
@@ -1481,13 +1504,18 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
validateIdentifier(fl, valp, "--prefix");
|
validateIdentifier(fl, valp, "--prefix");
|
||||||
m_prefix = valp;
|
m_prefix = valp;
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-preproc-resolve", OnOff, &m_preprocResolve);
|
||||||
|
DECL_OPTION("-preproc-token-limit", CbVal, [this, fl](const char* valp) {
|
||||||
|
m_preprocTokenLimit = std::atoi(valp);
|
||||||
|
if (m_preprocTokenLimit <= 0) fl->v3error("--preproc-token-limit must be > 0: " << valp);
|
||||||
|
});
|
||||||
DECL_OPTION("-private", CbCall, [this]() { m_public = false; });
|
DECL_OPTION("-private", CbCall, [this]() { m_public = false; });
|
||||||
DECL_OPTION("-prof-c", OnOff, &m_profC);
|
DECL_OPTION("-prof-c", OnOff, &m_profC);
|
||||||
DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; });
|
DECL_OPTION("-prof-cfuncs", CbCall, [this]() { m_profC = m_profCFuncs = true; });
|
||||||
DECL_OPTION("-profile-cfuncs", CbCall,
|
|
||||||
[this]() { m_profC = m_profCFuncs = true; }); // Renamed
|
|
||||||
DECL_OPTION("-prof-exec", OnOff, &m_profExec);
|
DECL_OPTION("-prof-exec", OnOff, &m_profExec);
|
||||||
DECL_OPTION("-prof-pgo", OnOff, &m_profPgo);
|
DECL_OPTION("-prof-pgo", OnOff, &m_profPgo);
|
||||||
|
DECL_OPTION("-profile-cfuncs", CbCall,
|
||||||
|
[this]() { m_profC = m_profCFuncs = true; }); // Renamed
|
||||||
DECL_OPTION("-protect-ids", OnOff, &m_protectIds);
|
DECL_OPTION("-protect-ids", OnOff, &m_protectIds);
|
||||||
DECL_OPTION("-protect-key", Set, &m_protectKey);
|
DECL_OPTION("-protect-key", Set, &m_protectKey);
|
||||||
DECL_OPTION("-protect-lib", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-protect-lib", CbVal, [this, fl](const char* valp) {
|
||||||
@@ -1501,10 +1529,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
m_publicFlatRW = flag;
|
m_publicFlatRW = flag;
|
||||||
v3Global.dpi(true);
|
v3Global.dpi(true);
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-public-ignore", CbOnOff, [this](bool flag) { m_publicIgnore = flag; });
|
||||||
DECL_OPTION("-public-params", CbOnOff, [this](bool flag) {
|
DECL_OPTION("-public-params", CbOnOff, [this](bool flag) {
|
||||||
m_public_params = flag;
|
m_publicParams = flag;
|
||||||
v3Global.dpi(true);
|
v3Global.dpi(true);
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-pvalue+", CbPartialMatch,
|
||||||
|
[this](const char* varp) { addParameter(varp, false); });
|
||||||
|
|
||||||
DECL_OPTION("-quiet", CbOnOff, [this](bool flag) {
|
DECL_OPTION("-quiet", CbOnOff, [this](bool flag) {
|
||||||
m_quietExit = flag;
|
m_quietExit = flag;
|
||||||
m_quietStats = flag;
|
m_quietStats = flag;
|
||||||
@@ -1550,7 +1582,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
DECL_OPTION("-structs-packed", OnOff, &m_structsPacked);
|
DECL_OPTION("-structs-packed", OnOff, &m_structsPacked);
|
||||||
DECL_OPTION("-sv", CbCall, [this]() { m_defaultLanguage = V3LangCode::L1800_2023; });
|
DECL_OPTION("-sv", CbCall, [this]() { m_defaultLanguage = V3LangCode::L1800_2023; });
|
||||||
|
|
||||||
DECL_OPTION("-threads-coarsen", OnOff, &m_threadsCoarsen).undocumented(); // Debug
|
|
||||||
DECL_OPTION("-no-threads", CbCall, [this, fl]() {
|
DECL_OPTION("-no-threads", CbCall, [this, fl]() {
|
||||||
fl->v3warn(DEPRECATED, "Option --no-threads is deprecated, use '--threads 1' instead");
|
fl->v3warn(DEPRECATED, "Option --no-threads is deprecated, use '--threads 1' instead");
|
||||||
m_threads = 1;
|
m_threads = 1;
|
||||||
@@ -1563,6 +1594,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
m_threads = 1;
|
m_threads = 1;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-threads-coarsen", OnOff, &m_threadsCoarsen).undocumented(); // Debug
|
||||||
DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-threads-dpi", CbVal, [this, fl](const char* valp) {
|
||||||
if (!std::strcmp(valp, "all")) {
|
if (!std::strcmp(valp, "all")) {
|
||||||
m_threadsDpiPure = true;
|
m_threadsDpiPure = true;
|
||||||
@@ -1604,9 +1636,8 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
DECL_OPTION("-timing", OnOff, &m_timing);
|
DECL_OPTION("-timing", OnOff, &m_timing);
|
||||||
DECL_OPTION("-top-module", Set, &m_topModule);
|
|
||||||
DECL_OPTION("-top", Set, &m_topModule);
|
DECL_OPTION("-top", Set, &m_topModule);
|
||||||
DECL_OPTION("-no-trace-top", Set, &m_noTraceTop);
|
DECL_OPTION("-top-module", Set, &m_topModule);
|
||||||
DECL_OPTION("-trace", OnOff, &m_trace);
|
DECL_OPTION("-trace", OnOff, &m_trace);
|
||||||
DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage);
|
DECL_OPTION("-trace-coverage", OnOff, &m_traceCoverage);
|
||||||
DECL_OPTION("-trace-depth", Set, &m_traceDepth);
|
DECL_OPTION("-trace-depth", Set, &m_traceDepth);
|
||||||
@@ -1632,6 +1663,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
m_traceThreads = std::atoi(valp);
|
m_traceThreads = std::atoi(valp);
|
||||||
if (m_traceThreads < 1) fl->v3fatal("--trace-threads must be >= 1: " << valp);
|
if (m_traceThreads < 1) fl->v3fatal("--trace-threads must be >= 1: " << valp);
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-no-trace-top", Set, &m_noTraceTop);
|
||||||
DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore);
|
DECL_OPTION("-trace-underscore", OnOff, &m_traceUnderscore);
|
||||||
|
|
||||||
DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef);
|
DECL_OPTION("-U", CbPartialMatch, &V3PreShell::undef);
|
||||||
@@ -1649,6 +1681,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
V3Options::addLibraryFile(parseFileArg(optdir, valp));
|
V3Options::addLibraryFile(parseFileArg(optdir, valp));
|
||||||
});
|
});
|
||||||
DECL_OPTION("-valgrind", CbCall, []() {}); // Processed only in bin/verilator shell
|
DECL_OPTION("-valgrind", CbCall, []() {}); // Processed only in bin/verilator shell
|
||||||
|
DECL_OPTION("-verilate", OnOff, &m_verilate);
|
||||||
DECL_OPTION("-verilate-jobs", CbVal, [this, fl](const char* valp) {
|
DECL_OPTION("-verilate-jobs", CbVal, [this, fl](const char* valp) {
|
||||||
int val = std::atoi(valp);
|
int val = std::atoi(valp);
|
||||||
if (val < 0) {
|
if (val < 0) {
|
||||||
@@ -1660,17 +1693,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
}
|
}
|
||||||
m_verilateJobs = val;
|
m_verilateJobs = val;
|
||||||
});
|
});
|
||||||
DECL_OPTION("-verilate", OnOff, &m_verilate);
|
|
||||||
DECL_OPTION("-version", CbCall, [this]() {
|
DECL_OPTION("-version", CbCall, [this]() {
|
||||||
showVersion(false);
|
showVersion(false);
|
||||||
std::exit(0);
|
std::exit(0);
|
||||||
});
|
});
|
||||||
DECL_OPTION("-vpi", OnOff, &m_vpi);
|
DECL_OPTION("-vpi", OnOff, &m_vpi);
|
||||||
|
|
||||||
DECL_OPTION("-Wpedantic", CbCall, [this]() {
|
|
||||||
m_pedantic = true;
|
|
||||||
V3Error::pretendError(V3ErrorCode::ASSIGNIN, false);
|
|
||||||
});
|
|
||||||
DECL_OPTION("-Wall", CbCall, []() {
|
DECL_OPTION("-Wall", CbCall, []() {
|
||||||
FileLine::globalWarnLintOff(false);
|
FileLine::globalWarnLintOff(false);
|
||||||
FileLine::globalWarnStyleOff(false);
|
FileLine::globalWarnStyleOff(false);
|
||||||
@@ -1713,6 +1741,10 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); });
|
DECL_OPTION("-Wno-style", CbCall, []() { FileLine::globalWarnStyleOff(true); });
|
||||||
DECL_OPTION("-Wno-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); });
|
DECL_OPTION("-Wno-UNUSED", CbCall, []() { FileLine::globalWarnUnusedOff(true); });
|
||||||
DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); });
|
DECL_OPTION("-Wno-WIDTH", CbCall, []() { FileLine::globalWarnOff(V3ErrorCode::WIDTH, true); });
|
||||||
|
DECL_OPTION("-Wpedantic", CbCall, [this]() {
|
||||||
|
m_pedantic = true;
|
||||||
|
V3Error::pretendError(V3ErrorCode::ASSIGNIN, false);
|
||||||
|
});
|
||||||
DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) VL_MT_DISABLED {
|
DECL_OPTION("-Wwarn-", CbPartialMatch, [this, fl, &parser](const char* optp) VL_MT_DISABLED {
|
||||||
const V3ErrorCode code{optp};
|
const V3ErrorCode code{optp};
|
||||||
if (code == V3ErrorCode::EC_ERROR) {
|
if (code == V3ErrorCode::EC_ERROR) {
|
||||||
@@ -1735,6 +1767,12 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
V3Error::pretendError(V3ErrorCode::UNUSEDSIGNAL, false);
|
V3Error::pretendError(V3ErrorCode::UNUSEDSIGNAL, false);
|
||||||
V3Error::pretendError(V3ErrorCode::UNUSEDPARAM, false);
|
V3Error::pretendError(V3ErrorCode::UNUSEDPARAM, false);
|
||||||
});
|
});
|
||||||
|
DECL_OPTION("-Wwarn-UNSUPPORTED", CbCall, []() {
|
||||||
|
FileLine::globalWarnOff(V3ErrorCode::E_UNSUPPORTED, false);
|
||||||
|
FileLine::globalWarnOff(V3ErrorCode::COVERIGN, false);
|
||||||
|
V3Error::pretendError(V3ErrorCode::E_UNSUPPORTED, false);
|
||||||
|
V3Error::pretendError(V3ErrorCode::COVERIGN, false);
|
||||||
|
});
|
||||||
DECL_OPTION("-Wwarn-WIDTH", CbCall, []() {
|
DECL_OPTION("-Wwarn-WIDTH", CbCall, []() {
|
||||||
FileLine::globalWarnOff(V3ErrorCode::WIDTH, false);
|
FileLine::globalWarnOff(V3ErrorCode::WIDTH, false);
|
||||||
V3Error::pretendError(V3ErrorCode::WIDTH, false);
|
V3Error::pretendError(V3ErrorCode::WIDTH, false);
|
||||||
@@ -1776,19 +1814,11 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
m_xmlOutput = valp;
|
m_xmlOutput = valp;
|
||||||
m_xmlOnly = true;
|
m_xmlOnly = true;
|
||||||
});
|
});
|
||||||
DECL_OPTION("-json-only", OnOff, &m_jsonOnly);
|
|
||||||
DECL_OPTION("-json-only-output", CbVal, [this](const char* valp) {
|
|
||||||
m_jsonOnlyOutput = valp;
|
|
||||||
m_jsonOnly = true;
|
|
||||||
});
|
|
||||||
DECL_OPTION("-json-only-meta-output", CbVal, [this](const char* valp) {
|
|
||||||
m_jsonOnlyMetaOutput = valp;
|
|
||||||
m_jsonOnly = true;
|
|
||||||
});
|
|
||||||
|
|
||||||
DECL_OPTION("-y", CbVal, [this, &optdir](const char* valp) {
|
DECL_OPTION("-y", CbVal, [this, &optdir](const char* valp) {
|
||||||
addIncDirUser(parseFileArg(optdir, string{valp}));
|
addIncDirUser(parseFileArg(optdir, string{valp}));
|
||||||
});
|
});
|
||||||
|
|
||||||
parser.finalize();
|
parser.finalize();
|
||||||
|
|
||||||
for (int i = 0; i < argc;) {
|
for (int i = 0; i < argc;) {
|
||||||
@@ -1837,8 +1867,6 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc,
|
|||||||
++i;
|
++i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (m_buildJobs == -1) m_buildJobs = 1;
|
|
||||||
if (m_verilateJobs == -1) m_verilateJobs = 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|||||||
+24
-11
@@ -219,6 +219,7 @@ private:
|
|||||||
V3StringSet m_fDfgPeepholeDisabled; // argument: -f[no-]dfg-peephole-<name>
|
V3StringSet m_fDfgPeepholeDisabled; // argument: -f[no-]dfg-peephole-<name>
|
||||||
|
|
||||||
bool m_preprocOnly = false; // main switch: -E
|
bool m_preprocOnly = false; // main switch: -E
|
||||||
|
bool m_preprocResolve = false; // main switch: --preproc-resolve
|
||||||
bool m_makePhony = false; // main switch: -MP
|
bool m_makePhony = false; // main switch: -MP
|
||||||
bool m_preprocNoLine = false; // main switch: -P
|
bool m_preprocNoLine = false; // main switch: -P
|
||||||
bool m_assert = false; // main switch: --assert
|
bool m_assert = false; // main switch: --assert
|
||||||
@@ -230,6 +231,7 @@ private:
|
|||||||
bool m_build = false; // main switch: --build
|
bool m_build = false; // main switch: --build
|
||||||
bool m_cmake = false; // main switch: --make cmake
|
bool m_cmake = false; // main switch: --make cmake
|
||||||
bool m_context = true; // main switch: --Wcontext
|
bool m_context = true; // main switch: --Wcontext
|
||||||
|
bool m_coverageExpr = false; // main switch: --coverage-expr
|
||||||
bool m_coverageLine = false; // main switch: --coverage-block
|
bool m_coverageLine = false; // main switch: --coverage-block
|
||||||
bool m_coverageToggle = false; // main switch: --coverage-toggle
|
bool m_coverageToggle = false; // main switch: --coverage-toggle
|
||||||
bool m_coverageUnderscore = false; // main switch: --coverage-underscore
|
bool m_coverageUnderscore = false; // main switch: --coverage-underscore
|
||||||
@@ -255,6 +257,7 @@ private:
|
|||||||
bool m_flatten = false; // main switch: --flatten
|
bool m_flatten = false; // main switch: --flatten
|
||||||
bool m_hierarchical = false; // main switch: --hierarchical
|
bool m_hierarchical = false; // main switch: --hierarchical
|
||||||
bool m_ignc = false; // main switch: --ignc
|
bool m_ignc = false; // main switch: --ignc
|
||||||
|
bool m_jsonOnly = false; // main switch: --json-only
|
||||||
bool m_lintOnly = false; // main switch: --lint-only
|
bool m_lintOnly = false; // main switch: --lint-only
|
||||||
bool m_gmake = false; // main switch: --make gmake
|
bool m_gmake = false; // main switch: --make gmake
|
||||||
bool m_main = false; // main switch: --main
|
bool m_main = false; // main switch: --main
|
||||||
@@ -273,7 +276,8 @@ private:
|
|||||||
bool m_protectIds = false; // main switch: --protect-ids
|
bool m_protectIds = false; // main switch: --protect-ids
|
||||||
bool m_public = false; // main switch: --public
|
bool m_public = false; // main switch: --public
|
||||||
bool m_publicFlatRW = false; // main switch: --public-flat-rw
|
bool m_publicFlatRW = false; // main switch: --public-flat-rw
|
||||||
bool m_public_params = false; // main switch: --public-params
|
bool m_publicIgnore = false; // main switch: --public-ignore
|
||||||
|
bool m_publicParams = false; // main switch: --public-params
|
||||||
bool m_quietExit = false; // main switch: --quiet-exit
|
bool m_quietExit = false; // main switch: --quiet-exit
|
||||||
bool m_quietStats = false; // main switch: --quiet-stats
|
bool m_quietStats = false; // main switch: --quiet-stats
|
||||||
bool m_relativeIncludes = false; // main switch: --relative-includes
|
bool m_relativeIncludes = false; // main switch: --relative-includes
|
||||||
@@ -301,9 +305,9 @@ private:
|
|||||||
bool m_waiverMultiline = false; // main switch: --waiver-multiline
|
bool m_waiverMultiline = false; // main switch: --waiver-multiline
|
||||||
bool m_xInitialEdge = false; // main switch: --x-initial-edge
|
bool m_xInitialEdge = false; // main switch: --x-initial-edge
|
||||||
bool m_xmlOnly = false; // main switch: --xml-only
|
bool m_xmlOnly = false; // main switch: --xml-only
|
||||||
bool m_jsonOnly = false; // main switch: --json-only
|
|
||||||
|
|
||||||
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
int m_buildJobs = -1; // main switch: --build-jobs, -j
|
||||||
|
int m_coverageExprMax = 32; // main switch: --coverage-expr-max
|
||||||
int m_convergeLimit = 100; // main switch: --converge-limit
|
int m_convergeLimit = 100; // main switch: --converge-limit
|
||||||
int m_coverageMaxWidth = 256; // main switch: --coverage-max-width
|
int m_coverageMaxWidth = 256; // main switch: --coverage-max-width
|
||||||
int m_expandLimit = 64; // main switch: --expand-limit
|
int m_expandLimit = 64; // main switch: --expand-limit
|
||||||
@@ -323,6 +327,7 @@ private:
|
|||||||
int m_outputSplitCFuncs = -1; // main switch: --output-split-cfuncs
|
int m_outputSplitCFuncs = -1; // main switch: --output-split-cfuncs
|
||||||
int m_outputSplitCTrace = -1; // main switch: --output-split-ctrace
|
int m_outputSplitCTrace = -1; // main switch: --output-split-ctrace
|
||||||
int m_pinsBv = 65; // main switch: --pins-bv
|
int m_pinsBv = 65; // main switch: --pins-bv
|
||||||
|
int m_preprocTokenLimit = 40000; // main switch: --preproc-token-limit
|
||||||
int m_publicDepth = 0; // main switch: --public-depth
|
int m_publicDepth = 0; // main switch: --public-depth
|
||||||
int m_reloopLimit = 40; // main switch: --reloop-limit
|
int m_reloopLimit = 40; // main switch: --reloop-limit
|
||||||
VOptionBool m_skipIdentical; // main switch: --skip-identical
|
VOptionBool m_skipIdentical; // main switch: --skip-identical
|
||||||
@@ -350,6 +355,8 @@ private:
|
|||||||
string m_exeName; // main switch: -o {name}
|
string m_exeName; // main switch: -o {name}
|
||||||
string m_flags; // main switch: -f {name}
|
string m_flags; // main switch: -f {name}
|
||||||
string m_hierParamsFile; // main switch: --hierarchical-params-file
|
string m_hierParamsFile; // main switch: --hierarchical-params-file
|
||||||
|
string m_jsonOnlyOutput; // main switch: --json-only-output
|
||||||
|
string m_jsonOnlyMetaOutput; // main switch: --json-only-meta-output
|
||||||
string m_l2Name; // main switch: --l2name; "" for top-module's name
|
string m_l2Name; // main switch: --l2name; "" for top-module's name
|
||||||
string m_libCreate; // main switch: --lib-create {lib_name}
|
string m_libCreate; // main switch: --lib-create {lib_name}
|
||||||
string m_mainTopName; // main switch: --main-top-name
|
string m_mainTopName; // main switch: --main-top-name
|
||||||
@@ -364,8 +371,6 @@ private:
|
|||||||
string m_xAssign; // main switch: --x-assign
|
string m_xAssign; // main switch: --x-assign
|
||||||
string m_xInitial; // main switch: --x-initial
|
string m_xInitial; // main switch: --x-initial
|
||||||
string m_xmlOutput; // main switch: --xml-output
|
string m_xmlOutput; // main switch: --xml-output
|
||||||
string m_jsonOnlyOutput; // main switch: --json-only-output
|
|
||||||
string m_jsonOnlyMetaOutput; // main switch: --json-only-meta-output
|
|
||||||
|
|
||||||
// Language is now held in FileLine, on a per-node basis. However we still
|
// Language is now held in FileLine, on a per-node basis. However we still
|
||||||
// have a concept of the default language at a global level.
|
// have a concept of the default language at a global level.
|
||||||
@@ -424,7 +429,9 @@ private:
|
|||||||
void addLibExtV(const string& libext);
|
void addLibExtV(const string& libext);
|
||||||
void optimize(int level);
|
void optimize(int level);
|
||||||
void showVersion(bool verbose);
|
void showVersion(bool verbose);
|
||||||
void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
|
void coverage(bool flag) {
|
||||||
|
m_coverageLine = m_coverageToggle = m_coverageExpr = m_coverageUser = flag;
|
||||||
|
}
|
||||||
static bool suffixed(const string& sw, const char* arg);
|
static bool suffixed(const string& sw, const char* arg);
|
||||||
static string parseFileArg(const string& optdir, const string& relfilename);
|
static string parseFileArg(const string& optdir, const string& relfilename);
|
||||||
string filePathCheckOneDir(const string& modname, const string& dirname);
|
string filePathCheckOneDir(const string& modname, const string& dirname);
|
||||||
@@ -464,6 +471,8 @@ public:
|
|||||||
bool preprocOnly() const { return m_preprocOnly; }
|
bool preprocOnly() const { return m_preprocOnly; }
|
||||||
bool makePhony() const { return m_makePhony; }
|
bool makePhony() const { return m_makePhony; }
|
||||||
bool preprocNoLine() const { return m_preprocNoLine; }
|
bool preprocNoLine() const { return m_preprocNoLine; }
|
||||||
|
bool preprocResolve() const { return m_preprocResolve; }
|
||||||
|
int preprocTokenLimit() const { return m_preprocTokenLimit; }
|
||||||
bool underlineZero() const { return m_underlineZero; }
|
bool underlineZero() const { return m_underlineZero; }
|
||||||
string flags() const { return m_flags; }
|
string flags() const { return m_flags; }
|
||||||
bool systemC() const VL_MT_SAFE { return m_systemC; }
|
bool systemC() const VL_MT_SAFE { return m_systemC; }
|
||||||
@@ -485,8 +494,9 @@ public:
|
|||||||
bool cmake() const { return m_cmake; }
|
bool cmake() const { return m_cmake; }
|
||||||
bool context() const VL_MT_SAFE { return m_context; }
|
bool context() const VL_MT_SAFE { return m_context; }
|
||||||
bool coverage() const VL_MT_SAFE {
|
bool coverage() const VL_MT_SAFE {
|
||||||
return m_coverageLine || m_coverageToggle || m_coverageUser;
|
return m_coverageLine || m_coverageToggle || m_coverageExpr || m_coverageUser;
|
||||||
}
|
}
|
||||||
|
bool coverageExpr() const { return m_coverageExpr; }
|
||||||
bool coverageLine() const { return m_coverageLine; }
|
bool coverageLine() const { return m_coverageLine; }
|
||||||
bool coverageToggle() const { return m_coverageToggle; }
|
bool coverageToggle() const { return m_coverageToggle; }
|
||||||
bool coverageUnderscore() const { return m_coverageUnderscore; }
|
bool coverageUnderscore() const { return m_coverageUnderscore; }
|
||||||
@@ -526,6 +536,7 @@ public:
|
|||||||
bool traceUnderscore() const { return m_traceUnderscore; }
|
bool traceUnderscore() const { return m_traceUnderscore; }
|
||||||
bool main() const { return m_main; }
|
bool main() const { return m_main; }
|
||||||
bool outFormatOk() const { return m_outFormatOk; }
|
bool outFormatOk() const { return m_outFormatOk; }
|
||||||
|
bool jsonOnly() const { return m_jsonOnly; }
|
||||||
bool keepTempFiles() const { return (V3Error::debugDefault() != 0); }
|
bool keepTempFiles() const { return (V3Error::debugDefault() != 0); }
|
||||||
bool pedantic() const { return m_pedantic; }
|
bool pedantic() const { return m_pedantic; }
|
||||||
bool pinsInoutEnables() const { return m_pinsInoutEnables; }
|
bool pinsInoutEnables() const { return m_pinsInoutEnables; }
|
||||||
@@ -541,8 +552,11 @@ public:
|
|||||||
bool usesProfiler() const { return profExec() || profPgo(); }
|
bool usesProfiler() const { return profExec() || profPgo(); }
|
||||||
bool protectIds() const VL_MT_SAFE { return m_protectIds; }
|
bool protectIds() const VL_MT_SAFE { return m_protectIds; }
|
||||||
bool allPublic() const { return m_public; }
|
bool allPublic() const { return m_public; }
|
||||||
bool publicParams() const { return m_public_params; }
|
bool publicParams() const { return m_publicParams; }
|
||||||
|
bool publicOff() const { return m_publicIgnore; }
|
||||||
bool publicFlatRW() const { return m_publicFlatRW; }
|
bool publicFlatRW() const { return m_publicFlatRW; }
|
||||||
|
int publicDepth() const { return m_publicDepth; }
|
||||||
|
bool anyPublicFlat() const { return m_publicParams || m_publicFlatRW || m_publicDepth; }
|
||||||
bool lintOnly() const VL_MT_SAFE { return m_lintOnly; }
|
bool lintOnly() const VL_MT_SAFE { return m_lintOnly; }
|
||||||
bool ignc() const { return m_ignc; }
|
bool ignc() const { return m_ignc; }
|
||||||
bool quietExit() const VL_MT_SAFE { return m_quietExit; }
|
bool quietExit() const VL_MT_SAFE { return m_quietExit; }
|
||||||
@@ -553,12 +567,12 @@ public:
|
|||||||
bool waiverMultiline() const { return m_waiverMultiline; }
|
bool waiverMultiline() const { return m_waiverMultiline; }
|
||||||
bool xInitialEdge() const { return m_xInitialEdge; }
|
bool xInitialEdge() const { return m_xInitialEdge; }
|
||||||
bool xmlOnly() const { return m_xmlOnly; }
|
bool xmlOnly() const { return m_xmlOnly; }
|
||||||
bool jsonOnly() const { return m_jsonOnly; }
|
|
||||||
bool serializeOnly() const { return m_xmlOnly || m_jsonOnly; }
|
bool serializeOnly() const { return m_xmlOnly || m_jsonOnly; }
|
||||||
bool topIfacesSupported() const { return lintOnly() && !hierarchical(); }
|
bool topIfacesSupported() const { return lintOnly() && !hierarchical(); }
|
||||||
|
|
||||||
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
|
int buildJobs() const VL_MT_SAFE { return m_buildJobs; }
|
||||||
int convergeLimit() const { return m_convergeLimit; }
|
int convergeLimit() const { return m_convergeLimit; }
|
||||||
|
int coverageExprMax() const { return m_coverageExprMax; }
|
||||||
int coverageMaxWidth() const { return m_coverageMaxWidth; }
|
int coverageMaxWidth() const { return m_coverageMaxWidth; }
|
||||||
bool dumpTreeAddrids() const VL_MT_SAFE;
|
bool dumpTreeAddrids() const VL_MT_SAFE;
|
||||||
int expandLimit() const { return m_expandLimit; }
|
int expandLimit() const { return m_expandLimit; }
|
||||||
@@ -577,7 +591,6 @@ public:
|
|||||||
int outputSplitCTrace() const { return m_outputSplitCTrace; }
|
int outputSplitCTrace() const { return m_outputSplitCTrace; }
|
||||||
int outputGroups() const { return m_outputGroups; }
|
int outputGroups() const { return m_outputGroups; }
|
||||||
int pinsBv() const VL_MT_SAFE { return m_pinsBv; }
|
int pinsBv() const VL_MT_SAFE { return m_pinsBv; }
|
||||||
int publicDepth() const { return m_publicDepth; }
|
|
||||||
int reloopLimit() const { return m_reloopLimit; }
|
int reloopLimit() const { return m_reloopLimit; }
|
||||||
VOptionBool skipIdentical() const { return m_skipIdentical; }
|
VOptionBool skipIdentical() const { return m_skipIdentical; }
|
||||||
bool stopFail() const { return m_stopFail; }
|
bool stopFail() const { return m_stopFail; }
|
||||||
@@ -614,6 +627,8 @@ public:
|
|||||||
|
|
||||||
string exeName() const { return m_exeName != "" ? m_exeName : prefix(); }
|
string exeName() const { return m_exeName != "" ? m_exeName : prefix(); }
|
||||||
string hierParamFile() const { return m_hierParamsFile; }
|
string hierParamFile() const { return m_hierParamsFile; }
|
||||||
|
string jsonOnlyOutput() const { return m_jsonOnlyOutput; }
|
||||||
|
string jsonOnlyMetaOutput() const { return m_jsonOnlyMetaOutput; }
|
||||||
string l2Name() const { return m_l2Name; }
|
string l2Name() const { return m_l2Name; }
|
||||||
string libCreate() const { return m_libCreate; }
|
string libCreate() const { return m_libCreate; }
|
||||||
string libCreateName(bool shared) {
|
string libCreateName(bool shared) {
|
||||||
@@ -641,8 +656,6 @@ public:
|
|||||||
string xAssign() const { return m_xAssign; }
|
string xAssign() const { return m_xAssign; }
|
||||||
string xInitial() const { return m_xInitial; }
|
string xInitial() const { return m_xInitial; }
|
||||||
string xmlOutput() const { return m_xmlOutput; }
|
string xmlOutput() const { return m_xmlOutput; }
|
||||||
string jsonOnlyOutput() const { return m_jsonOnlyOutput; }
|
|
||||||
string jsonOnlyMetaOutput() const { return m_jsonOnlyMetaOutput; }
|
|
||||||
|
|
||||||
const V3StringSet& cppFiles() const { return m_cppFiles; }
|
const V3StringSet& cppFiles() const { return m_cppFiles; }
|
||||||
const V3StringList& cFlags() const { return m_cFlags; }
|
const V3StringList& cFlags() const { return m_cFlags; }
|
||||||
|
|||||||
@@ -1710,7 +1710,11 @@ class DpiImportCallVisitor final : public VNVisitor {
|
|||||||
if (nodep->dpiImportWrapper()) {
|
if (nodep->dpiImportWrapper()) {
|
||||||
if (nodep->dpiPure() ? !v3Global.opt.threadsDpiPure()
|
if (nodep->dpiPure() ? !v3Global.opt.threadsDpiPure()
|
||||||
: !v3Global.opt.threadsDpiUnpure()) {
|
: !v3Global.opt.threadsDpiUnpure()) {
|
||||||
m_hasDpiHazard = true;
|
// If hierarchical DPI wrapper cost is not found or is of a 0 cost,
|
||||||
|
// we have a normal DPI which induces DPI hazard by default.
|
||||||
|
m_hasDpiHazard = V3Config::getProfileData(nodep->cname()) == 0;
|
||||||
|
UINFO(9, "DPI wrapper '" << nodep->cname()
|
||||||
|
<< "' has dpi hazard = " << m_hasDpiHazard << endl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
iterateChildren(nodep);
|
iterateChildren(nodep);
|
||||||
|
|||||||
+2
-2
@@ -91,9 +91,9 @@ string V3Os::getenvStr(const string& envvar, const string& defaultValue) {
|
|||||||
|
|
||||||
void V3Os::setenvStr(const string& envvar, const string& value, const string& why) {
|
void V3Os::setenvStr(const string& envvar, const string& value, const string& why) {
|
||||||
if (why != "") {
|
if (why != "") {
|
||||||
UINFO(1, "export " << envvar << "=" << value << " # " << why << endl);
|
UINFO(1, "export " << envvar << "='" << value << "' # " << why << endl);
|
||||||
} else {
|
} else {
|
||||||
UINFO(1, "export " << envvar << "=" << value << endl);
|
UINFO(1, "export " << envvar << "='" << value << "'" << endl);
|
||||||
}
|
}
|
||||||
#if defined(_WIN32) || defined(__MINGW32__)
|
#if defined(_WIN32) || defined(__MINGW32__)
|
||||||
_putenv_s(envvar.c_str(), value.c_str());
|
_putenv_s(envvar.c_str(), value.c_str());
|
||||||
|
|||||||
+4
-4
@@ -543,18 +543,18 @@ class ParamProcessor final {
|
|||||||
for (auto&& defaultValue : paramsIt->second) {
|
for (auto&& defaultValue : paramsIt->second) {
|
||||||
const auto pinIt = pins.find(defaultValue.first);
|
const auto pinIt = pins.find(defaultValue.first);
|
||||||
// If the pin does not have a value assigned, use the default one.
|
// If the pin does not have a value assigned, use the default one.
|
||||||
const AstNode* const node = pinIt == pins.end() ? defaultValue.second : pinIt->second;
|
const AstNode* const nodep = pinIt == pins.end() ? defaultValue.second : pinIt->second;
|
||||||
// This longname is not valid as verilog symbol, but ok, because it will be hashed
|
// This longname is not valid as verilog symbol, but ok, because it will be hashed
|
||||||
longname += "_" + defaultValue.first + "=";
|
longname += "_" + defaultValue.first + "=";
|
||||||
// constp can be nullptr
|
// constp can be nullptr
|
||||||
|
|
||||||
if (const AstConst* const p = VN_CAST(node, Const)) {
|
if (const AstConst* const p = VN_CAST(nodep, Const)) {
|
||||||
// Treat modules parametrized with the same values but with different type as the
|
// Treat modules parametrized with the same values but with different type as the
|
||||||
// same.
|
// same.
|
||||||
longname += p->num().ascii(false);
|
longname += p->num().ascii(false);
|
||||||
} else if (node) {
|
} else if (nodep) {
|
||||||
std::stringstream type;
|
std::stringstream type;
|
||||||
V3EmitV::verilogForTree(node, type);
|
V3EmitV::verilogForTree(nodep, type);
|
||||||
longname += type.str();
|
longname += type.str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
-1
@@ -356,7 +356,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
|
|||||||
dumpInputsFile();
|
dumpInputsFile();
|
||||||
|
|
||||||
// Parse it
|
// Parse it
|
||||||
if (!v3Global.opt.preprocOnly()) {
|
if (!v3Global.opt.preprocOnly() || v3Global.opt.preprocResolve()) {
|
||||||
lexFile(modfilename);
|
lexFile(modfilename);
|
||||||
} else {
|
} else {
|
||||||
m_ppBuffers.clear();
|
m_ppBuffers.clear();
|
||||||
|
|||||||
+9
-4
@@ -486,7 +486,7 @@ void V3PreProcImp::comment(const string& text) {
|
|||||||
//}
|
//}
|
||||||
// else ignore the comment we don't recognize
|
// else ignore the comment we don't recognize
|
||||||
} // else no assertions
|
} // else no assertions
|
||||||
} else if (vlcomment) {
|
} else if (vlcomment && !(v3Global.opt.publicOff() && VString::startsWith(cmd, "public"))) {
|
||||||
if (VString::startsWith(cmd, "public_flat_rw")) {
|
if (VString::startsWith(cmd, "public_flat_rw")) {
|
||||||
// "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)"
|
// "/*verilator public_flat_rw @(foo) */" -> "/*verilator public_flat_rw*/ @(foo)"
|
||||||
string::size_type endOfCmd = std::strlen("public_flat_rw");
|
string::size_type endOfCmd = std::strlen("public_flat_rw");
|
||||||
@@ -963,9 +963,9 @@ int V3PreProcImp::getRawToken() {
|
|||||||
if (m_lastLineno != m_lexp->m_tokFilelinep->lineno()) {
|
if (m_lastLineno != m_lexp->m_tokFilelinep->lineno()) {
|
||||||
m_lastLineno = m_lexp->m_tokFilelinep->lineno();
|
m_lastLineno = m_lexp->m_tokFilelinep->lineno();
|
||||||
m_tokensOnLine = 0;
|
m_tokensOnLine = 0;
|
||||||
} else if (++m_tokensOnLine > LINE_TOKEN_MAX) {
|
} else if (++m_tokensOnLine > v3Global.opt.preprocTokenLimit()) {
|
||||||
error("Too many preprocessor tokens on a line (>" + cvtToStr(LINE_TOKEN_MAX)
|
error("Too many preprocessor tokens on a line (>"
|
||||||
+ "); perhaps recursive `define");
|
+ cvtToStr(v3Global.opt.preprocTokenLimit()) + "); perhaps recursive `define");
|
||||||
tok = VP_EOF_ERROR;
|
tok = VP_EOF_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1065,6 +1065,11 @@ int V3PreProcImp::getStateToken() {
|
|||||||
// FALLTHRU, handle as with VP_SYMBOL_JOIN
|
// FALLTHRU, handle as with VP_SYMBOL_JOIN
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (state() == ps_STRIFY) {
|
||||||
|
// Ignore joins and symbol joins in stringify as they don't affect the final string
|
||||||
|
if (tok == VP_JOIN) goto next_tok;
|
||||||
|
if (tok == VP_SYMBOL_JOIN) tok = VP_SYMBOL;
|
||||||
|
}
|
||||||
if (tok == VP_SYMBOL_JOIN // not else if, can fallthru from above if()
|
if (tok == VP_SYMBOL_JOIN // not else if, can fallthru from above if()
|
||||||
|| tok == VP_DEFREF_JOIN || tok == VP_JOIN) {
|
|| tok == VP_DEFREF_JOIN || tok == VP_JOIN) {
|
||||||
// a`` -> string doesn't include the ``, so can just grab next and continue
|
// a`` -> string doesn't include the ``, so can just grab next and continue
|
||||||
|
|||||||
@@ -42,7 +42,6 @@ public:
|
|||||||
// CONSTANTS
|
// CONSTANTS
|
||||||
enum MiscConsts {
|
enum MiscConsts {
|
||||||
DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error
|
DEFINE_RECURSION_LEVEL_MAX = 1000, // How many `def substitutions before an error
|
||||||
LINE_TOKEN_MAX = 40000, // How many tokens on a line before an error
|
|
||||||
INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error
|
INCLUDE_DEPTH_MAX = 500, // How many `includes deep before an error
|
||||||
// Streams deep (sometimes `def deep) before an error.
|
// Streams deep (sometimes `def deep) before an error.
|
||||||
// Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX.
|
// Set more than DEFINE_RECURSION_LEVEL_MAX or INCLUDE_DEPTH_MAX.
|
||||||
|
|||||||
@@ -19,6 +19,7 @@
|
|||||||
#include "V3ProtectLib.h"
|
#include "V3ProtectLib.h"
|
||||||
|
|
||||||
#include "V3Hasher.h"
|
#include "V3Hasher.h"
|
||||||
|
#include "V3InstrCount.h"
|
||||||
#include "V3String.h"
|
#include "V3String.h"
|
||||||
#include "V3Task.h"
|
#include "V3Task.h"
|
||||||
|
|
||||||
@@ -98,6 +99,32 @@ class ProtectVisitor final : public VNVisitor {
|
|||||||
txtp->addNodesp(new AstComment{fl, comment});
|
txtp->addNodesp(new AstComment{fl, comment});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void configSection(AstNodeModule* modp, AstTextBlock* txtp, FileLine* fl) {
|
||||||
|
txtp->addText(fl, "\n`ifdef VERILATOR\n");
|
||||||
|
txtp->addText(fl, "`verilator_config\n");
|
||||||
|
|
||||||
|
// The `eval` function is called inside both update functions. As those functions
|
||||||
|
// are created by text bashing, we need to find cost of `_eval` which is the first function
|
||||||
|
// with a real cost in AST.
|
||||||
|
uint32_t cost = 0;
|
||||||
|
modp->foreach([&cost](AstCFunc* cfuncp) {
|
||||||
|
if (cfuncp->name() == "_eval") cost = V3InstrCount::count(cfuncp, false);
|
||||||
|
});
|
||||||
|
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||||
|
+ "_protectlib_combo_update\" -cost 64'd" + std::to_string(cost)
|
||||||
|
+ "\n");
|
||||||
|
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||||
|
+ "_protectlib_seq_update\" -cost 64'd" + std::to_string(cost)
|
||||||
|
+ "\n");
|
||||||
|
|
||||||
|
// Mark remaining NDA protectlib wrapper DPIs as non-hazardous by deliberately forwarding
|
||||||
|
// them with non-zero cost.
|
||||||
|
txtp->addText(fl, "profile_data -hier-dpi \"" + m_libName
|
||||||
|
+ "_protectlib_combo_ignore\" -cost 64'd1\n");
|
||||||
|
txtp->addText(fl, "`verilog\n");
|
||||||
|
txtp->addText(fl, "`endif\n");
|
||||||
|
}
|
||||||
|
|
||||||
void hashComment(AstTextBlock* txtp, FileLine* fl) {
|
void hashComment(AstTextBlock* txtp, FileLine* fl) {
|
||||||
addComment(txtp, fl, "Checks to make sure the .sv wrapper and library agree");
|
addComment(txtp, fl, "Checks to make sure the .sv wrapper and library agree");
|
||||||
}
|
}
|
||||||
@@ -283,6 +310,9 @@ class ProtectVisitor final : public VNVisitor {
|
|||||||
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
txtp->addText(fl, "final " + m_libName + "_protectlib_final(handle__V);\n\n");
|
||||||
|
|
||||||
txtp->addText(fl, "endmodule\n");
|
txtp->addText(fl, "endmodule\n");
|
||||||
|
|
||||||
|
configSection(modp, txtp, fl);
|
||||||
|
|
||||||
m_vfilep->tblockp(txtp);
|
m_vfilep->tblockp(txtp);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+67
-35
@@ -629,18 +629,22 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||||||
const uint32_t unpackedDimensions = dims.second;
|
const uint32_t unpackedDimensions = dims.second;
|
||||||
dimension = unpackedDimensions;
|
dimension = unpackedDimensions;
|
||||||
}
|
}
|
||||||
|
if (VN_IS(varp->dtypeSkipRefp(), StructDType)
|
||||||
|
&& !VN_AS(varp->dtypeSkipRefp(), StructDType)->packed()) {
|
||||||
|
VN_AS(varp->dtypeSkipRefp(), StructDType)->markConstrainedRand(true);
|
||||||
|
dimension = 1;
|
||||||
|
}
|
||||||
methodp->dtypeSetVoid();
|
methodp->dtypeSetVoid();
|
||||||
AstClass* const classp = VN_AS(varp->user2p(), Class);
|
AstClass* const classp = VN_AS(varp->user2p(), Class);
|
||||||
AstVarRef* const varRefp
|
AstVarRef* const varRefp
|
||||||
= new AstVarRef{varp->fileline(), classp, varp, VAccess::WRITE};
|
= new AstVarRef{varp->fileline(), classp, varp, VAccess::WRITE};
|
||||||
varRefp->classOrPackagep(classOrPackagep);
|
varRefp->classOrPackagep(classOrPackagep);
|
||||||
methodp->addPinsp(varRefp);
|
methodp->addPinsp(varRefp);
|
||||||
size_t width = varp->width();
|
|
||||||
AstNodeDType* tmpDtypep = varp->dtypep();
|
AstNodeDType* tmpDtypep = varp->dtypep();
|
||||||
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
while (VN_IS(tmpDtypep, UnpackArrayDType) || VN_IS(tmpDtypep, DynArrayDType)
|
||||||
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
|
|| VN_IS(tmpDtypep, QueueDType) || VN_IS(tmpDtypep, AssocArrayDType))
|
||||||
tmpDtypep = tmpDtypep->subDTypep();
|
tmpDtypep = tmpDtypep->subDTypep();
|
||||||
width = tmpDtypep->width();
|
const size_t width = tmpDtypep->width();
|
||||||
methodp->addPinsp(
|
methodp->addPinsp(
|
||||||
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, width});
|
new AstConst{varp->dtypep()->fileline(), AstConst::Unsized64{}, width});
|
||||||
AstNodeExpr* const varnamep
|
AstNodeExpr* const varnamep
|
||||||
@@ -706,42 +710,73 @@ class ConstraintExprVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
editSMT(nodep, nodep->fromp(), lsbp, msbp);
|
editSMT(nodep, nodep->fromp(), lsbp, msbp);
|
||||||
}
|
}
|
||||||
|
void visit(AstStructSel* nodep) override {
|
||||||
|
if (VN_IS(nodep->fromp()->dtypep()->skipRefp(), StructDType)) {
|
||||||
|
AstNodeExpr* const fromp = nodep->fromp();
|
||||||
|
if (VN_IS(fromp, StructSel)) {
|
||||||
|
VN_AS(fromp->dtypep()->skipRefp(), StructDType)->markConstrainedRand(true);
|
||||||
|
}
|
||||||
|
AstMemberDType* memberp = VN_AS(fromp->dtypep()->skipRefp(), StructDType)->membersp();
|
||||||
|
while (memberp) {
|
||||||
|
if (memberp->name() == nodep->name()) {
|
||||||
|
memberp->markConstrainedRand(true);
|
||||||
|
break;
|
||||||
|
} else
|
||||||
|
memberp = VN_CAST(memberp->nextp(), MemberDType);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
iterateChildren(nodep);
|
||||||
|
if (editFormat(nodep)) return;
|
||||||
|
FileLine* const fl = nodep->fileline();
|
||||||
|
AstSFormatF* const newp
|
||||||
|
= new AstSFormatF{fl, nodep->fromp()->name() + "." + nodep->name(), false, nullptr};
|
||||||
|
nodep->replaceWith(newp);
|
||||||
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
|
}
|
||||||
void visit(AstAssocSel* nodep) override {
|
void visit(AstAssocSel* nodep) override {
|
||||||
if (editFormat(nodep)) return;
|
if (editFormat(nodep)) return;
|
||||||
FileLine* const fl = nodep->fileline();
|
FileLine* const fl = nodep->fileline();
|
||||||
if (VN_IS(nodep->bitp(), CvtPackString)) {
|
if (VN_IS(nodep->bitp(), CvtPackString) && VN_IS(nodep->bitp()->dtypep(), BasicDType)) {
|
||||||
// Extract and truncate the string index to fit within 64 bits
|
|
||||||
AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString);
|
AstCvtPackString* const stringp = VN_AS(nodep->bitp(), CvtPackString);
|
||||||
VNRelinker handle;
|
const size_t stringSize = VN_AS(stringp->lhsp(), Const)->width();
|
||||||
AstNodeExpr* const strIdxp = new AstSFormatF{
|
if (stringSize > 128) {
|
||||||
fl, "#x%16x", false,
|
stringp->v3warn(
|
||||||
new AstAnd{fl, stringp->lhsp()->unlinkFrBack(&handle),
|
CONSTRAINTIGN,
|
||||||
new AstConst(fl, AstConst::Unsized64{}, 0xFFFFFFFFFFFFFFFF)}};
|
"Unsupported: Constrained randomization of associative array keys of "
|
||||||
handle.relink(strIdxp);
|
<< stringSize << "bits, limit is 128 bits");
|
||||||
editSMT(nodep, nodep->fromp(), strIdxp);
|
|
||||||
} else {
|
|
||||||
VNRelinker handle;
|
|
||||||
const int actual_width = nodep->bitp()->width();
|
|
||||||
std::string fmt;
|
|
||||||
// Normalize to standard bit width
|
|
||||||
if (actual_width <= 8) {
|
|
||||||
fmt = "#x%2x";
|
|
||||||
} else if (actual_width <= 16) {
|
|
||||||
fmt = "#x%4x";
|
|
||||||
} else if (actual_width <= 32) {
|
|
||||||
fmt = "#x%8x";
|
|
||||||
} else if (actual_width <= 64) {
|
|
||||||
fmt = "#x%16x";
|
|
||||||
} else {
|
|
||||||
nodep->v3warn(CONSTRAINTIGN,
|
|
||||||
"Unsupported: Associative array index "
|
|
||||||
"widths of more than 64 bits during constraint randomization.");
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
VNRelinker handle;
|
||||||
AstNodeExpr* const idxp
|
AstNodeExpr* const idxp
|
||||||
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
|
= new AstSFormatF{fl, "#x%32x", false, stringp->lhsp()->unlinkFrBack(&handle)};
|
||||||
handle.relink(idxp);
|
handle.relink(idxp);
|
||||||
editSMT(nodep, nodep->fromp(), idxp);
|
editSMT(nodep, nodep->fromp(), idxp);
|
||||||
|
} else {
|
||||||
|
if (VN_IS(nodep->bitp()->dtypep(), BasicDType)
|
||||||
|
|| (VN_IS(nodep->bitp()->dtypep(), StructDType)
|
||||||
|
&& VN_AS(nodep->bitp()->dtypep(), StructDType)->packed())
|
||||||
|
|| VN_IS(nodep->bitp()->dtypep(), EnumDType)
|
||||||
|
|| VN_IS(nodep->bitp()->dtypep(), PackArrayDType)) {
|
||||||
|
VNRelinker handle;
|
||||||
|
const int actual_width = nodep->bitp()->width();
|
||||||
|
std::string fmt;
|
||||||
|
// Normalize to standard bit width
|
||||||
|
if (actual_width <= 8) {
|
||||||
|
fmt = "#x%2x";
|
||||||
|
} else if (actual_width <= 16) {
|
||||||
|
fmt = "#x%4x";
|
||||||
|
} else {
|
||||||
|
fmt = "#x%" + std::to_string(VL_WORDS_I(actual_width) * 8) + "x";
|
||||||
|
}
|
||||||
|
|
||||||
|
AstNodeExpr* const idxp
|
||||||
|
= new AstSFormatF{fl, fmt, false, nodep->bitp()->unlinkFrBack(&handle)};
|
||||||
|
handle.relink(idxp);
|
||||||
|
editSMT(nodep, nodep->fromp(), idxp);
|
||||||
|
} else {
|
||||||
|
nodep->bitp()->v3error(
|
||||||
|
"Illegal non-integral expression or subexpression in random constraint."
|
||||||
|
" (IEEE 1800-2023 18.3)");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
void visit(AstArraySel* nodep) override {
|
void visit(AstArraySel* nodep) override {
|
||||||
@@ -1450,11 +1485,8 @@ class RandomizeVisitor final : public VNVisitor {
|
|||||||
AstNodeStmt* stmtsp = nullptr;
|
AstNodeStmt* stmtsp = nullptr;
|
||||||
auto createLoopIndex = [&](AstNodeDType* tempDTypep) {
|
auto createLoopIndex = [&](AstNodeDType* tempDTypep) {
|
||||||
if (VN_IS(tempDTypep, AssocArrayDType)) {
|
if (VN_IS(tempDTypep, AssocArrayDType)) {
|
||||||
return new AstVar{
|
return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""),
|
||||||
fl, VVarType::VAR, uniqueNamep->get(""),
|
VN_AS(tempDTypep, AssocArrayDType)->keyDTypep()};
|
||||||
dtypep->findBasicDType(
|
|
||||||
((AstBasicDType*)VN_AS(tempDTypep, AssocArrayDType)->keyDTypep())
|
|
||||||
->keyword())};
|
|
||||||
}
|
}
|
||||||
return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""),
|
return new AstVar{fl, VVarType::VAR, uniqueNamep->get(""),
|
||||||
dtypep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
dtypep->findBasicDType(VBasicDTypeKwd::UINT32)};
|
||||||
|
|||||||
@@ -70,6 +70,7 @@ AstCFunc* makeSubFunction(AstNetlist* netlistp, const string& name, bool slow) {
|
|||||||
AstCFunc* makeTopFunction(AstNetlist* netlistp, const string& name, bool slow) {
|
AstCFunc* makeTopFunction(AstNetlist* netlistp, const string& name, bool slow) {
|
||||||
AstCFunc* const funcp = makeSubFunction(netlistp, name, slow);
|
AstCFunc* const funcp = makeSubFunction(netlistp, name, slow);
|
||||||
funcp->entryPoint(true);
|
funcp->entryPoint(true);
|
||||||
|
funcp->keepIfEmpty(true);
|
||||||
return funcp;
|
return funcp;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -788,6 +789,10 @@ const TriggerKit createTriggers(AstNetlist* netlistp, AstCFunc* const initFuncp,
|
|||||||
// The debug code might leak signal names, so simply delete it when using --protect-ids
|
// The debug code might leak signal names, so simply delete it when using --protect-ids
|
||||||
if (v3Global.opt.protectIds()) dumpp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
if (v3Global.opt.protectIds()) dumpp->stmtsp()->unlinkFrBackWithNext()->deleteTree();
|
||||||
|
|
||||||
|
// These might get large when we have a lot of triggers, so split if necessary
|
||||||
|
splitCheck(funcp);
|
||||||
|
splitCheck(dumpp);
|
||||||
|
|
||||||
return {vscp, funcp, dumpp, map};
|
return {vscp, funcp, dumpp, map};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -182,16 +182,11 @@ class SenExprBuilder final {
|
|||||||
case VEdgeType::ET_EVENT: {
|
case VEdgeType::ET_EVENT: {
|
||||||
UASSERT_OBJ(v3Global.hasEvents(), senItemp, "Inconsistent");
|
UASSERT_OBJ(v3Global.hasEvents(), senItemp, "Inconsistent");
|
||||||
{
|
{
|
||||||
// If the event is fired, set up the clearing process
|
|
||||||
AstCMethodHard* const callp = new AstCMethodHard{flp, currp(), "isFired"};
|
|
||||||
callp->dtypeSetBit();
|
|
||||||
AstIf* const ifp = new AstIf{flp, callp};
|
|
||||||
m_postUpdates.push_back(ifp);
|
|
||||||
|
|
||||||
// Clear 'fired' state when done
|
// Clear 'fired' state when done
|
||||||
|
// No need to check if the event was fired, we need the flag clear regardless
|
||||||
AstCMethodHard* const clearp = new AstCMethodHard{flp, currp(), "clearFired"};
|
AstCMethodHard* const clearp = new AstCMethodHard{flp, currp(), "clearFired"};
|
||||||
clearp->dtypeSetVoid();
|
clearp->dtypeSetVoid();
|
||||||
ifp->addThensp(clearp->makeStmt());
|
m_postUpdates.push_back(clearp->makeStmt());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get 'fired' state
|
// Get 'fired' state
|
||||||
|
|||||||
+35
-38
@@ -78,8 +78,7 @@ private:
|
|||||||
// Cleared on each always/assignw
|
// Cleared on each always/assignw
|
||||||
const VNUser1InUse m_inuser1;
|
const VNUser1InUse m_inuser1;
|
||||||
|
|
||||||
// AstVar/AstVarScope::user1p() -> See AuxAstVar via m_varAux
|
// AstNode::user1p() -> See AuxAstVar via m_varAux
|
||||||
// AstConst::user1() -> bool. This AstConst (allocated by this class) is in use
|
|
||||||
|
|
||||||
enum VarUsage : uint8_t { VU_NONE = 0, VU_LV = 1, VU_RV = 2, VU_LVDLY = 4 };
|
enum VarUsage : uint8_t { VU_NONE = 0, VU_LV = 1, VU_RV = 2, VU_LVDLY = 4 };
|
||||||
|
|
||||||
@@ -96,6 +95,32 @@ private:
|
|||||||
|
|
||||||
AstUser1Allocator<AstNode, AuxVariable> m_varAux;
|
AstUser1Allocator<AstNode, AuxVariable> m_varAux;
|
||||||
|
|
||||||
|
// We want to re-use allocated constants across calls to clear(), but we want to be able
|
||||||
|
// to 'clear()' fast, so we use a generation number based allocator.
|
||||||
|
struct ConstAllocator final {
|
||||||
|
size_t m_generation = 0;
|
||||||
|
size_t m_nextFree = 0;
|
||||||
|
std::deque<AstConst*> m_constps;
|
||||||
|
AstConst* allocate(size_t currentGeneration, AstNode* nodep) {
|
||||||
|
if (m_generation != currentGeneration) {
|
||||||
|
m_generation = currentGeneration;
|
||||||
|
m_nextFree = 0;
|
||||||
|
}
|
||||||
|
UASSERT_OBJ(m_nextFree <= m_constps.size(), nodep, "Should only allocate at end");
|
||||||
|
if (m_nextFree == m_constps.size()) {
|
||||||
|
m_constps.push_back(
|
||||||
|
new AstConst{nodep->fileline(), AstConst::DTyped{}, nodep->dtypep()});
|
||||||
|
}
|
||||||
|
AstConst* const constp = m_constps[m_nextFree++];
|
||||||
|
constp->num().nodep(nodep);
|
||||||
|
return constp;
|
||||||
|
}
|
||||||
|
|
||||||
|
~ConstAllocator() {
|
||||||
|
for (AstConst* const constp : m_constps) VL_DO_DANGLING(delete constp, constp);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// STATE
|
// STATE
|
||||||
// Major mode
|
// Major mode
|
||||||
bool m_checkOnly; ///< Checking only (no simulation) mode
|
bool m_checkOnly; ///< Checking only (no simulation) mode
|
||||||
@@ -113,8 +138,9 @@ private:
|
|||||||
int m_dataCount; ///< Bytes of data
|
int m_dataCount; ///< Bytes of data
|
||||||
AstJumpGo* m_jumpp = nullptr; ///< Jump label we're branching from
|
AstJumpGo* m_jumpp = nullptr; ///< Jump label we're branching from
|
||||||
// Simulating:
|
// Simulating:
|
||||||
std::unordered_map<const AstNodeDType*, std::deque<AstConst*>>
|
// Allocators for constants of various data types
|
||||||
m_constps; ///< Lists of all AstConst* allocated per dtype
|
std::unordered_map<const AstNodeDType*, ConstAllocator> m_constps;
|
||||||
|
size_t m_constGeneration = 0;
|
||||||
std::vector<SimStackNode*> m_callStack; ///< Call stack for verbose error messages
|
std::vector<SimStackNode*> m_callStack; ///< Call stack for verbose error messages
|
||||||
|
|
||||||
// Cleanup
|
// Cleanup
|
||||||
@@ -223,37 +249,8 @@ public:
|
|||||||
// Simulation METHODS
|
// Simulation METHODS
|
||||||
private:
|
private:
|
||||||
AstConst* allocConst(AstNode* nodep) {
|
AstConst* allocConst(AstNode* nodep) {
|
||||||
// Save time - kept a list of allocated but unused values
|
// Allocate a constant with this dtype. Reuse them across a 'clear()' call for efficiency.
|
||||||
// It would be more efficient to do this by size, but the extra accounting
|
return m_constps[nodep->dtypep()].allocate(m_constGeneration, nodep);
|
||||||
// slows things down more than we gain.
|
|
||||||
AstConst* constp;
|
|
||||||
// Grab free list corresponding to this dtype
|
|
||||||
std::deque<AstConst*>& freeList = m_constps[nodep->dtypep()];
|
|
||||||
bool allocNewConst = true;
|
|
||||||
if (!freeList.empty()) {
|
|
||||||
constp = freeList.front();
|
|
||||||
if (!constp->user1()) {
|
|
||||||
// Front of free list is free, reuse it (otherwise allocate new node)
|
|
||||||
allocNewConst = false; // No need to allocate
|
|
||||||
// Mark the AstConst node as used, and move it to the back of the free list. This
|
|
||||||
// ensures that when all AstConst instances within the list are used, then the
|
|
||||||
// front of the list will be marked as used, in which case the enclosing 'if' will
|
|
||||||
// fail and we fall back to allocation.
|
|
||||||
constp->user1(1);
|
|
||||||
freeList.pop_front();
|
|
||||||
freeList.push_back(constp);
|
|
||||||
// configure const
|
|
||||||
constp->num().nodep(nodep);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (allocNewConst) {
|
|
||||||
// Need to allocate new constant
|
|
||||||
constp = new AstConst{nodep->fileline(), AstConst::DTyped{}, nodep->dtypep()};
|
|
||||||
// Mark as in use, add to free list for later reuse
|
|
||||||
constp->user1(1);
|
|
||||||
freeList.push_back(constp);
|
|
||||||
}
|
|
||||||
return constp;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@@ -850,6 +847,8 @@ private:
|
|||||||
if (!itemp) {
|
if (!itemp) {
|
||||||
clearOptimizable(nodep, "Array initialization has too few elements, need element "
|
clearOptimizable(nodep, "Array initialization has too few elements, need element "
|
||||||
+ cvtToStr(offset));
|
+ cvtToStr(offset));
|
||||||
|
} else if (AstConst* const constp = VN_CAST(itemp, Const)) {
|
||||||
|
setValue(nodep, constp);
|
||||||
} else {
|
} else {
|
||||||
setValue(nodep, fetchValue(itemp));
|
setValue(nodep, fetchValue(itemp));
|
||||||
}
|
}
|
||||||
@@ -1256,6 +1255,7 @@ public:
|
|||||||
|
|
||||||
AstNode::user1ClearTree();
|
AstNode::user1ClearTree();
|
||||||
m_varAux.clear();
|
m_varAux.clear();
|
||||||
|
++m_constGeneration;
|
||||||
}
|
}
|
||||||
void mainTableCheck(AstNode* nodep) {
|
void mainTableCheck(AstNode* nodep) {
|
||||||
setMode(true /*scoped*/, true /*checking*/, false /*params*/);
|
setMode(true /*scoped*/, true /*checking*/, false /*params*/);
|
||||||
@@ -1274,9 +1274,6 @@ public:
|
|||||||
mainGuts(nodep);
|
mainGuts(nodep);
|
||||||
}
|
}
|
||||||
~SimulateVisitor() override {
|
~SimulateVisitor() override {
|
||||||
for (const auto& pair : m_constps) {
|
|
||||||
for (AstConst* const constp : pair.second) delete constp;
|
|
||||||
}
|
|
||||||
m_constps.clear();
|
m_constps.clear();
|
||||||
for (AstNode* ip : m_reclaimValuesp) delete ip;
|
for (AstNode* ip : m_reclaimValuesp) delete ip;
|
||||||
m_reclaimValuesp.clear();
|
m_reclaimValuesp.clear();
|
||||||
|
|||||||
+15
-6
@@ -900,8 +900,9 @@ public:
|
|||||||
const AstBasicDType* basicp() const { return m_basicp; }
|
const AstBasicDType* basicp() const { return m_basicp; }
|
||||||
// Make a plan for variables after split
|
// Make a plan for variables after split
|
||||||
// when skipUnused==true, split variable for unread bits will not be created.
|
// when skipUnused==true, split variable for unread bits will not be created.
|
||||||
std::vector<SplitNewVar> splitPlan(bool skipUnused) const {
|
std::vector<SplitNewVar> splitPlan(const AstVar* varp, bool skipUnused) const {
|
||||||
UASSERT(m_dedupDone, "dedup() must be called before");
|
UASSERT(m_dedupDone, "dedup() must be called before");
|
||||||
|
AstNodeDType* const dtypep = varp->dtypeSkipRefp();
|
||||||
std::vector<SplitNewVar> plan;
|
std::vector<SplitNewVar> plan;
|
||||||
std::vector<std::pair<int, bool>> points; // <bit location, is end>
|
std::vector<std::pair<int, bool>> points; // <bit location, is end>
|
||||||
points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry
|
points.reserve(m_lhs.size() * 2 + 2); // 2 points will be added per one PackedVarRefEntry
|
||||||
@@ -909,9 +910,17 @@ public:
|
|||||||
points.emplace_back(ref.lsb(), false); // Start of a region
|
points.emplace_back(ref.lsb(), false); // Start of a region
|
||||||
points.emplace_back(ref.msb() + 1, true); // End of a region
|
points.emplace_back(ref.msb() + 1, true); // End of a region
|
||||||
}
|
}
|
||||||
|
int bit_hi, bit_lo;
|
||||||
|
if (basicp() == dtypep) {
|
||||||
|
bit_hi = basicp()->hi();
|
||||||
|
bit_lo = basicp()->lo();
|
||||||
|
} else { // packed struct, packed array. lo is 0
|
||||||
|
bit_hi = dtypep->width() - 1;
|
||||||
|
bit_lo = 0;
|
||||||
|
}
|
||||||
if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here
|
if (skipUnused && !m_rhs.empty()) { // Range to be read must be kept, so add points here
|
||||||
int lsb = m_basicp->hi() + 1;
|
int lsb = bit_hi + 1;
|
||||||
int msb = m_basicp->lo() - 1;
|
int msb = bit_lo - 1;
|
||||||
for (const PackedVarRefEntry& ref : m_rhs) {
|
for (const PackedVarRefEntry& ref : m_rhs) {
|
||||||
lsb = std::min(lsb, ref.lsb());
|
lsb = std::min(lsb, ref.lsb());
|
||||||
msb = std::max(msb, ref.msb());
|
msb = std::max(msb, ref.msb());
|
||||||
@@ -921,8 +930,8 @@ public:
|
|||||||
points.emplace_back(msb + 1, true);
|
points.emplace_back(msb + 1, true);
|
||||||
}
|
}
|
||||||
if (!skipUnused) { // All bits are necessary
|
if (!skipUnused) { // All bits are necessary
|
||||||
points.emplace_back(m_basicp->lo(), false);
|
points.emplace_back(bit_lo, false);
|
||||||
points.emplace_back(m_basicp->hi() + 1, true);
|
points.emplace_back(bit_hi + 1, true);
|
||||||
}
|
}
|
||||||
std::sort(points.begin(), points.end(), SortByFirst());
|
std::sort(points.begin(), points.end(), SortByFirst());
|
||||||
|
|
||||||
@@ -1154,7 +1163,7 @@ class SplitPackedVarVisitor final : public VNVisitor, public SplitVarImpl {
|
|||||||
<< " which has " << ref.lhs().size() << " lhs refs and "
|
<< " which has " << ref.lhs().size() << " lhs refs and "
|
||||||
<< ref.rhs().size() << " rhs refs will be split.\n");
|
<< ref.rhs().size() << " rhs refs will be split.\n");
|
||||||
std::vector<SplitNewVar> vars
|
std::vector<SplitNewVar> vars
|
||||||
= ref.splitPlan(!varp->isTrace()); // If traced, all bit must be kept
|
= ref.splitPlan(varp, !varp->isTrace()); // If traced, all bit must be kept
|
||||||
if (vars.empty()) continue;
|
if (vars.empty()) continue;
|
||||||
if (vars.size() == 1 && vars.front().bitwidth() == varp->width())
|
if (vars.size() == 1 && vars.front().bitwidth() == varp->width())
|
||||||
continue; // No split
|
continue; // No split
|
||||||
|
|||||||
+14
-1
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "V3Task.h"
|
#include "V3Task.h"
|
||||||
|
|
||||||
|
#include "V3Config.h"
|
||||||
#include "V3Const.h"
|
#include "V3Const.h"
|
||||||
#include "V3EmitCBase.h"
|
#include "V3EmitCBase.h"
|
||||||
#include "V3Graph.h"
|
#include "V3Graph.h"
|
||||||
@@ -372,6 +373,7 @@ class TaskVisitor final : public VNVisitor {
|
|||||||
// STATE - across all visitors
|
// STATE - across all visitors
|
||||||
DpiCFuncs m_dpiNames; // Map of all created DPI functions
|
DpiCFuncs m_dpiNames; // Map of all created DPI functions
|
||||||
VDouble0 m_statInlines; // Statistic tracking
|
VDouble0 m_statInlines; // Statistic tracking
|
||||||
|
VDouble0 m_statHierDpisWithCosts; // Statistic tracking
|
||||||
|
|
||||||
// METHODS
|
// METHODS
|
||||||
|
|
||||||
@@ -980,6 +982,11 @@ class TaskVisitor final : public VNVisitor {
|
|||||||
funcp->isMethod(false);
|
funcp->isMethod(false);
|
||||||
funcp->protect(false);
|
funcp->protect(false);
|
||||||
funcp->dpiPure(nodep->dpiPure());
|
funcp->dpiPure(nodep->dpiPure());
|
||||||
|
|
||||||
|
const int cost = static_cast<int>(V3Config::getProfileData(funcp->name()));
|
||||||
|
m_statHierDpisWithCosts += (cost != 0);
|
||||||
|
funcp->cost(cost);
|
||||||
|
|
||||||
// Add DPI Import to top, since it's a global function
|
// Add DPI Import to top, since it's a global function
|
||||||
m_topScopep->scopep()->addBlocksp(funcp);
|
m_topScopep->scopep()->addBlocksp(funcp);
|
||||||
makePortList(nodep, funcp);
|
makePortList(nodep, funcp);
|
||||||
@@ -1259,6 +1266,8 @@ class TaskVisitor final : public VNVisitor {
|
|||||||
if (nodep->name() == "new") cfuncp->isConstructor(true);
|
if (nodep->name() == "new") cfuncp->isConstructor(true);
|
||||||
if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname());
|
if (cfuncp->dpiExportImpl()) cfuncp->cname(nodep->cname());
|
||||||
|
|
||||||
|
if (cfuncp->dpiImportWrapper()) cfuncp->cname(nodep->cname());
|
||||||
|
|
||||||
if (!nodep->dpiImport() && !nodep->taskPublic()) {
|
if (!nodep->dpiImport() && !nodep->taskPublic()) {
|
||||||
// Need symbol table
|
// Need symbol table
|
||||||
cfuncp->argTypes(EmitCBase::symClassVar());
|
cfuncp->argTypes(EmitCBase::symClassVar());
|
||||||
@@ -1613,7 +1622,11 @@ public:
|
|||||||
: m_statep{statep} {
|
: m_statep{statep} {
|
||||||
iterate(nodep);
|
iterate(nodep);
|
||||||
}
|
}
|
||||||
~TaskVisitor() { V3Stats::addStat("Optimizations, Functions inlined", m_statInlines); }
|
~TaskVisitor() {
|
||||||
|
V3Stats::addStat("Optimizations, Functions inlined", m_statInlines);
|
||||||
|
V3Stats::addStat("Optimizations, Hierarchical DPI wrappers with costs",
|
||||||
|
m_statHierDpisWithCosts);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
//######################################################################
|
//######################################################################
|
||||||
|
|||||||
+2
-2
@@ -57,7 +57,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||||||
bool cantUnroll(AstNode* nodep, const char* reason) const {
|
bool cantUnroll(AstNode* nodep, const char* reason) const {
|
||||||
if (m_generate)
|
if (m_generate)
|
||||||
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason);
|
nodep->v3warn(E_UNSUPPORTED, "Unsupported: Can't unroll generate for; " << reason);
|
||||||
UINFO(3, " Can't Unroll: " << reason << " :" << nodep << endl);
|
UINFO(4, " Can't Unroll: " << reason << " :" << nodep << endl);
|
||||||
// if (debug() >= 9) nodep->dumpTree("- cant: ");
|
// if (debug() >= 9) nodep->dumpTree("- cant: ");
|
||||||
V3Stats::addStatSum("Unrolling gave up, "s + reason, 1);
|
V3Stats::addStatSum("Unrolling gave up, "s + reason, 1);
|
||||||
return false;
|
return false;
|
||||||
@@ -210,7 +210,7 @@ class UnrollVisitor final : public VNVisitor {
|
|||||||
SimulateVisitor simvis;
|
SimulateVisitor simvis;
|
||||||
simvis.mainParamEmulate(clonep);
|
simvis.mainParamEmulate(clonep);
|
||||||
if (!simvis.optimizable()) {
|
if (!simvis.optimizable()) {
|
||||||
UINFO(3, "Unable to simulate" << endl);
|
UINFO(4, "Unable to simulate" << endl);
|
||||||
if (debug() >= 9) nodep->dumpTree("- _simtree: ");
|
if (debug() >= 9) nodep->dumpTree("- _simtree: ");
|
||||||
VL_DO_DANGLING(clonep->deleteTree(), clonep);
|
VL_DO_DANGLING(clonep->deleteTree(), clonep);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
+32
-11
@@ -2874,8 +2874,8 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
|
||||||
// Iterate into subDTypep() to resolve that type and update pointer.
|
// Iterate into subDTypep() to resolve that type and update pointer.
|
||||||
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
nodep->refDTypep(iterateEditMoveDTypep(nodep, nodep->subDTypep()));
|
||||||
nodep->dtypep(nodep); // The member itself, not subDtype
|
|
||||||
nodep->widthFromSub(nodep->subDTypep());
|
nodep->widthFromSub(nodep->subDTypep());
|
||||||
|
nodep->dtypeFrom(nodep->subDTypep());
|
||||||
if (nodep->valuep()) {
|
if (nodep->valuep()) {
|
||||||
userIterateAndNext(nodep->valuep(), WidthVP{nodep->dtypep(), PRELIM}.p());
|
userIterateAndNext(nodep->valuep(), WidthVP{nodep->dtypep(), PRELIM}.p());
|
||||||
iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep());
|
iterateCheckAssign(nodep, "Initial value", nodep->valuep(), FINAL, nodep->dtypep());
|
||||||
@@ -3929,11 +3929,14 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
AstNodeExpr* argsp = nullptr;
|
AstNodeExpr* argsp = nullptr;
|
||||||
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
|
||||||
AstNodeFTaskRef* newp = nullptr;
|
AstNodeFTaskRef* newp = nullptr;
|
||||||
if (VN_IS(ftaskp, Task)) {
|
// We use m_vup to determine task or function, so that later error checks
|
||||||
newp = new AstTaskRef{nodep->fileline(), VN_AS(ftaskp, Task), argsp};
|
// for funcref->task and taskref->func will pick up properly
|
||||||
|
if (!m_vup) { // Called as task
|
||||||
|
newp = new AstTaskRef{nodep->fileline(), nodep->name(), argsp};
|
||||||
} else {
|
} else {
|
||||||
newp = new AstFuncRef{nodep->fileline(), VN_AS(ftaskp, Func), argsp};
|
newp = new AstFuncRef{nodep->fileline(), nodep->name(), argsp};
|
||||||
}
|
}
|
||||||
|
newp->taskp(ftaskp); // Not passed above as might be func vs task mismatch
|
||||||
newp->classOrPackagep(classp);
|
newp->classOrPackagep(classp);
|
||||||
nodep->replaceWith(newp);
|
nodep->replaceWith(newp);
|
||||||
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
VL_DO_DANGLING(nodep->deleteTree(), nodep);
|
||||||
@@ -3941,7 +3944,18 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
nodep->taskp(ftaskp);
|
nodep->taskp(ftaskp);
|
||||||
nodep->dtypeFrom(ftaskp);
|
nodep->dtypeFrom(ftaskp);
|
||||||
nodep->classOrPackagep(classp);
|
nodep->classOrPackagep(classp);
|
||||||
if (VN_IS(ftaskp, Task)) nodep->dtypeSetVoid();
|
if (VN_IS(ftaskp, Task)) {
|
||||||
|
if (!m_vup) {
|
||||||
|
nodep->dtypeSetVoid();
|
||||||
|
} else {
|
||||||
|
if (m_vup->prelim()) {
|
||||||
|
nodep->v3error(
|
||||||
|
"Cannot call a task/void-function as a member function: "
|
||||||
|
<< nodep->prettyNameQ());
|
||||||
|
}
|
||||||
|
nodep->dtypeSetVoid();
|
||||||
|
}
|
||||||
|
}
|
||||||
if (withp) nodep->addPinsp(withp);
|
if (withp) nodep->addPinsp(withp);
|
||||||
processFTaskRefArgs(nodep);
|
processFTaskRefArgs(nodep);
|
||||||
}
|
}
|
||||||
@@ -4223,9 +4237,8 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
UASSERT_OBJ(classp, nodep, "Unlinked classOrPackagep()");
|
UASSERT_OBJ(classp, nodep, "Unlinked classOrPackagep()");
|
||||||
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked taskp()");
|
UASSERT_OBJ(nodep->taskp(), nodep, "Unlinked taskp()");
|
||||||
}
|
}
|
||||||
userIterate(nodep->taskp(), nullptr);
|
|
||||||
if (!assign) nodep->dtypeFrom(nodep->taskp());
|
|
||||||
processFTaskRefArgs(nodep);
|
processFTaskRefArgs(nodep);
|
||||||
|
if (!assign) nodep->dtypeFrom(nodep->taskp());
|
||||||
}
|
}
|
||||||
void visit(AstNewCopy* nodep) override {
|
void visit(AstNewCopy* nodep) override {
|
||||||
if (nodep->didWidthAndSet()) return;
|
if (nodep->didWidthAndSet()) return;
|
||||||
@@ -4561,8 +4574,8 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
|
|
||||||
if (patp) {
|
if (patp) {
|
||||||
// Don't want the RHS an array
|
// Don't want the RHS an array
|
||||||
patp->dtypep(arrayDtp->subDTypep());
|
|
||||||
allConstant &= VN_IS(patp->lhssp(), Const);
|
allConstant &= VN_IS(patp->lhssp(), Const);
|
||||||
|
patp->dtypep(arrayDtp->subDTypep());
|
||||||
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
AstNodeExpr* const valuep = patternMemberValueIterate(patp);
|
||||||
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
if (VN_IS(arrayDtp, UnpackArrayDType)) {
|
||||||
if (!newp) {
|
if (!newp) {
|
||||||
@@ -5825,7 +5838,15 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
}
|
}
|
||||||
void visit(AstFuncRef* nodep) override {
|
void visit(AstFuncRef* nodep) override {
|
||||||
visit(static_cast<AstNodeFTaskRef*>(nodep));
|
visit(static_cast<AstNodeFTaskRef*>(nodep));
|
||||||
nodep->dtypeFrom(nodep->taskp());
|
if (nodep->taskp() && VN_IS(nodep->taskp(), Task)) {
|
||||||
|
UASSERT_OBJ(m_vup, nodep, "Function reference where widthed expression expection");
|
||||||
|
if (m_vup->prelim())
|
||||||
|
nodep->v3error(
|
||||||
|
"Cannot call a task/void-function as a function: " << nodep->prettyNameQ());
|
||||||
|
nodep->dtypeSetVoid();
|
||||||
|
} else {
|
||||||
|
nodep->dtypeFrom(nodep->taskp());
|
||||||
|
}
|
||||||
if (nodep->fileline()->timingOn()) {
|
if (nodep->fileline()->timingOn()) {
|
||||||
AstNodeModule* const classp = nodep->classOrPackagep();
|
AstNodeModule* const classp = nodep->classOrPackagep();
|
||||||
if (nodep->name() == "self" && classp->name() == "process") {
|
if (nodep->name() == "self" && classp->name() == "process") {
|
||||||
@@ -6086,17 +6107,17 @@ class WidthVisitor final : public VNVisitor {
|
|||||||
nodep->v3error("Cannot call non-static member function "
|
nodep->v3error("Cannot call non-static member function "
|
||||||
<< nodep->prettyNameQ() << " without object (IEEE 1800-2023 8.10)");
|
<< nodep->prettyNameQ() << " without object (IEEE 1800-2023 8.10)");
|
||||||
}
|
}
|
||||||
userIterate(nodep->taskp(), nullptr);
|
|
||||||
// And do the arguments to the task/function too
|
// And do the arguments to the task/function too
|
||||||
processFTaskRefArgs(nodep);
|
processFTaskRefArgs(nodep);
|
||||||
nodep->addPinsp(withp);
|
nodep->addPinsp(withp);
|
||||||
nodep->didWidth(true);
|
nodep->didWidth(true);
|
||||||
|
// See steps that follow in visit(AstFuncRef*)
|
||||||
}
|
}
|
||||||
void visit(AstNodeProcedure* nodep) override {
|
void visit(AstNodeProcedure* nodep) override {
|
||||||
assertAtStatement(nodep);
|
assertAtStatement(nodep);
|
||||||
|
VL_RESTORER(m_procedurep);
|
||||||
m_procedurep = nodep;
|
m_procedurep = nodep;
|
||||||
userIterateChildren(nodep, nullptr);
|
userIterateChildren(nodep, nullptr);
|
||||||
m_procedurep = nullptr;
|
|
||||||
}
|
}
|
||||||
void visit(AstSenItem* nodep) override {
|
void visit(AstSenItem* nodep) override {
|
||||||
UASSERT_OBJ(nodep->isClocked(), nodep, "Invalid edge");
|
UASSERT_OBJ(nodep->isClocked(), nodep, "Invalid edge");
|
||||||
|
|||||||
@@ -100,9 +100,15 @@ private:
|
|||||||
if (local || prot) {
|
if (local || prot) {
|
||||||
const auto refClassp = VN_CAST(m_modp, Class);
|
const auto refClassp = VN_CAST(m_modp, Class);
|
||||||
const char* how = nullptr;
|
const char* how = nullptr;
|
||||||
if (local && defClassp && refClassp != defClassp) {
|
// Inner nested classes can access `local` or `protected` members of their outer class
|
||||||
|
const auto nestedAccess = [refClassp](const AstClass*, const AstNode* memberp) {
|
||||||
|
return memberp == refClassp;
|
||||||
|
};
|
||||||
|
if (local && defClassp
|
||||||
|
&& ((refClassp != defClassp) && !(defClassp->existsMember(nestedAccess)))) {
|
||||||
how = "'local'";
|
how = "'local'";
|
||||||
} else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)) {
|
} else if (prot && defClassp && !AstClass::isClassExtendedFrom(refClassp, defClassp)
|
||||||
|
&& !(defClassp->existsMember(nestedAccess))) {
|
||||||
how = "'protected'";
|
how = "'protected'";
|
||||||
}
|
}
|
||||||
if (how) {
|
if (how) {
|
||||||
|
|||||||
+11
-5
@@ -305,13 +305,19 @@ class WidthSelVisitor final : public VNVisitor {
|
|||||||
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
VL_DO_DANGLING(pushDeletep(nodep), nodep);
|
||||||
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
|
} else if (VN_IS(ddtypep, BasicDType) && ddtypep->isString()) {
|
||||||
// SELBIT(string, index) -> GETC(string, index)
|
// SELBIT(string, index) -> GETC(string, index)
|
||||||
const AstNodeVarRef* const varrefp = VN_CAST(fromp, NodeVarRef);
|
AstNodeExpr* exprp = fromp;
|
||||||
if (!varrefp) {
|
while (true) {
|
||||||
nodep->v3warn(E_UNSUPPORTED,
|
if (AstMemberSel* const memberselp = VN_CAST(exprp, MemberSel)) {
|
||||||
"Unsupported: String array operation on non-variable");
|
exprp = memberselp->fromp();
|
||||||
|
} else if (AstStructSel* const structselp = VN_CAST(exprp, StructSel)) {
|
||||||
|
exprp = structselp->fromp();
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
const AstNodeVarRef* const varrefp = VN_CAST(exprp, NodeVarRef);
|
||||||
AstNodeExpr* newp;
|
AstNodeExpr* newp;
|
||||||
if (varrefp && varrefp->access().isReadOnly()) {
|
if (!varrefp || varrefp->access().isReadOnly()) {
|
||||||
newp = new AstGetcN{nodep->fileline(), fromp, rhsp};
|
newp = new AstGetcN{nodep->fileline(), fromp, rhsp};
|
||||||
} else {
|
} else {
|
||||||
newp = new AstGetcRefN{nodep->fileline(), fromp, rhsp};
|
newp = new AstGetcRefN{nodep->fileline(), fromp, rhsp};
|
||||||
|
|||||||
+6
-1
@@ -141,6 +141,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||||||
-?"-cost" { FL; return yVLT_D_COST; }
|
-?"-cost" { FL; return yVLT_D_COST; }
|
||||||
-?"-file" { FL; return yVLT_D_FILE; }
|
-?"-file" { FL; return yVLT_D_FILE; }
|
||||||
-?"-function" { FL; return yVLT_D_FUNCTION; }
|
-?"-function" { FL; return yVLT_D_FUNCTION; }
|
||||||
|
-?"-hier-dpi" { FL; return yVLT_D_HIER_DPI; }
|
||||||
-?"-levels" { FL; return yVLT_D_LEVELS; }
|
-?"-levels" { FL; return yVLT_D_LEVELS; }
|
||||||
-?"-lines" { FL; return yVLT_D_LINES; }
|
-?"-lines" { FL; return yVLT_D_LINES; }
|
||||||
-?"-match" { FL; return yVLT_D_MATCH; }
|
-?"-match" { FL; return yVLT_D_MATCH; }
|
||||||
@@ -1062,7 +1063,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
|
|||||||
"`protect" { FL_FWD; FL_BRK; }
|
"`protect" { FL_FWD; FL_BRK; }
|
||||||
"`remove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
"`remove_gatenames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
||||||
"`remove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
"`remove_netnames" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
||||||
"`resetall" { FL; PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true);
|
"`resetall" { FL;
|
||||||
|
PARSEP->lexFileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE, true);
|
||||||
|
v3Global.rootp()->timeInit();
|
||||||
|
PARSEP->lexFileline()->celldefineOn(false);
|
||||||
|
PARSEP->unconnectedDrive(VOptionBool::OPT_DEFAULT_FALSE);
|
||||||
return yaT_RESETALL; } // Rest handled by preproc
|
return yaT_RESETALL; } // Rest handled by preproc
|
||||||
"`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
"`suppress_faults" { FL_FWD; FL_BRK; } // Verilog-XL compatibility
|
||||||
"`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl,
|
"`timescale"{ws}+[^\n\r]* { FL; PARSEP->lexTimescaleParse(yylval.fl,
|
||||||
|
|||||||
+88
-67
@@ -37,6 +37,7 @@
|
|||||||
|
|
||||||
// Pick up new lexer
|
// Pick up new lexer
|
||||||
#define yylex PARSEP->tokenToBison
|
#define yylex PARSEP->tokenToBison
|
||||||
|
#define BBCOVERIGN(fl, msg) (fl)->v3warn(COVERIGN, msg)
|
||||||
#define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg)
|
#define BBUNSUP(fl, msg) (fl)->v3warn(E_UNSUPPORTED, msg)
|
||||||
#define GATEUNSUP(fl, tok) \
|
#define GATEUNSUP(fl, tok) \
|
||||||
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
|
{ BBUNSUP((fl), "Unsupported: Verilog 1995 gate primitive: " << (tok)); }
|
||||||
@@ -491,6 +492,7 @@ BISONPRE_VERSION(3.7,%define api.header.include {"V3ParseBison.h"})
|
|||||||
%token<fl> yVLT_D_COST "--cost"
|
%token<fl> yVLT_D_COST "--cost"
|
||||||
%token<fl> yVLT_D_FILE "--file"
|
%token<fl> yVLT_D_FILE "--file"
|
||||||
%token<fl> yVLT_D_FUNCTION "--function"
|
%token<fl> yVLT_D_FUNCTION "--function"
|
||||||
|
%token<fl> yVLT_D_HIER_DPI "--hier-dpi"
|
||||||
%token<fl> yVLT_D_LEVELS "--levels"
|
%token<fl> yVLT_D_LEVELS "--levels"
|
||||||
%token<fl> yVLT_D_LINES "--lines"
|
%token<fl> yVLT_D_LINES "--lines"
|
||||||
%token<fl> yVLT_D_MATCH "--match"
|
%token<fl> yVLT_D_MATCH "--match"
|
||||||
@@ -1477,13 +1479,13 @@ portsStarE<nodep>: // IEEE: .* + list_of_ports + list_of_port_decla
|
|||||||
;
|
;
|
||||||
|
|
||||||
list_of_portsE<nodep>: // IEEE: [ list_of_ports + list_of_port_declarations ]
|
list_of_portsE<nodep>: // IEEE: [ list_of_ports + list_of_port_declarations ]
|
||||||
portAndTagE { $$ = $1; }
|
portAndTagE { $$ = $1; }
|
||||||
| list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); }
|
| list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
list_of_ports<nodep>: // IEEE: list_of_ports + list_of_port_declarations
|
list_of_ports<nodep>: // IEEE: list_of_ports + list_of_port_declarations
|
||||||
portAndTag { $$ = $1; }
|
portAndTag { $$ = $1; }
|
||||||
| list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); }
|
| list_of_portsE ',' portAndTagE { $$ = addNextNull($1, $3); }
|
||||||
;
|
;
|
||||||
|
|
||||||
portAndTagE<nodep>:
|
portAndTagE<nodep>:
|
||||||
@@ -1582,33 +1584,43 @@ port<nodep>: // ==IEEE: port
|
|||||||
//
|
//
|
||||||
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
|
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $3; VARDTYPE($2); VARIOANSI(); addNextNull($$, VARDONEP($$, $4, $5)); }
|
{ $$ = $3; VARDTYPE($2); VARIOANSI(); addNextNull($$, VARDONEP($$, $4, $5)); }
|
||||||
|
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
|
{ $$ = $3; VARDTYPE($2); VARIOANSI();
|
||||||
|
if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } }
|
||||||
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
|
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
|
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
|
||||||
|
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
|
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||||
|
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
||||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
|
{ $$ = $4; VARDTYPE($3); VARIOANSI(); addNextNull($$, VARDONEP($$, $5, $6)); }
|
||||||
|
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
|
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
||||||
|
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
||||||
| portDirNetE signing portSig variable_dimensionListE sigAttrListE
|
| portDirNetE signing portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $3;
|
{ $$ = $3;
|
||||||
AstNodeDType* const dtp = new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2};
|
AstNodeDType* const dtp = new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2};
|
||||||
VARDTYPE_NDECL(dtp); VARIOANSI();
|
VARDTYPE_NDECL(dtp); VARIOANSI();
|
||||||
addNextNull($$, VARDONEP($$, $4, $5)); }
|
addNextNull($$, VARDONEP($$, $4, $5)); }
|
||||||
|
| portDirNetE signing portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
|
{ $$ = $3;
|
||||||
|
AstNodeDType* const dtp = new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2};
|
||||||
|
VARDTYPE_NDECL(dtp); VARIOANSI();
|
||||||
|
if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } }
|
||||||
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $4;
|
{ $$ = $4;
|
||||||
AstNodeDType* const dtp = GRAMMARP->addRange(
|
AstNodeDType* const dtp = GRAMMARP->addRange(
|
||||||
new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2}, $3, true);
|
new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2}, $3, true);
|
||||||
VARDTYPE_NDECL(dtp);
|
VARDTYPE_NDECL(dtp);
|
||||||
addNextNull($$, VARDONEP($$, $5, $6)); }
|
addNextNull($$, VARDONEP($$, $5, $6)); }
|
||||||
|
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
|
{ $$ = $4;
|
||||||
|
AstNodeDType* const dtp = GRAMMARP->addRange(
|
||||||
|
new AstBasicDType{$3->fileline(), LOGIC_IMPLICIT, $2}, $3, true);
|
||||||
|
VARDTYPE_NDECL(dtp);
|
||||||
|
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
||||||
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
|
||||||
{ $$ = $2; /*VARDTYPE-same*/ addNextNull($$, VARDONEP($$, $3, $4)); }
|
{ $$ = $2; /*VARDTYPE-same*/ addNextNull($$, VARDONEP($$, $3, $4)); }
|
||||||
//
|
|
||||||
| portDirNetE data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
||||||
{ $$ = $3; VARDTYPE($2); VARIOANSI();
|
|
||||||
if (AstVar* vp = VARDONEP($$, $4, $5)) { addNextNull($$, vp); vp->valuep($7); } }
|
|
||||||
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
||||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
|
||||||
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
|
||||||
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE '=' constExpr
|
|
||||||
{ $$ = $4; VARDTYPE($3); VARIOANSI();
|
|
||||||
if (AstVar* vp = VARDONEP($$, $5, $6)) { addNextNull($$, vp); vp->valuep($8); } }
|
|
||||||
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr
|
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE '=' constExpr
|
||||||
{ $$ = $2; /*VARDTYPE-same*/
|
{ $$ = $2; /*VARDTYPE-same*/
|
||||||
if (AstVar* vp = VARDONEP($$, $3, $4)) { addNextNull($$, vp); vp->valuep($6); } }
|
if (AstVar* vp = VARDONEP($$, $3, $4)) { addNextNull($$, vp); vp->valuep($6); } }
|
||||||
@@ -3831,17 +3843,21 @@ inc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
|
|||||||
// // Need fexprScope instead of variable_lvalue to prevent conflict
|
// // Need fexprScope instead of variable_lvalue to prevent conflict
|
||||||
~l~exprScope yP_PLUSPLUS
|
~l~exprScope yP_PLUSPLUS
|
||||||
{ $<fl>$ = $<fl>1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"},
|
{ $<fl>$ = $<fl>1; $$ = new AstPostAdd{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"},
|
||||||
$1, $1->cloneTreePure(true)}; }
|
// Purity checked in V3LinkInc
|
||||||
|
$1, $1->cloneTree(true)}; }
|
||||||
| ~l~exprScope yP_MINUSMINUS
|
| ~l~exprScope yP_MINUSMINUS
|
||||||
{ $<fl>$ = $<fl>1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"},
|
{ $<fl>$ = $<fl>1; $$ = new AstPostSub{$2, new AstConst{$2, AstConst::StringToParse{}, "'b1"},
|
||||||
$1, $1->cloneTreePure(true)}; }
|
// Purity checked in V3LinkInc
|
||||||
|
$1, $1->cloneTree(true)}; }
|
||||||
// // Need expr instead of variable_lvalue to prevent conflict
|
// // Need expr instead of variable_lvalue to prevent conflict
|
||||||
| yP_PLUSPLUS expr
|
| yP_PLUSPLUS expr
|
||||||
{ $<fl>$ = $<fl>1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"},
|
{ $<fl>$ = $<fl>1; $$ = new AstPreAdd{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"},
|
||||||
$2, $2->cloneTreePure(true)}; }
|
// Purity checked in V3LinkInc
|
||||||
|
$2, $2->cloneTree(true)}; }
|
||||||
| yP_MINUSMINUS expr
|
| yP_MINUSMINUS expr
|
||||||
{ $<fl>$ = $<fl>1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"},
|
{ $<fl>$ = $<fl>1; $$ = new AstPreSub{$1, new AstConst{$1, AstConst::StringToParse{}, "'b1"},
|
||||||
$2, $2->cloneTreePure(true)}; }
|
// Purity checked in V3LinkInc
|
||||||
|
$2, $2->cloneTree(true)}; }
|
||||||
;
|
;
|
||||||
|
|
||||||
finc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
|
finc_or_dec_expression<nodeExprp>: // ==IEEE: inc_or_dec_expression
|
||||||
@@ -3947,16 +3963,16 @@ value_range<nodeExprp>: // ==IEEE: value_range/open_value_range
|
|||||||
covergroup_value_range<nodeExprp>: // ==IEEE-2012: covergroup_value_range
|
covergroup_value_range<nodeExprp>: // ==IEEE-2012: covergroup_value_range
|
||||||
cgexpr { $$ = $1; }
|
cgexpr { $$ = $1; }
|
||||||
| '[' cgexpr ':' cgexpr ']'
|
| '[' cgexpr ':' cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup value range"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); }
|
||||||
// // IEEE-2023: added all four:
|
// // IEEE-2023: added all four:
|
||||||
// // Skipped as '$' is part of our expr
|
// // Skipped as '$' is part of our expr
|
||||||
// // IEEE-2023: '[' '$' ':' cgexpr ']'
|
// // IEEE-2023: '[' '$' ':' cgexpr ']'
|
||||||
// // Skipped as '$' is part of our expr
|
// // Skipped as '$' is part of our expr
|
||||||
// // IEEE-2023: '[' cgexpr ':' '$' ']'
|
// // IEEE-2023: '[' cgexpr ':' '$' ']'
|
||||||
| '[' cgexpr yP_PLUSSLASHMINUS cgexpr ']'
|
| '[' cgexpr yP_PLUSSLASHMINUS cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup value range"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); }
|
||||||
| '[' cgexpr yP_PLUSPCTMINUS cgexpr ']'
|
| '[' cgexpr yP_PLUSPCTMINUS cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup value range"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup value range"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
caseCondList<nodeExprp>: // IEEE: part of case_item
|
caseCondList<nodeExprp>: // IEEE: part of case_item
|
||||||
@@ -6173,13 +6189,13 @@ concurrent_assertion_statement<nodep>: // ==IEEE: concurrent_assertion_statemen
|
|||||||
{ $$ = new AstCover{$1, $4, $6, VAssertType::CONCURRENT}; }
|
{ $$ = new AstCover{$1, $4, $6, VAssertType::CONCURRENT}; }
|
||||||
// // IEEE: cover_sequence_statement
|
// // IEEE: cover_sequence_statement
|
||||||
| yCOVER ySEQUENCE '(' sexpr ')' stmt
|
| yCOVER ySEQUENCE '(' sexpr ')' stmt
|
||||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); }
|
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); }
|
||||||
// // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt
|
// // IEEE: yCOVER ySEQUENCE '(' clocking_event sexpr ')' stmt
|
||||||
// // sexpr already includes "clocking_event sexpr"
|
// // sexpr already includes "clocking_event sexpr"
|
||||||
| yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt
|
| yCOVER ySEQUENCE '(' clocking_event yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt
|
||||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); }
|
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); }
|
||||||
| yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt
|
| yCOVER ySEQUENCE '(' yDISABLE yIFF '(' expr/*expression_or_dist*/ ')' sexpr ')' stmt
|
||||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: cover sequence"); }
|
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: cover sequence"); }
|
||||||
// // IEEE: restrict_property_statement
|
// // IEEE: restrict_property_statement
|
||||||
| yRESTRICT yPROPERTY '(' property_spec ')' ';'
|
| yRESTRICT yPROPERTY '(' property_spec ')' ';'
|
||||||
{ $$ = new AstRestrict{$1, $4}; }
|
{ $$ = new AstRestrict{$1, $4}; }
|
||||||
@@ -6656,7 +6672,7 @@ covergroup_declaration<nodep>: // ==IEEE: covergroup_declaration
|
|||||||
covergroup_declarationFront<constraintp>: // IEEE: part of covergroup_declaration
|
covergroup_declarationFront<constraintp>: // IEEE: part of covergroup_declaration
|
||||||
yCOVERGROUP idAny
|
yCOVERGROUP idAny
|
||||||
{ $$ = new AstConstraint{$<fl>2, *$2, nullptr};
|
{ $$ = new AstConstraint{$<fl>2, *$2, nullptr};
|
||||||
BBUNSUP($<fl>1, "Unsupported: covergroup");
|
BBCOVERIGN($<fl>1, "Ignoring unsupported: covergroup");
|
||||||
SYMP->pushNew($<constraintp>$); }
|
SYMP->pushNew($<constraintp>$); }
|
||||||
;
|
;
|
||||||
|
|
||||||
@@ -6686,27 +6702,27 @@ coverage_option<nodep>: // ==IEEE: coverage_option
|
|||||||
// // option/type_option aren't really keywords
|
// // option/type_option aren't really keywords
|
||||||
id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr
|
id/*yOPTION | yTYPE_OPTION*/ '.' idAny/*member_identifier*/ '=' expr
|
||||||
{ // TODO: check that 'id' is 'option' or 'type_option'
|
{ // TODO: check that 'id' is 'option' or 'type_option'
|
||||||
$$ = nullptr; BBUNSUP($<fl>1, "Unsupported: coverage option"); }
|
$$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage option"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
cover_point<nodep>: // ==IEEE: cover_point
|
cover_point<nodep>: // ==IEEE: cover_point
|
||||||
// // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT
|
// // [ [ data_type_or_implicit ] cover_point_identifier ':' ] yCOVERPOINT
|
||||||
yCOVERPOINT expr iffE bins_or_empty
|
yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverpoint"); }
|
||||||
// // IEEE-2012: class_scope before an ID
|
// // IEEE-2012: class_scope before an ID
|
||||||
| id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>3, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>3, "Ignoring unsupported: coverpoint"); }
|
||||||
// // data_type_or_implicit expansion
|
// // data_type_or_implicit expansion
|
||||||
| data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>4, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: coverpoint"); }
|
||||||
| yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| yVAR data_type id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>5, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); }
|
||||||
| yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| yVAR implicit_typeE id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>5, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); }
|
||||||
| signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| signingE rangeList id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>5, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: coverpoint"); }
|
||||||
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
| signing id/*cover_point_id*/ ':' yCOVERPOINT expr iffE bins_or_empty
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>4, "Unsupported: cover point"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: coverpoint"); }
|
||||||
// // IEEE-2012:
|
// // IEEE-2012:
|
||||||
| bins_or_empty { $$ = $1; }
|
| bins_or_empty { $$ = $1; }
|
||||||
;
|
;
|
||||||
@@ -6714,7 +6730,7 @@ cover_point<nodep>: // ==IEEE: cover_point
|
|||||||
iffE<nodep>: // IEEE: part of cover_point, others
|
iffE<nodep>: // IEEE: part of cover_point, others
|
||||||
/* empty */ { $$ = nullptr; }
|
/* empty */ { $$ = nullptr; }
|
||||||
| yIFF '(' expr ')'
|
| yIFF '(' expr ')'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: cover 'iff'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover 'iff'"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
bins_or_empty<nodep>: // ==IEEE: bins_or_empty
|
bins_or_empty<nodep>: // ==IEEE: bins_or_empty
|
||||||
@@ -6739,24 +6755,24 @@ bins_or_options<nodep>: // ==IEEE: bins_or_options
|
|||||||
coverage_option { $$ = $1; }
|
coverage_option { $$ = $1; }
|
||||||
// // Can't use wildcardE as results in conflicts
|
// // Can't use wildcardE as results in conflicts
|
||||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>4, "Unsupported: cover bin specification"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: cover bin specification"); }
|
||||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
|
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>8, "Unsupported: cover bin 'with' specification"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>8, "Ignoring unsupported: cover bin 'with' specification"); }
|
||||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>5, "Unsupported: cover bin 'wildcard' specification"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: cover bin 'wildcard' specification"); }
|
||||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
|
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' '{' range_list '}' yWITH__CUR '{' cgexpr '}' iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>9, "Unsupported: cover bin 'wildcard' 'with' specification"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>9, "Ignoring unsupported: cover bin 'wildcard' 'with' specification"); }
|
||||||
//
|
//
|
||||||
// // cgexpr part of trans_list
|
// // cgexpr part of trans_list
|
||||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>4, "Unsupported: cover bin trans list"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>4, "Ignoring unsupported: cover bin trans list"); }
|
||||||
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
| yWILDCARD bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' trans_list iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: cover bin 'wildcard' trans list"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover bin 'wildcard' trans list"); }
|
||||||
//
|
//
|
||||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>5, "Unsupported: cover bin 'default'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>5, "Ignoring unsupported: cover bin 'default'"); }
|
||||||
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
| bins_keyword idAny/*bin_identifier*/ bins_orBraE '=' yDEFAULT ySEQUENCE iffE
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>6, "Unsupported: cover bin 'default' 'sequence'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>6, "Ignoring unsupported: cover bin 'default' 'sequence'"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
bins_orBraE<nodep>: // IEEE: part of bins_or_options:
|
bins_orBraE<nodep>: // IEEE: part of bins_or_options:
|
||||||
@@ -6780,23 +6796,23 @@ trans_set<nodep>: // ==IEEE: trans_set
|
|||||||
trans_range_list { $$ = $1; }
|
trans_range_list { $$ = $1; }
|
||||||
// // Note the { => } in the grammar, this is really a list
|
// // Note the { => } in the grammar, this is really a list
|
||||||
| trans_set yP_EQGT trans_range_list
|
| trans_set yP_EQGT trans_range_list
|
||||||
{ $$ = $1; BBUNSUP($<fl>2, "Unsupported: cover trans set '=>'"); }
|
{ $$ = $1; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover trans set '=>'"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
trans_range_list<nodep>: // ==IEEE: trans_range_list
|
trans_range_list<nodep>: // ==IEEE: trans_range_list
|
||||||
trans_item { $$ = $1; }
|
trans_item { $$ = $1; }
|
||||||
| trans_item yP_BRASTAR cgexpr ']'
|
| trans_item yP_BRASTAR cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[*'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[*'"); }
|
||||||
| trans_item yP_BRASTAR cgexpr ':' cgexpr ']'
|
| trans_item yP_BRASTAR cgexpr ':' cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[*'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[*'"); }
|
||||||
| trans_item yP_BRAMINUSGT cgexpr ']'
|
| trans_item yP_BRAMINUSGT cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[->'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[->'"); }
|
||||||
| trans_item yP_BRAMINUSGT cgexpr ':' cgexpr ']'
|
| trans_item yP_BRAMINUSGT cgexpr ':' cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[->'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[->'"); }
|
||||||
| trans_item yP_BRAEQ cgexpr ']'
|
| trans_item yP_BRAEQ cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[='"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[='"); }
|
||||||
| trans_item yP_BRAEQ cgexpr ':' cgexpr ']'
|
| trans_item yP_BRAEQ cgexpr ':' cgexpr ']'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>2, "Unsupported: cover '[='"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>2, "Ignoring unsupported: cover '[='"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
trans_item<nodep>: // ==IEEE: range_list
|
trans_item<nodep>: // ==IEEE: range_list
|
||||||
@@ -6811,9 +6827,9 @@ covergroup_range_list<nodep>: // ==IEEE: covergroup_range_list
|
|||||||
|
|
||||||
cover_cross<nodep>: // ==IEEE: cover_cross
|
cover_cross<nodep>: // ==IEEE: cover_cross
|
||||||
id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body
|
id/*cover_point_identifier*/ ':' yCROSS list_of_cross_items iffE cross_body
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>3, "Unsupported: cross"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>3, "Ignoring unsupported: cover cross"); }
|
||||||
| yCROSS list_of_cross_items iffE cross_body
|
| yCROSS list_of_cross_items iffE cross_body
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: cross"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: cover cross"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
list_of_cross_items<nodep>: // ==IEEE: list_of_cross_items
|
list_of_cross_items<nodep>: // ==IEEE: list_of_cross_items
|
||||||
@@ -6855,25 +6871,25 @@ cross_body_item<nodep>: // ==IEEE: cross_body_item
|
|||||||
coverage_option { $$ = $1; }
|
coverage_option { $$ = $1; }
|
||||||
// // IEEE: bins_selection
|
// // IEEE: bins_selection
|
||||||
| function_declaration
|
| function_declaration
|
||||||
{ $$ = $1; BBUNSUP($1->fileline(), "Unsupported: coverage cross 'function' declaration"); }
|
{ $$ = $1; BBCOVERIGN($1->fileline(), "Ignoring unsupported: coverage cross 'function' declaration"); }
|
||||||
| bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE
|
| bins_keyword idAny/*new-bin_identifier*/ '=' select_expression iffE
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: coverage cross bin"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage cross bin"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
select_expression<nodep>: // ==IEEE: select_expression
|
select_expression<nodep>: // ==IEEE: select_expression
|
||||||
// // IEEE: select_condition expanded here
|
// // IEEE: select_condition expanded here
|
||||||
yBINSOF '(' bins_expression ')'
|
yBINSOF '(' bins_expression ')'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression 'binsof'"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); }
|
||||||
| '!' yBINSOF '(' bins_expression ')'
|
| '!' yBINSOF '(' bins_expression ')'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression 'binsof'"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression 'binsof'"); }
|
||||||
| yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'
|
| yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}'
|
||||||
{ $$ = nullptr; BBUNSUP($5, "Unsupported: coverage select expression 'intersect'"); }
|
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); }
|
||||||
| '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { }
|
| '!' yBINSOF '(' bins_expression ')' yINTERSECT '{' covergroup_range_list '}' { }
|
||||||
{ $$ = nullptr; BBUNSUP($5, "Unsupported: coverage select expression 'intersect'"); }
|
{ $$ = nullptr; BBCOVERIGN($5, "Ignoring unsupported: coverage select expression 'intersect'"); }
|
||||||
| yWITH__PAREN '(' cgexpr ')'
|
| yWITH__PAREN '(' cgexpr ')'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression with"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); }
|
||||||
| '!' yWITH__PAREN '(' cgexpr ')'
|
| '!' yWITH__PAREN '(' cgexpr ')'
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression with"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression with"); }
|
||||||
// // IEEE-2012: Need clarification as to precedence
|
// // IEEE-2012: Need clarification as to precedence
|
||||||
//UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { }
|
//UNSUP yWITH__PAREN '(' cgexpr ')' yMATCHES cgexpr { }
|
||||||
// // IEEE-2012: Need clarification as to precedence
|
// // IEEE-2012: Need clarification as to precedence
|
||||||
@@ -6881,13 +6897,13 @@ select_expression<nodep>: // ==IEEE: select_expression
|
|||||||
//
|
//
|
||||||
| '(' select_expression ')' { $$ = $2; }
|
| '(' select_expression ')' { $$ = $2; }
|
||||||
| select_expression yP_ANDAND select_expression
|
| select_expression yP_ANDAND select_expression
|
||||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: coverage select expression '&&'"); }
|
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '&&'"); }
|
||||||
| select_expression yP_OROR select_expression
|
| select_expression yP_OROR select_expression
|
||||||
{ $$ = nullptr; BBUNSUP($2, "Unsupported: coverage select expression '||'"); }
|
{ $$ = nullptr; BBCOVERIGN($2, "Ignoring unsupported: coverage select expression '||'"); }
|
||||||
// // IEEE-2012: cross_identifier
|
// // IEEE-2012: cross_identifier
|
||||||
// // Part of covergroup_expression - generic identifier
|
// // Part of covergroup_expression - generic identifier
|
||||||
// // IEEE-2012: Need clarification as to precedence
|
// // IEEE-2012: Need clarification as to precedence
|
||||||
//UNSUP cgexpr { $$ = nullptr; BBUNSUP($1, "Unsupported: coverage select expression"); }
|
//UNSUP cgexpr { $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: coverage select expression"); }
|
||||||
//
|
//
|
||||||
// // Need precedence fix
|
// // Need precedence fix
|
||||||
//UNSUP cgexpr yMATCHES cgexpr {..}
|
//UNSUP cgexpr yMATCHES cgexpr {..}
|
||||||
@@ -6904,11 +6920,11 @@ bins_expression<nodep>: // ==IEEE: bins_expression
|
|||||||
coverage_eventE<nodep>: // IEEE: [ coverage_event ]
|
coverage_eventE<nodep>: // IEEE: [ coverage_event ]
|
||||||
/* empty */ { $$ = nullptr; }
|
/* empty */ { $$ = nullptr; }
|
||||||
| clocking_event
|
| clocking_event
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: coverage clocking event"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage clocking event"); }
|
||||||
| yWITH__ETC yFUNCTION idAny/*"sample"*/ '(' tf_port_listE ')'
|
| yWITH__ETC yFUNCTION idAny/*"sample"*/ '(' tf_port_listE ')'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: coverage 'with' 'function'"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage 'with' 'function'"); }
|
||||||
| yP_ATAT '(' block_event_expression ')'
|
| yP_ATAT '(' block_event_expression ')'
|
||||||
{ $$ = nullptr; BBUNSUP($<fl>1, "Unsupported: coverage '@@' events"); }
|
{ $$ = nullptr; BBCOVERIGN($<fl>1, "Ignoring unsupported: coverage '@@' events"); }
|
||||||
;
|
;
|
||||||
|
|
||||||
block_event_expression<nodep>: // ==IEEE: block_event_expression
|
block_event_expression<nodep>: // ==IEEE: block_event_expression
|
||||||
@@ -7348,11 +7364,10 @@ class_item<nodep>: // ==IEEE: class_item
|
|||||||
| class_method { $$ = $1; }
|
| class_method { $$ = $1; }
|
||||||
| class_constraint { $$ = $1; }
|
| class_constraint { $$ = $1; }
|
||||||
//
|
//
|
||||||
| class_declaration
|
| class_declaration { $$ = $1; }
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: class within class"); }
|
|
||||||
| timeunits_declaration { $$ = $1; }
|
| timeunits_declaration { $$ = $1; }
|
||||||
| covergroup_declaration
|
| covergroup_declaration
|
||||||
{ $$ = nullptr; BBUNSUP($1, "Unsupported: covergroup within class"); }
|
{ $$ = nullptr; BBCOVERIGN($1, "Ignoring unsupported: covergroup within class"); }
|
||||||
// // local_parameter_declaration under parameter_declaration
|
// // local_parameter_declaration under parameter_declaration
|
||||||
| parameter_declaration ';' { $$ = $1; }
|
| parameter_declaration ';' { $$ = $1; }
|
||||||
| ';' { $$ = nullptr; }
|
| ';' { $$ = nullptr; }
|
||||||
@@ -7650,6 +7665,8 @@ vltItem:
|
|||||||
{ V3Config::addCaseParallel(*$2, 0); }
|
{ V3Config::addCaseParallel(*$2, 0); }
|
||||||
| yVLT_PARALLEL_CASE vltDFile yVLT_D_LINES yaINTNUM
|
| yVLT_PARALLEL_CASE vltDFile yVLT_D_LINES yaINTNUM
|
||||||
{ V3Config::addCaseParallel(*$2, $4->toUInt()); }
|
{ V3Config::addCaseParallel(*$2, $4->toUInt()); }
|
||||||
|
| yVLT_PROFILE_DATA vltDHierDpi vltDCost
|
||||||
|
{ V3Config::addProfileData($<fl>1, *$2, $3->toUQuad()); }
|
||||||
| yVLT_PROFILE_DATA vltDModel vltDMtask vltDCost
|
| yVLT_PROFILE_DATA vltDModel vltDMtask vltDCost
|
||||||
{ V3Config::addProfileData($<fl>1, *$2, *$3, $4->toUQuad()); }
|
{ V3Config::addProfileData($<fl>1, *$2, *$3, $4->toUQuad()); }
|
||||||
;
|
;
|
||||||
@@ -7694,6 +7711,10 @@ vltDFile<strp>: // --file <arg>
|
|||||||
yVLT_D_FILE str { $$ = $2; }
|
yVLT_D_FILE str { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|
||||||
|
vltDHierDpi<strp>: // --hier-dpi <arg>
|
||||||
|
yVLT_D_HIER_DPI str { $$ = $2; }
|
||||||
|
;
|
||||||
|
|
||||||
vltDLevels<nump>: // --levels <arg>
|
vltDLevels<nump>: // --levels <arg>
|
||||||
yVLT_D_LEVELS yaINTNUM { $$ = $2; }
|
yVLT_D_LEVELS yaINTNUM { $$ = $2; }
|
||||||
;
|
;
|
||||||
|
|||||||
@@ -1417,8 +1417,7 @@ class VlTest:
|
|||||||
pli_opt = "-pli " + self.obj_dir + "/libvpi.so"
|
pli_opt = "-pli " + self.obj_dir + "/libvpi.so"
|
||||||
cmd = [
|
cmd = [
|
||||||
"echo q | " + run_env + VtOs.getenv_def('VERILATOR_MODELSIM', "vsim"),
|
"echo q | " + run_env + VtOs.getenv_def('VERILATOR_MODELSIM', "vsim"),
|
||||||
' '.join(param['ms_run_flags']), ' '.join(param['all_run_flags']), pli_opt,
|
' '.join(param['ms_run_flags']), ' '.join(param['all_run_flags']), pli_opt, (" t")
|
||||||
(" top")
|
|
||||||
]
|
]
|
||||||
self.run(cmd=cmd,
|
self.run(cmd=cmd,
|
||||||
check_finished=param['check_finished'],
|
check_finished=param['check_finished'],
|
||||||
|
|||||||
@@ -17,11 +17,12 @@
|
|||||||
class TestSimulator {
|
class TestSimulator {
|
||||||
private:
|
private:
|
||||||
struct SimTypes {
|
struct SimTypes {
|
||||||
int verilator;
|
bool verilator = false;
|
||||||
int icarus;
|
bool icarus = false;
|
||||||
int mti;
|
bool mti = false;
|
||||||
int ncsim;
|
bool ncsim = false;
|
||||||
int vcs;
|
bool vcs = false;
|
||||||
|
bool questa = false;
|
||||||
};
|
};
|
||||||
s_vpi_vlog_info m_info;
|
s_vpi_vlog_info m_info;
|
||||||
SimTypes m_simulators;
|
SimTypes m_simulators;
|
||||||
@@ -37,6 +38,8 @@ public:
|
|||||||
== strncmp(m_info.product, "Chronologic Simulation VCS",
|
== strncmp(m_info.product, "Chronologic Simulation VCS",
|
||||||
std::strlen("Chronologic Simulation VCS"))) {
|
std::strlen("Chronologic Simulation VCS"))) {
|
||||||
m_simulators.vcs = true;
|
m_simulators.vcs = true;
|
||||||
|
} else if (0 == strcmp(m_info.product, "ModelSim for Questa-64")) {
|
||||||
|
m_simulators.questa = true;
|
||||||
} else {
|
} else {
|
||||||
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", __FILE__,
|
printf("%%Warning: %s:%d: Unknown simulator in TestSimulator.h: %s\n", __FILE__,
|
||||||
__LINE__, m_info.product);
|
__LINE__, m_info.product);
|
||||||
@@ -59,12 +62,13 @@ public:
|
|||||||
static bool is_mti() { return simulators().mti; }
|
static bool is_mti() { return simulators().mti; }
|
||||||
static bool is_ncsim() { return simulators().ncsim; }
|
static bool is_ncsim() { return simulators().ncsim; }
|
||||||
static bool is_vcs() { return simulators().vcs; }
|
static bool is_vcs() { return simulators().vcs; }
|
||||||
|
static bool is_questa() { return simulators().questa; }
|
||||||
// Simulator properties
|
// Simulator properties
|
||||||
static bool is_event_driven() { return !simulators().verilator; }
|
static bool is_event_driven() { return !simulators().verilator; }
|
||||||
static bool has_get_scalar() { return !simulators().icarus; }
|
static bool has_get_scalar() { return !simulators().icarus; }
|
||||||
// return test level scope
|
// return test level scope
|
||||||
static const char* top() {
|
static const char* top() {
|
||||||
if (simulators().verilator || simulators().icarus) {
|
if (simulators().verilator || simulators().icarus || simulators().questa) {
|
||||||
return "t";
|
return "t";
|
||||||
} else {
|
} else {
|
||||||
return "top.t";
|
return "top.t";
|
||||||
|
|||||||
@@ -12,6 +12,8 @@
|
|||||||
#include "sv_vpi_user.h"
|
#include "sv_vpi_user.h"
|
||||||
#include "vpi_user.h"
|
#include "vpi_user.h"
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
// Avoid C++11 in this file as not all simulators allow it
|
// Avoid C++11 in this file as not all simulators allow it
|
||||||
|
|
||||||
//======================================================================
|
//======================================================================
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
// -*- mode: C++; c-file-style: "cc-mode" -*-
|
||||||
//*************************************************************************
|
//*************************************************************************
|
||||||
//
|
//
|
||||||
// Copyright 2024 by Andrew Nolte. This program is free software; you can
|
// Copyright 2024-2025 by Andrew Nolte. This program is free software; you can
|
||||||
// redistribute it and/or modify it under the terms of either the GNU
|
// redistribute it and/or modify it under the terms of either the GNU
|
||||||
// Lesser General Public License Version 3 or the Perl Artistic License
|
// Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
// Version 2.0.
|
// Version 2.0.
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
#
|
#
|
||||||
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
# Copyright 2025 by Wilson Snyder. This program is free software; you
|
||||||
# can redistribute it and/or modify it under the terms of either the GNU
|
# 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
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
# Version 2.0.
|
# Version 2.0.
|
||||||
|
|||||||
@@ -13,11 +13,12 @@
|
|||||||
// please note it here, otherwise:**
|
// please note it here, otherwise:**
|
||||||
//
|
//
|
||||||
// This file ONLY is placed under the Creative Commons Public Domain, for
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
// any use, without warranty, 2024 by Wilson Snyder.
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
`define stop $stop
|
`define stop $stop
|
||||||
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0x exp=%0x (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||||
|
`define checks(gotv,expv) do if ((gotv) != (expv)) begin $write("%%Error: %s:%0d: got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); `stop; end while(0);
|
||||||
|
|
||||||
module t(/*AUTOARG*/
|
module t(/*AUTOARG*/
|
||||||
// Inputs
|
// Inputs
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2024 by Wilson Snyder. This program is free software; you
|
||||||
|
# can redistribute it and/or modify it under the terms of either the GNU
|
||||||
|
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||||
|
# Version 2.0.
|
||||||
|
# SPDX-License-Identifier: LGPL-3.0-only OR Artistic-2.0
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator_st')
|
||||||
|
|
||||||
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
`define stop $stop
|
||||||
|
`define checkd(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%0d exp=%0d (%s !== %s)\n", `__FILE__,`__LINE__, (gotv), (expv), `"gotv`", `"expv`"); `stop; end while(0);
|
||||||
|
|
||||||
|
class Cls;
|
||||||
|
int m_index;
|
||||||
|
|
||||||
|
function automatic int get_index();
|
||||||
|
int rtn;
|
||||||
|
rtn = m_index;
|
||||||
|
++m_index;
|
||||||
|
`ifdef VERILATOR
|
||||||
|
return $c(rtn); // Avoid optimizations
|
||||||
|
`else
|
||||||
|
return rtn;
|
||||||
|
`endif
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
module t (/*AUTOARG*/);
|
||||||
|
|
||||||
|
Cls cls;
|
||||||
|
int array[10];
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
cls = new;
|
||||||
|
// Common UVM construct 'id_cnt[get_id()]++;'
|
||||||
|
// Properly avoid/handle SIDEEFF warnings
|
||||||
|
cls.m_index = 5;
|
||||||
|
array[5] = 50;
|
||||||
|
array[6] = 60;
|
||||||
|
array[7] = 70;
|
||||||
|
array[8] = 80;
|
||||||
|
|
||||||
|
array[cls.get_index()]++;
|
||||||
|
`checkd(array[5], 51);
|
||||||
|
array[cls.get_index()]++;
|
||||||
|
`checkd(array[6], 61);
|
||||||
|
|
||||||
|
++array[cls.get_index()];
|
||||||
|
`checkd(array[7], 71);
|
||||||
|
++array[cls.get_index()];
|
||||||
|
`checkd(array[8], 81);
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -1,5 +0,0 @@
|
|||||||
%Error-UNSUPPORTED: t/t_class_class.v:12:4: Unsupported: class within class
|
|
||||||
12 | class SubCls;
|
|
||||||
| ^~~~~
|
|
||||||
... For error description see https://verilator.org/warn/UNSUPPORTED?v=latest
|
|
||||||
%Error: Exiting due to
|
|
||||||
@@ -11,6 +11,8 @@ import vltest_bootstrap
|
|||||||
|
|
||||||
test.scenarios('simulator')
|
test.scenarios('simulator')
|
||||||
|
|
||||||
test.compile(fails=test.vlt_all, expect_filename=test.golden_filename)
|
test.compile()
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
test.passes()
|
test.passes()
|
||||||
|
|||||||
@@ -31,5 +31,8 @@ module t (/*AUTOARG*/);
|
|||||||
if (c.imemberb != 20) $stop;
|
if (c.imemberb != 20) $stop;
|
||||||
if (c.sc.smembera != 30) $stop;
|
if (c.sc.smembera != 30) $stop;
|
||||||
if (c.sc.smemberb != 40) $stop;
|
if (c.sc.smemberb != 40) $stop;
|
||||||
|
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
end
|
end
|
||||||
endmodule
|
endmodule
|
||||||
|
|||||||
@@ -11,6 +11,9 @@
|
|||||||
`define check_ne(lhs, rhs) `check_comp(lhs, rhs, ==, 1'b0) `check_comp(lhs, rhs, !=, 1'b1)
|
`define check_ne(lhs, rhs) `check_comp(lhs, rhs, ==, 1'b0) `check_comp(lhs, rhs, !=, 1'b1)
|
||||||
|
|
||||||
class Cls;
|
class Cls;
|
||||||
|
class InnerCls;
|
||||||
|
int j;
|
||||||
|
endclass
|
||||||
int i;
|
int i;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
@@ -22,14 +25,25 @@ module t;
|
|||||||
Cls a = new;
|
Cls a = new;
|
||||||
Cls b = new;
|
Cls b = new;
|
||||||
ExtendCls ext = new;
|
ExtendCls ext = new;
|
||||||
|
Cls::InnerCls ia = new;
|
||||||
|
Cls::InnerCls ib = new;
|
||||||
|
ExtendCls::InnerCls iext = new;
|
||||||
`check_ne(a, b)
|
`check_ne(a, b)
|
||||||
`check_ne(a, ext)
|
`check_ne(a, ext)
|
||||||
`check_ne(ext, a)
|
`check_ne(ext, a)
|
||||||
|
`check_ne(ia, ib)
|
||||||
|
`check_ne(ia, iext)
|
||||||
|
`check_ne(iext, ia)
|
||||||
a = b;
|
a = b;
|
||||||
|
ia = ib;
|
||||||
`check_eq(a, b)
|
`check_eq(a, b)
|
||||||
|
`check_eq(ia, ib)
|
||||||
a = ext;
|
a = ext;
|
||||||
|
ia = iext;
|
||||||
`check_eq(a, ext)
|
`check_eq(a, ext)
|
||||||
`check_eq(ext, a)
|
`check_eq(ext, a)
|
||||||
|
`check_eq(ia, iext)
|
||||||
|
`check_eq(iext, ia)
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|||||||
Executable
+18
@@ -0,0 +1,18 @@
|
|||||||
|
#!/usr/bin/env python3
|
||||||
|
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||||
|
#
|
||||||
|
# Copyright 2025 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
|
||||||
|
|
||||||
|
import vltest_bootstrap
|
||||||
|
|
||||||
|
test.scenarios('simulator')
|
||||||
|
|
||||||
|
test.compile(verilator_flags2=['--binary'])
|
||||||
|
|
||||||
|
test.execute()
|
||||||
|
|
||||||
|
test.passes()
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
// DESCRIPTION: Verilator: Verilog Test module
|
||||||
|
//
|
||||||
|
// This file ONLY is placed under the Creative Commons Public Domain, for
|
||||||
|
// any use, without warranty, 2025 by Wilson Snyder.
|
||||||
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
module t();
|
||||||
|
|
||||||
|
class A;
|
||||||
|
int num;
|
||||||
|
function new(int num);
|
||||||
|
this.num = num;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class B;
|
||||||
|
static A obj = new(2);
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class C;
|
||||||
|
static A obj = new(5);
|
||||||
|
endclass
|
||||||
|
|
||||||
|
initial begin
|
||||||
|
#1;
|
||||||
|
$display("Bobj=%p Cobj=%p eq=%p", B::obj, C::obj, (B::obj == C::obj));
|
||||||
|
if (B::obj == C::obj) $stop;
|
||||||
|
$write("*-* All Finished *-*\n");
|
||||||
|
$finish;
|
||||||
|
end
|
||||||
|
|
||||||
|
endmodule
|
||||||
@@ -5,21 +5,55 @@
|
|||||||
// SPDX-License-Identifier: CC0-1.0
|
// SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
class Base0;
|
class Base0;
|
||||||
|
class BaseInnerOnly;
|
||||||
|
int inneronly;
|
||||||
|
function new();
|
||||||
|
inneronly = 10;
|
||||||
|
if (inneronly != 10) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class BaseInnerOver;
|
||||||
|
int innerover;
|
||||||
|
function new();
|
||||||
|
innerover = 10;
|
||||||
|
if (innerover != 10) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int baseonly;
|
int baseonly;
|
||||||
int baseover;
|
int baseover;
|
||||||
|
BaseInnerOnly inneronly = new;
|
||||||
|
BaseInnerOver innerover = new;
|
||||||
|
|
||||||
function void b_set_bo(int v); baseover = v; endfunction
|
function void b_set_bo(int v); baseover = v; endfunction
|
||||||
function int b_get_bo(); return baseover; endfunction
|
function int b_get_bo(); return baseover; endfunction
|
||||||
function int get_bo(); return baseover; endfunction
|
function int get_bo(); return baseover; endfunction
|
||||||
|
function void b_set_io(int v); innerover.innerover = v; endfunction
|
||||||
|
function int b_get_io(); return innerover.innerover; endfunction
|
||||||
|
function int get_io(); return innerover.innerover; endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Ext extends Base0;
|
class Ext extends Base0;
|
||||||
|
class BaseInnerOver;
|
||||||
|
int innerover;
|
||||||
|
function new();
|
||||||
|
innerover = 20;
|
||||||
|
if (innerover != 20) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int baseover;
|
int baseover;
|
||||||
int extonly;
|
int extonly;
|
||||||
|
BaseInnerOnly inneronly = new;
|
||||||
|
BaseInnerOver innerover = new;
|
||||||
|
|
||||||
function void e_set_bo(int v); baseover = v; endfunction
|
function void e_set_bo(int v); baseover = v; endfunction
|
||||||
function int e_get_bo(); return baseover; endfunction
|
function int e_get_bo(); return baseover; endfunction
|
||||||
function int get_bo(); return baseover; endfunction
|
function int get_bo(); return baseover; endfunction
|
||||||
|
function void e_set_io(int v); innerover.innerover = v; endfunction
|
||||||
|
function int e_get_io(); return innerover.innerover; endfunction
|
||||||
|
function int get_io(); return innerover.innerover; endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
@@ -29,15 +63,24 @@ module t (/*AUTOARG*/);
|
|||||||
c.baseonly = 10;
|
c.baseonly = 10;
|
||||||
c.baseover = 20;
|
c.baseover = 20;
|
||||||
c.extonly = 30;
|
c.extonly = 30;
|
||||||
|
c.inneronly.inneronly = 40;
|
||||||
|
c.innerover.innerover = 50;
|
||||||
if (c.baseonly != 10) $stop;
|
if (c.baseonly != 10) $stop;
|
||||||
if (c.baseover != 20) $stop;
|
if (c.baseover != 20) $stop;
|
||||||
if (c.extonly != 30) $stop;
|
if (c.extonly != 30) $stop;
|
||||||
|
if (c.inneronly.inneronly != 40) $stop;
|
||||||
|
if (c.innerover.innerover != 50) $stop;
|
||||||
|
|
||||||
c.b_set_bo(100);
|
c.b_set_bo(100);
|
||||||
c.e_set_bo(200);
|
c.e_set_bo(200);
|
||||||
|
c.b_set_io(300);
|
||||||
|
c.e_set_io(400);
|
||||||
if (c.b_get_bo() != 100) $stop;
|
if (c.b_get_bo() != 100) $stop;
|
||||||
if (c.e_get_bo() != 200) $stop;
|
if (c.e_get_bo() != 200) $stop;
|
||||||
if (c.get_bo() != 200) $stop;
|
if (c.get_bo() != 200) $stop;
|
||||||
|
if (c.b_get_io() != 300) $stop;
|
||||||
|
if (c.e_get_io() != 400) $stop;
|
||||||
|
if (c.get_io() != 400) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
|
|||||||
@@ -6,22 +6,59 @@
|
|||||||
|
|
||||||
package Pkg;
|
package Pkg;
|
||||||
class Base0;
|
class Base0;
|
||||||
|
class BaseInnerOnly;
|
||||||
|
int inneronly;
|
||||||
|
function new();
|
||||||
|
inneronly = 10;
|
||||||
|
if (inneronly != 10) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
|
class BaseInnerOver;
|
||||||
|
int innerover;
|
||||||
|
function new();
|
||||||
|
innerover = 10;
|
||||||
|
if (innerover != 10) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int baseonly;
|
int baseonly;
|
||||||
int baseover;
|
int baseover;
|
||||||
|
BaseInnerOnly inneronly = new;
|
||||||
|
BaseInnerOver innerover = new;
|
||||||
|
|
||||||
function void b_set_bo(int v); baseover = v; endfunction
|
function void b_set_bo(int v); baseover = v; endfunction
|
||||||
function int b_get_bo(); return baseover; endfunction
|
function int b_get_bo(); return baseover; endfunction
|
||||||
function int get_bo(); return baseover; endfunction
|
function int get_bo(); return baseover; endfunction
|
||||||
|
function void b_set_io(int v); innerover.innerover = v; endfunction
|
||||||
|
function int b_get_io(); return innerover.innerover; endfunction
|
||||||
|
function int get_io(); return innerover.innerover; endfunction
|
||||||
endclass
|
endclass
|
||||||
endpackage
|
endpackage
|
||||||
|
|
||||||
|
// We need to import Base0, as verilator currently doesn't support
|
||||||
|
// multiple `::` references, but we would need to do that to reference
|
||||||
|
// `BaseInnerOnly` class inside `Ext` class.
|
||||||
|
import Pkg::Base0;
|
||||||
class Ext extends Pkg::Base0;
|
class Ext extends Pkg::Base0;
|
||||||
|
class BaseInnerOver;
|
||||||
|
int innerover;
|
||||||
|
function new();
|
||||||
|
innerover = 20;
|
||||||
|
if (innerover != 20) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
int baseover;
|
int baseover;
|
||||||
int extonly;
|
int extonly;
|
||||||
|
BaseInnerOnly inneronly = new;
|
||||||
|
BaseInnerOver innerover = new;
|
||||||
|
|
||||||
function void e_set_bo(int v); baseover = v; endfunction
|
function void e_set_bo(int v); baseover = v; endfunction
|
||||||
function int e_get_bo(); return baseover; endfunction
|
function int e_get_bo(); return baseover; endfunction
|
||||||
function int get_bo(); return baseover; endfunction
|
function int get_bo(); return baseover; endfunction
|
||||||
|
function void e_set_io(int v); innerover.innerover = v; endfunction
|
||||||
|
function int e_get_io(); return innerover.innerover; endfunction
|
||||||
|
function int get_io(); return innerover.innerover; endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
module t (/*AUTOARG*/);
|
module t (/*AUTOARG*/);
|
||||||
@@ -31,15 +68,24 @@ module t (/*AUTOARG*/);
|
|||||||
c.baseonly = 10;
|
c.baseonly = 10;
|
||||||
c.baseover = 20;
|
c.baseover = 20;
|
||||||
c.extonly = 30;
|
c.extonly = 30;
|
||||||
|
c.inneronly.inneronly = 40;
|
||||||
|
c.innerover.innerover = 50;
|
||||||
if (c.baseonly != 10) $stop;
|
if (c.baseonly != 10) $stop;
|
||||||
if (c.baseover != 20) $stop;
|
if (c.baseover != 20) $stop;
|
||||||
if (c.extonly != 30) $stop;
|
if (c.extonly != 30) $stop;
|
||||||
|
if (c.inneronly.inneronly != 40) $stop;
|
||||||
|
if (c.innerover.innerover != 50) $stop;
|
||||||
|
|
||||||
c.b_set_bo(100);
|
c.b_set_bo(100);
|
||||||
c.e_set_bo(200);
|
c.e_set_bo(200);
|
||||||
|
c.b_set_io(300);
|
||||||
|
c.e_set_io(400);
|
||||||
if (c.b_get_bo() != 100) $stop;
|
if (c.b_get_bo() != 100) $stop;
|
||||||
if (c.e_get_bo() != 200) $stop;
|
if (c.e_get_bo() != 200) $stop;
|
||||||
if (c.get_bo() != 200) $stop;
|
if (c.get_bo() != 200) $stop;
|
||||||
|
if (c.b_get_io() != 300) $stop;
|
||||||
|
if (c.e_get_io() != 400) $stop;
|
||||||
|
if (c.get_io() != 400) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
|
|||||||
@@ -8,26 +8,53 @@ module t (/*AUTOARG*/
|
|||||||
);
|
);
|
||||||
|
|
||||||
class Foo;
|
class Foo;
|
||||||
|
class InnerFoo;
|
||||||
|
int y = 10;
|
||||||
|
function int get_y;
|
||||||
|
return y;
|
||||||
|
endfunction
|
||||||
|
function int get_30;
|
||||||
|
return 30;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int x = 1;
|
int x = 1;
|
||||||
|
InnerFoo foo = new;
|
||||||
function int get_x;
|
function int get_x;
|
||||||
return x;
|
return x;
|
||||||
endfunction
|
endfunction
|
||||||
function int get_3;
|
function int get_3;
|
||||||
return 3;
|
return 3;
|
||||||
endfunction
|
endfunction
|
||||||
|
function InnerFoo get_foo;
|
||||||
|
return foo;
|
||||||
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Bar #(type T=Foo) extends T;
|
class Bar #(type T=Foo) extends T;
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Baz;
|
class Baz;
|
||||||
|
class InnerFoo;
|
||||||
|
int y = 20;
|
||||||
|
function int get_y;
|
||||||
|
return y;
|
||||||
|
endfunction
|
||||||
|
function int get_40;
|
||||||
|
return 40;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
int x = 2;
|
int x = 2;
|
||||||
|
InnerFoo foo = new;
|
||||||
function int get_x;
|
function int get_x;
|
||||||
return x;
|
return x;
|
||||||
endfunction
|
endfunction
|
||||||
function int get_4;
|
function int get_4;
|
||||||
return 4;
|
return 4;
|
||||||
endfunction
|
endfunction
|
||||||
|
function InnerFoo get_foo;
|
||||||
|
return foo;
|
||||||
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class ExtendBar extends Bar#();
|
class ExtendBar extends Bar#();
|
||||||
@@ -71,6 +98,9 @@ module t (/*AUTOARG*/
|
|||||||
function int get_x_of_item(int i);
|
function int get_x_of_item(int i);
|
||||||
return q[i].x;
|
return q[i].x;
|
||||||
endfunction
|
endfunction
|
||||||
|
function int get_y_of_item(int i);
|
||||||
|
return q[i].get_foo().get_y();
|
||||||
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
Bar #() bar_foo_i;
|
Bar #() bar_foo_i;
|
||||||
@@ -93,8 +123,12 @@ module t (/*AUTOARG*/
|
|||||||
|
|
||||||
if (bar_foo_i.get_x() != 1) $stop;
|
if (bar_foo_i.get_x() != 1) $stop;
|
||||||
if (bar_foo_i.get_3() != 3) $stop;
|
if (bar_foo_i.get_3() != 3) $stop;
|
||||||
|
if (bar_foo_i.get_foo().get_y() != 10) $stop;
|
||||||
|
if (bar_foo_i.get_foo().get_30() != 30) $stop;
|
||||||
if (bar_baz_i.get_x() != 2) $stop;
|
if (bar_baz_i.get_x() != 2) $stop;
|
||||||
if (bar_baz_i.get_4() != 4) $stop;
|
if (bar_baz_i.get_4() != 4) $stop;
|
||||||
|
if (bar_baz_i.get_foo().get_y() != 20) $stop;
|
||||||
|
if (bar_baz_i.get_foo().get_40() != 40) $stop;
|
||||||
if (extend_bar_i.get_x() != 1) $stop;
|
if (extend_bar_i.get_x() != 1) $stop;
|
||||||
if (extend_bar_i.get_6() != 6) $stop;
|
if (extend_bar_i.get_6() != 6) $stop;
|
||||||
if (extend_bar_i.get_x() != 1) $stop;
|
if (extend_bar_i.get_x() != 1) $stop;
|
||||||
@@ -106,6 +140,7 @@ module t (/*AUTOARG*/
|
|||||||
if (extend_extend_bar_i.get_x() != 1) $stop;
|
if (extend_extend_bar_i.get_x() != 1) $stop;
|
||||||
if (extend_extend_bar_i.get_12() != 12) $stop;
|
if (extend_extend_bar_i.get_12() != 12) $stop;
|
||||||
if (extend_foo_dict_i.get_x_of_item(1) != 1) $stop;
|
if (extend_foo_dict_i.get_x_of_item(1) != 1) $stop;
|
||||||
|
if (extend_foo_dict_i.get_y_of_item(1) != 10) $stop;
|
||||||
|
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
|
|||||||
@@ -7,7 +7,20 @@
|
|||||||
typedef class Cls;
|
typedef class Cls;
|
||||||
|
|
||||||
class Base;
|
class Base;
|
||||||
|
class BaseInner;
|
||||||
|
int value = 10;
|
||||||
|
function void test;
|
||||||
|
if (value != 10) $stop;
|
||||||
|
if (this.value != 10) $stop;
|
||||||
|
value = 20;
|
||||||
|
if (value != 20) $stop;
|
||||||
|
this.value = 30;
|
||||||
|
if (value != 30) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int value = 1;
|
int value = 1;
|
||||||
|
BaseInner inner = new;
|
||||||
function void test;
|
function void test;
|
||||||
if (value != 1) $stop;
|
if (value != 1) $stop;
|
||||||
if (this.value != 1) $stop;
|
if (this.value != 1) $stop;
|
||||||
@@ -19,7 +32,25 @@ class Base;
|
|||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Cls extends Base;
|
class Cls extends Base;
|
||||||
|
class BaseInner extends Base::BaseInner;
|
||||||
|
int value = 100;
|
||||||
|
function void test;
|
||||||
|
if (value != 100) $stop;
|
||||||
|
if (this.value != 100) $stop;
|
||||||
|
if (super.value != 10) $stop;
|
||||||
|
super.test();
|
||||||
|
if (value != 100) $stop;
|
||||||
|
if (this.value != 100) $stop;
|
||||||
|
if (super.value != 30) $stop;
|
||||||
|
value = 200;
|
||||||
|
if (value != 200) $stop;
|
||||||
|
this.value = 300;
|
||||||
|
if (value != 300) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
|
|
||||||
int value = 20;
|
int value = 20;
|
||||||
|
BaseInner inner = new;
|
||||||
function void test;
|
function void test;
|
||||||
if (value != 20) $stop;
|
if (value != 20) $stop;
|
||||||
if (this.value != 20) $stop;
|
if (this.value != 20) $stop;
|
||||||
@@ -31,7 +62,9 @@ class Cls extends Base;
|
|||||||
super.value = 9;
|
super.value = 9;
|
||||||
this.value = 29;
|
this.value = 29;
|
||||||
if (super.value != 9) $stop;
|
if (super.value != 9) $stop;
|
||||||
if (value != 29) $stop;;
|
if (value != 29) $stop;
|
||||||
|
|
||||||
|
inner.test();
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
|
|||||||
@@ -7,15 +7,24 @@
|
|||||||
typedef class Cls;
|
typedef class Cls;
|
||||||
|
|
||||||
class Base;
|
class Base;
|
||||||
|
class Inner;
|
||||||
|
int value = 10;
|
||||||
|
function void testBaseInner;
|
||||||
|
if (value != 10) $stop;
|
||||||
|
endfunction
|
||||||
|
endclass
|
||||||
int value = 1;
|
int value = 1;
|
||||||
|
Inner inner = new;
|
||||||
function void testBase;
|
function void testBase;
|
||||||
if (value != 1) $stop;
|
if (value != 1) $stop;
|
||||||
|
if (inner.value != 10) $stop;
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
class Cls extends Base;
|
class Cls extends Base;
|
||||||
function void testDerived;
|
function void testDerived;
|
||||||
if (value != 1) $stop;
|
if (value != 1) $stop;
|
||||||
|
if (inner.value != 10) $stop;
|
||||||
endfunction
|
endfunction
|
||||||
endclass
|
endclass
|
||||||
|
|
||||||
@@ -25,6 +34,7 @@ module t (/*AUTOARG*/);
|
|||||||
c = new;
|
c = new;
|
||||||
c.testBase();
|
c.testBase();
|
||||||
c.testDerived();
|
c.testDerived();
|
||||||
|
c.inner.testBaseInner();
|
||||||
$write("*-* All Finished *-*\n");
|
$write("*-* All Finished *-*\n");
|
||||||
$finish;
|
$finish;
|
||||||
end
|
end
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user