Compare commits

...
91 Commits
Author SHA1 Message Date
Wilson Snyder 7d0dce3267 Version bump 2013-03-09 16:44:48 -05:00
Wilson Snyder 9e29625207 Fix UNOPTFLAT circular array bounds crossing, bug630. 2013-03-08 19:25:20 -05:00
Wilson Snyder a767da4f3f Support <number>'() sized casts, bug628. 2013-03-05 22:13:22 -05:00
Wilson Snyder 7bd96c2876 Internals: Tristate commentary 2013-02-27 22:59:17 -05:00
Wilson Snyder 70fd64dcd6 IEEE 1800-2012 is now the default language. This adds 4 new keywords and updates the svdpi.h and vpi_user.h header files. 2013-02-26 23:01:19 -05:00
Jeremy Bennett bb2822f4b5 Add --report-unoptflat, bug611.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-26 22:26:47 -05:00
Wilson Snyder ad21108b63 Internals: Create graph clone methods. 2013-02-25 21:03:50 -05:00
Wilson Snyder e6808a787c Fix opening a VerilatedVcdC file multiple times, msg1021. 2013-02-23 21:10:25 -05:00
Wilson Snyder 1fb2762725 Tests: Clocking test to consider bug623. 2013-02-22 21:00:37 -05:00
Wilson Snyder cce55941d3 Makefile: Distribute .gdbinit 2013-02-22 17:24:15 -05:00
Wilson Snyder 6c8d95e0e2 Nice message on fopen with missing argument. 2013-02-22 17:14:27 -05:00
Wilson Snyder 216a178b28 Makefile: Distribute .gdbinit 2013-02-22 17:13:31 -05:00
Wilson Snyder 6594a54a95 Fix wrong dot resolution under inlining. 2013-02-21 23:38:29 -05:00
Wilson Snyder a9a4cf061a Fix tristate duplicate __Vcellinp declaration 2013-02-20 22:28:56 -05:00
Wilson Snyder b7f0e204cb Spelling fixes 2013-02-20 21:51:39 -05:00
Varun Koyyalagunta e6a15f233b Internals: GateDedupe: Use visitor per msg980.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-20 20:26:53 -05:00
Varun Koyyalagunta e0edb596ea Add duplicate clock gate optimization, msg980.
Experimental and disabled unless -OD or -O3 used (for now),
Please try it as may get some significant speedups.

Signed-off-by: Wilson Snyder <[email protected]>
2013-02-20 20:14:15 -05:00
Varun Koyyalagunta f2fb77c15a Internals: New Hashed/Graph functions towards msg980.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-19 18:49:36 -05:00
Wilson Snyder 772a3a97eb Internals: Functions in order. No functional change. 2013-02-18 12:15:50 -05:00
Wilson Snyder 6c310836a1 Internals: Track original signal name. No functional change. 2013-02-18 11:22:24 -05:00
Wilson Snyder 75416a3016 Commentary 2013-02-18 11:05:47 -05:00
Wilson Snyder ebef78a13e Tests 2013-02-18 10:17:34 -05:00
Wilson Snyder e71baca39b Internals: Make propagateAttrClocksFrom. No functional change. 2013-02-16 08:07:18 -05:00
Wilson Snyder 18eb210313 Support bind in , bug602. 2013-02-14 06:55:09 -05:00
Wilson Snyder 7d38a5e1f9 Test bug424. 2013-02-13 21:10:17 -05:00
Wilson Snyder 4386077e2d Support pattern assignments with data type labels, bug618. 2013-02-13 20:52:38 -05:00
Wilson Snyder 49dbfd2131 Support pattern assignments in function calls, bug617. 2013-02-13 20:32:25 -05:00
Wilson Snyder a80fce5ac1 Support pattern assignments to const variables, bug616. 2013-02-13 19:32:36 -05:00
Wilson Snyder 891b981cab Fix LITENDIAN on unpacked structures, bug614. 2013-02-13 19:03:10 -05:00
Rich Porter 2dd87b8384 Fix 32-bit OS VPI scan issue, bug615.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-11 07:17:18 -05:00
Jeremy Bennett 062eb85075 Fix DETECTARRAY on packed structures, bug610.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-10 09:54:27 -05:00
Wilson Snyder e1f6802f5f tests: Fix bootstrap wouldn't cd for test_regress/t/t_dist_portability.pl. 2013-02-10 09:29:35 -05:00
Wilson Snyder 6cfcd50f12 devel release 2013-02-04 22:19:37 -05:00
Wilson Snyder bcadb0b3b3 Version bump 2013-02-04 22:12:21 -05:00
Wilson Snyder 0df561f873 Fix whole slices of arrays, bug609. 2013-02-04 22:11:10 -05:00
Wilson Snyder 238fc24684 Remove slow sync() call for NFS flushing. 2013-02-04 21:21:55 -05:00
Wilson Snyder 936855c81c Fix elimination, bug610 _2 test. 2013-02-03 14:13:16 -05:00
Jeremy Bennett 61ad9d4651 Commentary, bug610.
Signed-off-by: Wilson Snyder <[email protected]>
2013-02-03 13:29:37 -05:00
Wilson Snyder f07f6a26a8 cppcheck fixes 2013-02-03 13:27:37 -05:00
Wilson Snyder 4a5a56f8ef Tests: Fix t_vpi_var uninitialized 2013-02-03 12:21:48 -05:00
Wilson Snyder 7d44bba95c Better packed-array misconnect error message 2013-02-02 19:22:02 -05:00
Wilson Snyder 6e6f1045b8 Fix per-bit array output connection error, bug414. 2013-02-02 18:33:10 -05:00
Wilson Snyder 5dd3221759 Fix complete selection of array ports 2013-02-02 16:52:08 -05:00
Wilson Snyder 09edb467f6 Fix CDC report causing out-of-memory 2013-02-02 15:40:59 -05:00
Wilson Snyder ffb187ae15 Fix enums in sensitivity lists 2013-02-02 14:37:18 -05:00
Wilson Snyder b4a8be07f3 Fix enum items under packages. 2013-02-02 14:11:50 -05:00
Wilson Snyder 4968a2abc5 Support inside expressions. 2013-02-02 12:55:48 -05:00
Wilson Snyder 91159da30d Fix enums with X values. Test in next commit. 2013-02-02 12:43:28 -05:00
Wilson Snyder c9ad61b4fb Support wires with data types, bug608. 2013-02-02 09:33:04 -05:00
Wilson Snyder 3f0dcd8c0e Tests: Redo check macro. 2013-02-02 09:28:45 -05:00
Wilson Snyder e1eb41fe77 Fix segfault on multidimensional dotted arrays, bug607. 2013-01-25 21:27:19 -05:00
Wilson Snyder 498ab23355 Commentary 2013-01-20 13:00:02 -05:00
Wilson Snyder 5d6a053f98 Fix internal error on array pin mismatch, bug393. 2013-01-20 12:59:27 -05:00
Wilson Snyder 929aeebf12 Support , and related functions, bug448. 2013-01-20 12:19:22 -05:00
Wilson Snyder 00bd947385 Tests: Additional unsupported iface tests 2013-01-19 14:40:35 -05:00
Wilson Snyder d4ef86afc0 Fix signed/unsigned parameter misconversion, bug606. 2013-01-18 21:35:43 -05:00
Wilson Snyder 1856cad816 Maintain little endian indication for multidimensional arrays 2013-01-17 23:21:07 -05:00
Wilson Snyder 91e2d1d2a0 Tests: Make struct test pass. 2013-01-17 22:45:35 -05:00
Wilson Snyder f29f30dce0 Fix struct +: slices, bug605. 2013-01-17 21:48:35 -05:00
Wilson Snyder e7ba6ef492 Support VPI product info, warning calls, etc, bug588. 2013-01-17 21:40:37 -05:00
Wilson Snyder de4016dcff Internals: Ast classes create declRange(). 2013-01-17 20:41:45 -05:00
Wilson Snyder bbeb382cbb Internals: Rename range lo/hi to match IEEE. 2013-01-17 20:29:20 -05:00
Wilson Snyder 385c166830 Fix package logic var compile error. 2013-01-17 19:04:36 -05:00
Wilson Snyder 410e6ff203 Fix DECLFILENAME warning on . 2013-01-17 18:38:51 -05:00
Jeremy Bennett 8b47c4e307 Fix loosing logic/bit difference and -x-initial-edge fallout, bug604.
Signed-off-by: Wilson Snyder <[email protected]>
2013-01-17 07:16:19 -05:00
Wilson Snyder 6d1b42bedb Fix implicit one bit parameter selection, bug603. 2013-01-16 20:58:48 -05:00
Wilson Snyder f0a4bd28b6 Comment about -x-initial-edge and logic/bit. 2013-01-16 20:47:22 -05:00
Wilson Snyder 2879684f21 Define SYSTEMVERILOG, SV_COV_START and other IEEE mandated predefines. 2013-01-16 19:11:56 -05:00
Wilson Snyder 0437d0abea Fix pin width mismatch error, bug595. 2013-01-15 19:26:35 -05:00
Wilson Snyder 0286f588bf Tests: bind by modname 2013-01-15 19:23:46 -05:00
Wilson Snyder 042fb76837 Tests 2013-01-14 23:39:56 -05:00
Wilson Snyder 795e66eac9 Support bind, to module names only, bug602. 2013-01-14 23:19:44 -05:00
Wilson Snyder aae0615ffd Commentary 2013-01-14 21:51:02 -05:00
Wilson Snyder 8127a79cb1 Fix nested packed arrays and structs, bug600.
IMPORTANT: Packed arrays are now represented as a single linear vector in
Verilated models this may affect packed arrays that are public or accessed via the VPI.
2013-01-14 21:49:22 -05:00
Wilson Snyder 057ca497dd tests: Fix Xs on vector data 2013-01-14 21:38:16 -05:00
Wilson Snyder 66b1611649 In debug, show node dump after errors. 2013-01-14 21:37:55 -05:00
Wilson Snyder 7f5220a6ca Internals: Fix marking of packed vs unpacked wires. 2013-01-13 22:18:57 -05:00
Wilson Snyder e41e26717b Commentary 2013-01-13 19:51:15 -05:00
Wilson Snyder 7a8184d206 Internals: Remove dimension and use only dtypes for V3Width. 2013-01-13 15:21:38 -05:00
Wilson Snyder 13bf2f19ac Internals: Have V3Unknown/Const use only dtypes for selects. 2013-01-13 14:54:12 -05:00
Wilson Snyder 1d5ebfd0b1 Internals: Have V3WidthSel use only dtypes for select promotion. 2013-01-13 14:49:53 -05:00
Wilson Snyder dfc11da2ce Internals: Dump array bounds in tree file. 2013-01-13 14:30:56 -05:00
Wilson Snyder 191af2e87b Internals: Make SelPlus consistent with other branches. No functional change intended. 2013-01-13 11:30:05 -05:00
Wilson Snyder 0985b82760 Commentary 2013-01-13 09:48:12 -05:00
Wilson Snyder 26f4b5a69a Stats: Count only unpacked 2013-01-12 16:26:26 -05:00
Wilson Snyder 5c7a6e278f Internals: Split into packed and unpacked array types 2013-01-12 16:19:25 -05:00
Wilson Snyder ae1ab8aaaa Fix array slice selection of msb==lsb. 2013-01-12 15:34:09 -05:00
Wilson Snyder 18c25d1b6f Commentary 2013-01-12 14:51:16 -05:00
Wilson Snyder 5888a2c399 Internals: Move V3WidthSel::range into V3Width. No functional change intended. 2013-01-12 14:23:56 -05:00
Wilson Snyder c00603704e Commentary 2013-01-11 07:05:25 -05:00
Wilson Snyder 786bc4b04f devel release 2013-01-09 22:27:36 -05:00
202 changed files with 9573 additions and 1084 deletions
+65 -1
View File
@@ -3,6 +3,70 @@ Revision history for Verilator
The contributors that suggested a given feature are shown in []. [by ...]
indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.846 2013-03-09
** IEEE 1800-2012 is now the default language. This adds 4 new keywords
and updates the svdpi.h and vpi_user.h header files.
*** Add --report-unoptflat, bug611. [Jeremy Bennett]
*** Add duplicate clock gate optimization, msg980. [Varun Koyyalagunta]
Disabled unless -OD or -O3 used, please try it as may get some
significant speedups.
*** Fix wrong dot resolution under inlining. [Art Stamness]
**** Support pattern assignment features, bug616, bug617, bug618. [Ed Lander]
**** Support bind in $unit, bug602. [Ed Lander]
**** Support <number>'() sized casts, bug628. [Ed Lander]
**** Fix DETECTARRAY on packed structures, bug610. [Jeremy Bennett]
**** Fix LITENDIAN on unpacked structures, bug614. [Wai Sum Mong]
**** Fix 32-bit OS VPI scan issue, bug615. [Jeremy Bennett, Rich Porter]
**** Fix opening a VerilatedVcdC file multiple times, msg1021. [Frederic Requin]
**** Fix UNOPTFLAT circular array bounds crossing, bug630. [Jie Xu]
* Verilator 3.845 2013/02/04
*** Fix nested packed arrays and struct, bug600. [Jeremy Bennett]
Packed arrays are now represented as a single linear vector in
Verilated models. This may affect packed arrays that are public or
accessed via the VPI.
*** Support wires with data types, bug608. [Ed Lander]
*** Support bind, to module names only, bug602. [Ed Lander]
*** Support VPI product info, warning calls, etc, bug588. [Rick Porter]
*** Support $left, $right and related functions, bug448. [Iztok Jeras]
*** Support inside expressions.
*** Define SYSTEMVERILOG, SV_COV_START and other IEEE mandated predefines.
**** Fix pin width mismatch error, bug595. [Alex Solomatnikov]
**** Fix implicit one bit parameter selection, bug603. [Jeremy Bennett]
**** Fix signed/unsigned parameter misconversion, bug606. [Jeremy Bennett]
**** Fix segfault on multidimensional dotted arrays, bug607. [Jie Xu]
**** Fix per-bit array output connection error, bug414. [Jan Egil Ruud]
**** Fix package logic var compile error.
**** Fix enums with X values.
* Verilator 3.844 2013/01/09
*** Support "unsigned int" DPI import functions, msg966. [Alex Lee]
@@ -13,7 +77,7 @@ indicates the contributor was also the author of the fix; Thanks!
**** Fix task inlining under $display and case, bug589, bug598. [Holger Waechtler]
**** Fix package import of non-localparam parameter, bug591. [Jeremy Bennett]
**** Fix package import of non-localparam parameter, bug474, bug591. [Jeremy Bennett]
**** Fix package import of package imports, partial bug592. [Jeremy Bennett]
+1 -1
View File
@@ -1,6 +1,5 @@
^CVS/
/CVS/
\.gdbinit$
\.git/
\.svn/
\.(bak|old)/
@@ -23,6 +22,7 @@
src/Makefile$
src/Makefile_obj$
include/verilated.mk$
test_regress/.gdbinit$
config.cache$
config.status$
verilator.log
+7 -3
View File
@@ -121,6 +121,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
include/vltstd/*.[chv]* \
.*attributes */.*attributes */*/.*attributes \
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
src/.gdbinit \
src/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
test_*/*.pl test_*/*.v test_*/*.vc test_*/*.vh \
@@ -398,14 +399,17 @@ endif
# VERILATOR_AUTHOR_SITE
endif
# Use --xml flag to see the cppcheck code to use for suppression
CPPCHECK = cppcheck
CPPCHECK_FLAGS = --enable=all --inline-suppr --suppress=unusedScopedObject
CPPCHECK_FLAGS = --enable=all --inline-suppr --suppress=unusedScopedObject --suppress=cstyleCast
CPPCHECK_FLAGS += --xml
CPPCHECK_CPP = $(wildcard $(srcdir)/include/*.cpp $(srcdir)/src/*.cpp)
CPPCHECK_DEP = $(subst .cpp,.cppcheck,$(CPPCHECK_CPP))
CPPCHECK_INC = -I$(srcdir)/include -I$(srcdir)/src/obj_dbg -I$(srcdir)/src
cppcheck: $(CPPCHECK_DEP)
%.cppcheck: %.cpp
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 -I$(srcdir)/include -I$(srcdir)/src $<
$(CPPCHECK) $(CPPCHECK_FLAGS) -DVL_DEBUG=1 $(CPPCHECK_INC) $<
ftp: info
@@ -455,7 +459,7 @@ clean mostlyclean distclean maintainer-clean::
distclean maintainer-clean::
rm -f Makefile config.status config.cache config.log verilator_bin* TAGS
rm -f include/verilated.mk
rm -f include/verilated.mk include/verilated_config.h
TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
${srcdir}/*.in ${srcdir}/*.pod
+66 -12
View File
@@ -202,9 +202,8 @@ Verilator - Convert Verilog code to C++/SystemC
verilator --help
verilator --version
verilator --cc [options] [top_level.v] [opt_c_files.cpp/c/cc/a/o/so]
verilator --sc [options] [top_level.v] [opt_c_files.cpp/c/cc/a/o/so]
verilator --sp [options] [top_level.v] [opt_c_files.cpp/c/cc/a/o/so]
verilator --cc [options] [top_level.v]... [opt_c_files.cpp/c/cc/a/o/so]
verilator --sc [options] [top_level.v]... [opt_c_files.cpp/c/cc/a/o/so]
verilator --lint-only [top_level.v]...
=head1 DESCRIPTION
@@ -246,6 +245,7 @@ descriptions in the next sections for more information.
+1364-2005ext+<ext> Use Verilog 2005 with file extension <ext>
+1800-2005ext+<ext> Use SystemVerilog 2005 with file extension <ext>
+1800-2009ext+<ext> Use SystemVerilog 2009 with file extension <ext>
+1800-2012ext+<ext> Use SystemVerilog 2012 with file extension <ext>
--assert Enable all assertions
--autoflush Flush streams after all $displays
--bbox-sys Blackbox unknown $system calls
@@ -309,12 +309,13 @@ descriptions in the next sections for more information.
--private Debugging; see docs
--psl Enable PSL parsing
--public Debugging; see docs
--report-unoptflat Extra diagnostics for UNOPTFLAT
--savable Enable model save-restore
--sc Create SystemC output
--sp Create SystemPerl output
--stats Create statistics file
-sv Enable SystemVerilog parsing
+systemverilogext+<ext> Synonym for +1800-2009ext+<ext>
+systemverilogext+<ext> Synonym for +1800-2012ext+<ext>
--top-module <topname> Name of top level input module
--trace Enable waveform creation
--trace-depth <levels> Depth of tracing
@@ -374,6 +375,8 @@ with the --exe option.
=item +1800-2009ext+I<ext>
=item +1800-2012ext+I<ext>
Specifies the language standard to be used with a specific filename
extension, I<ext>.
@@ -585,7 +588,7 @@ C<--debug> is equivalent to C<--debugi 4>).
Select the language to be used by default when first processing each
Verilog file. The language value must be "1364-1995", "1364-2001",
"1364-2005", "1800-2005" or "1800-2009".
"1364-2005", "1800-2005", "1800-2009" or "1800-2012".
Any language associated with a particular file extension (see the various
+I<lang>ext+ options) will be used in preference to the language specified
@@ -598,7 +601,7 @@ legacy mixed language designs, the various +I<lang>ext+ options should be
used.
If no language is specified, either by this flag or +I<lang>ext+ options,
then the latest SystemVerilog language (IEEE 1800-2009) is used.
then the latest SystemVerilog language (IEEE 1800-2012) is used.
=item +define+I<var>+I<value>
@@ -878,6 +881,27 @@ inlining. This will also turn off inlining as if all modules had a
/*verilator public_module*/, unless the module specifically enabled it with
/*verilator inline_module*/.
=item --report-unoptflat
Extra diagnostics for UNOPTFLAT warnings. This includes for each loop, the
10 widest variables in the loop, and the 10 most fanned out variables in
the loop. These are candidates for splitting into multiple variables to
break the loop.
In addition produces a GraphViz DOT file of the entire strongly connected
components within the source associated with each loop. This is produced
irrespective of whether --dump-tree is set. Such graphs may help in
analysing the problem, but can be very large indeed.
Various commands exist for viewing and manipulating DOT files. For example
the I<dot> command can be used to convert a DOT file to a PDF for
printing. For example:
dot -Tpdf -O Vt_unoptflat_simple_2_35_unoptflat.dot
will generate a PDF Vt_unoptflat_simple_2_35_unoptflat.dot.pdf from the DOT
file.
=item --savable
Enable including save and restore functions in the generated model.
@@ -919,7 +943,7 @@ compatibility with other simulators.
=item +systemverilogext+I<ext>
A synonym for C<+1800-2009ext+>I<ext>.
A synonym for C<+1800-2012ext+>I<ext>.
=item --top-module I<topname>
@@ -1321,7 +1345,8 @@ OPT_FAST and OPT_SLOW affect. For best results, use OPT="-O2", and link
with "-static". Nearly the same results can be had with much better
compile times with OPT_FAST="-O1 -fstrict-aliasing". Higher optimization
such as "-O3" may help, but gcc compile times may be excessive under O3 on
even medium sized designs.
even medium sized designs. Alternatively, some larger designs report
better performance using "-Os".
Unfortunately, using the optimizer with SystemC files can result in
compiles taking several minutes. (The SystemC libraries have many little
@@ -1894,13 +1919,13 @@ It also supports .name and .* interconnection.
Verilator partially supports concurrent assert and cover statements; see
the enclosed coverage tests for the syntax which is allowed.
=head2 SystemVerilog 2009 (IEEE 1800-2009) Support
=head2 SystemVerilog 2012 (IEEE 1800-2012) Support
Verilator implements a full SystemVerilog 2009 preprocessor, including
Verilator implements a full SystemVerilog 2012 preprocessor, including
function call-like preprocessor defines, default define arguments,
`__FILE__, `__LINE__ and `undefineall.
Verilator currently has some support for SystemVerilog 2009 synthesis
Verilator currently has some support for SystemVerilog synthesis
constructs. As SystemVerilog features enter common usage they are added;
please file a bug if a feature you need is missing.
@@ -2070,6 +2095,11 @@ functions, the Verilog signals must be declared with /*verilator public*/.
See also the public task feature; writing an accessor may result in cleaner
code.
=item `SYSTEMVERILOG
The SYSTEMVERILOG, SV_COV_START and related standard defines are set by
default when --language is 1800-*.
=item `VERILATOR
=item `verilator
@@ -2327,6 +2357,11 @@ always @* to reduce missing activity items. Avoid putting $displays in
combo blocks, as they may print multiple times when not desired, even on
compliant simulators as event ordering is not specified.
=head2 Bind
Verilator only supports "bind" to a target module name, not an instance
path.
=head2 Dotted cross-hierarchy references
Verilator supports dotted references to variables, functions and tasks in
@@ -2548,6 +2583,11 @@ the disable statement itself is inside. This was commonly used to provide
loop break and continue functionality before SystemVerilog added the break
and continue keywords.
=item inside
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
=item priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted to be
@@ -2822,6 +2862,15 @@ designs should now be using the #(...) format to specify parameters.
Disabled by default as this is a code style warning; it will simulate
correctly.
=item DETECTARRAY
Error when Verilator tries to deal with a combinatorial loop that could not be
flattened, and which involves a datatype which Verilator cannot handle, such
as an unpacked struct or a large unpacked array. This typically ocurrs when
-Wno-UNOPTFLAT has been used to override an UNOPTFLAT warning (see below).
The solution is to break the loop, as described for UNOPTFLAT.
=item ENDLABEL
Warns that a label attached to a "end"-something statement does not match
@@ -2903,7 +2952,7 @@ simulators.
=item LITENDIAN
Warns that a vector is declared with little endian bit numbering
Warns that a packed vector is declared with little endian bit numbering
(i.e. [0:7]). Big endian bit numbering is now the overwhelming standard,
and little numbering is now thus often due to simple oversight instead of
intent.
@@ -3122,6 +3171,11 @@ The UNOPTFLAT warning may also occur where outputs from a block of logic
are independent, but occur in the same always block. To fix this, use the
isolate_assignments meta comment described above.
To assist in resolving UNOPTFLAT, the option C<--report-unoptflat> can be
used, which will provide suggestions for variables that can be split up,
and a graph of all the nodes connected in the loop. See the L<Arguments>
section for more details.
Ignoring this warning will only slow simulations, it will simulate
correctly.
+2 -2
View File
@@ -6,9 +6,9 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.844 2013-01-09])
AC_INIT([Verilator],[3.846 2013-03-09])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
AC_MSG_RESULT([configuring for $PACKAGE_STRING])
+1
View File
@@ -1 +1,2 @@
verilated.mk
verilated_config.h
+9 -3
View File
@@ -40,6 +40,7 @@ Verilated::Serialized Verilated::s_s;
VL_THREAD const VerilatedScope* Verilated::t_dpiScopep = NULL;
VL_THREAD const char* Verilated::t_dpiFilename = "";
VL_THREAD int Verilated::t_dpiLineno = 0;
struct Verilated::CommandArgValues Verilated::s_args = {0, NULL};
VerilatedImp VerilatedImp::s_s;
@@ -86,6 +87,7 @@ Verilated::Serialized::Serialized() {
s_calcUnusedSigs = false;
s_gotFinish = false;
s_assertOn = true;
s_fatalOnVpiError = true; // retains old default behaviour
}
//===========================================================================
@@ -601,7 +603,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
vlsint64_t ld;
sscanf(tmp,"%" VL_PRI64 "d",&ld);
sscanf(tmp,"%30" VL_PRI64 "d",&ld);
VL_SET_WQ(owp,ld);
break;
}
@@ -622,7 +624,7 @@ IData _vl_vsscanf(FILE* fp, // If a fscanf
_vl_vsss_read(fp,floc,fromp, tmp, "0123456789+-xXzZ?_");
if (!tmp[0]) goto done;
QData ld;
sscanf(tmp,"%" VL_PRI64 "u",&ld);
sscanf(tmp,"%30" VL_PRI64 "u",&ld);
VL_SET_WQ(owp,ld);
break;
}
@@ -975,7 +977,7 @@ IData VL_VALUEPLUSARGS_IW(int rbits, const char* prefixp, char fmt, WDataOutP rw
break;
case 'd':
vlsint64_t ld;
sscanf(dp,"%" VL_PRI64 "d",&ld);
sscanf(dp,"%30" VL_PRI64 "d",&ld);
VL_SET_WQ(rwp,ld);
break;
case 'b':
@@ -1064,6 +1066,8 @@ void Verilated::flushCb(VerilatedVoidCb cb) {
}
void Verilated::commandArgs(int argc, const char** argv) {
s_args.argc = argc;
s_args.argv = argv;
VerilatedImp::commandArgs(argc,argv);
}
@@ -1097,6 +1101,7 @@ VerilatedModule::~VerilatedModule() {
//======================================================================
// VerilatedVar:: Methods
// cppcheck-suppress unusedFunction // Used by applications
vluint32_t VerilatedVar::entSize() const {
vluint32_t size = 1;
switch (vltype()) {
@@ -1193,6 +1198,7 @@ void VerilatedScope::varInsert(int finalize, const char* namep, void* datap,
m_varsp->insert(make_pair(namep,var));
}
// cppcheck-suppress unusedFunction // Used by applications
VerilatedVar* VerilatedScope::varFind(const char* namep) const {
if (VL_LIKELY(m_varsp)) {
VerilatedVarNameMap::iterator it = m_varsp->find(namep);
+17
View File
@@ -28,6 +28,7 @@
#ifndef _VERILATED_H_
#define _VERILATED_H_ 1 ///< Header Guard
#include "verilated_config.h"
#include "verilatedos.h"
#include <cassert>
@@ -229,6 +230,7 @@ private:
bool s_calcUnusedSigs; ///< Waves file on, need all signals calculated
bool s_gotFinish; ///< A $finish statement executed
bool s_assertOn; ///< Assertions are enabled
bool s_fatalOnVpiError; ///< Stop on vpi error/unsupported
Serialized();
} s_s;
@@ -236,6 +238,13 @@ private:
static VL_THREAD const char* t_dpiFilename; ///< DPI context filename
static VL_THREAD int t_dpiLineno; ///< DPI context line number
// no need to be save-restored (serialized) the
// assumption is that the restore is allowed to pass different arguments
static struct CommandArgValues {
int argc;
const char** argv;
} s_args;
public:
// METHODS - User called
@@ -268,6 +277,9 @@ public:
/// Enable/disable assertions
static void assertOn(bool flag) { s_s.s_assertOn=flag; }
static bool assertOn() { return s_s.s_assertOn; }
/// Enable/disable vpi fatal
static void fatalOnVpiError(bool flag) { s_s.s_fatalOnVpiError=flag; }
static bool fatalOnVpiError() { return s_s.s_fatalOnVpiError; }
/// Flush callback for VCD waves
static void flushCb(VerilatedVoidCb cb);
static void flushCall() { if (s_flushCb) (*s_flushCb)(); }
@@ -275,8 +287,13 @@ public:
/// Record command line arguments, for retrieval by $test$plusargs/$value$plusargs
static void commandArgs(int argc, const char** argv);
static void commandArgs(int argc, char** argv) { commandArgs(argc,(const char**)argv); }
static CommandArgValues* getCommandArgs() {return &s_args;}
static const char* commandArgsPlusMatch(const char* prefixp);
/// Produce name & version for (at least) VPI
static const char* productName() { return VERILATOR_PRODUCT; }
static const char* productVersion() { return VERILATOR_VERSION; }
/// For debugging, print text list of all scope names with
/// dpiImport/Export context. This function may change in future
/// releases - contact the authors before production use.
+28
View File
@@ -0,0 +1,28 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
//
// Copyright 2003-2012 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.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
///
/// \file
/// \brief Verilator: Auto version information include for all Verilated C files
///
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
///**** Product and Version name
// Autoconf substitutes this with the strings from AC_INIT.
#define VERILATOR_PRODUCT "@PACKAGE_NAME@"
#define VERILATOR_VERSION "@PACKAGE_VERSION@"
-3
View File
@@ -104,9 +104,6 @@ int svHigh(const svOpenArrayHandle h, int d) {
int svIncrement(const svOpenArrayHandle h, int d) {
_VL_SVDPI_UNIMP(); return 0;
}
int svLength(const svOpenArrayHandle h, int d) {
_VL_SVDPI_UNIMP(); return 0;
}
int svDimensions(const svOpenArrayHandle h) {
_VL_SVDPI_UNIMP(); return 0;
}
+2
View File
@@ -116,6 +116,7 @@ void VerilatedSave::open (const char* filenamep) {
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open (filenamep, O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK
, 0666);
if (m_fd<0) {
@@ -137,6 +138,7 @@ void VerilatedRestore::open (const char* filenamep) {
if (filenamep[0]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open (filenamep, O_CREAT|O_RDONLY|O_LARGEFILE
, 0666);
if (m_fd<0) {
+3 -3
View File
@@ -109,7 +109,7 @@ protected:
void trailer();
public:
// CREATORS
VerilatedDeserialize() {}
VerilatedDeserialize() { m_endp = NULL; }
virtual ~VerilatedDeserialize() { close(); }
// METHODS
inline VerilatedDeserialize& read (void* __restrict datap, size_t size) {
@@ -146,7 +146,7 @@ private:
public:
// CREATORS
VerilatedSave() {}
VerilatedSave() { m_fd=-1; }
virtual ~VerilatedSave() { close(); }
// METHODS
void open(const char* filenamep); ///< Open the file; call isOpen() to see if errors
@@ -164,7 +164,7 @@ private:
public:
// CREATORS
VerilatedRestore() {}
VerilatedRestore() { m_fd=-1; }
virtual ~VerilatedRestore() { close(); }
// METHODS
+10 -2
View File
@@ -141,6 +141,7 @@ void VerilatedVcd::openNext (bool incFilename) {
if (m_filename[0]=='|') {
assert(0); // Not supported yet.
} else {
// cppcheck-suppress duplicateExpression
m_fd = ::open (m_filename.c_str(), O_CREAT|O_WRONLY|O_TRUNC|O_LARGEFILE|O_NONBLOCK
, 0666);
if (m_fd<0) {
@@ -156,6 +157,8 @@ void VerilatedVcd::openNext (bool incFilename) {
void VerilatedVcd::makeNameMap() {
// Take signal information from each module and build m_namemapp
deleteNameMap();
m_nextCode = 1;
m_namemapp = new NameMap;
for (vluint32_t ent = 0; ent< m_callbacks.size(); ent++) {
VerilatedVcdCallInfo *cip = m_callbacks[ent];
@@ -182,15 +185,20 @@ void VerilatedVcd::makeNameMap() {
newname += hiername;
newmapp->insert(make_pair(newname,decl));
}
delete m_namemapp; m_namemapp=NULL;
deleteNameMap();
m_namemapp = newmapp;
}
}
void VerilatedVcd::deleteNameMap() {
if (m_namemapp) { delete m_namemapp; m_namemapp=NULL; }
}
VerilatedVcd::~VerilatedVcd() {
close();
if (m_wrBufp) { delete[] m_wrBufp; m_wrBufp=NULL; }
if (m_sigs_oldvalp) { delete[] m_sigs_oldvalp; m_sigs_oldvalp=NULL; }
deleteNameMap();
// Remove from list of traces
vector<VerilatedVcd*>::iterator pos = find(s_vcdVecp.begin(), s_vcdVecp.end(), this);
if (pos != s_vcdVecp.end()) { s_vcdVecp.erase(pos); }
@@ -413,7 +421,7 @@ void VerilatedVcd::dumpHeader () {
assert (m_modDepth==0);
// Reclaim storage
delete m_namemapp;
deleteNameMap();
}
void VerilatedVcd::module (string name) {
+7 -1
View File
@@ -57,7 +57,8 @@ typedef void (*VerilatedVcdCallback_t)(VerilatedVcd* vcdp, void* userthis, vluin
//=============================================================================
// VerilatedVcd
/// Create a SystemPerl VCD dump
/// Base class to create a Verilator VCD dump
/// This is an internally used class - see VerilatedVcdC for what to call from applications
class VerilatedVcd {
private:
@@ -100,6 +101,7 @@ private:
void closeErr();
void openNext();
void makeNameMap();
void deleteNameMap();
void printIndent (int levelchange);
void printStr (const char* str);
void printQuad (vluint64_t n);
@@ -400,8 +402,12 @@ public:
bool isOpen() const { return m_sptrace.isOpen(); }
// METHODS
/// Open a new VCD file
/// This includes a complete header dump each time it is called,
/// just as if this object was deleted and reconstructed.
void open (const char* filename) { m_sptrace.open(filename); }
/// Continue a VCD dump by rotating to a new file name
/// The header is only in the first file created, this allows
/// "cat" to be used to combine the header plus any number of data files.
void openNext (bool incFilename=true) { m_sptrace.openNext(incFilename); }
/// Set size in megabytes after which new file should be created
void rolloverMB(size_t rolloverMB) { m_sptrace.rolloverMB(rolloverMB); };
+331
View File
@@ -31,3 +31,334 @@ VerilatedVpi VerilatedVpi::s_s; // Singleton
vluint8_t* VerilatedVpio::s_freeHead = NULL;
//======================================================================
const char* VerilatedVpiError::strFromVpiVal(PLI_INT32 vpiVal) {
static const char *names[] = {
"*undefined*",
"vpiBinStrVal",
"vpiOctStrVal",
"vpiDecStrVal",
"vpiHexStrVal",
"vpiScalarVal",
"vpiIntVal",
"vpiRealVal",
"vpiStringVal",
"vpiVectorVal",
"vpiStrengthVal",
"vpiTimeVal",
"vpiObjTypeVal",
"vpiSuppressVal",
"vpiShortIntVal",
"vpiLongIntVal",
"vpiShortRealVal",
"vpiRawTwoStateVal",
"vpiRawFourStateVal",
};
if (vpiVal < 0) return names[0];
return names[(vpiVal<=vpiRawFourStateVal)?vpiVal:0];
}
const char* VerilatedVpiError::strFromVpiObjType(PLI_INT32 vpiVal) {
static const char *names[] = {
"*undefined*",
"vpiAlways",
"vpiAssignStmt",
"vpiAssignment",
"vpiBegin",
"vpiCase",
"vpiCaseItem",
"vpiConstant",
"vpiContAssign",
"vpiDeassign",
"vpiDefParam",
"vpiDelayControl",
"vpiDisable",
"vpiEventControl",
"vpiEventStmt",
"vpiFor",
"vpiForce",
"vpiForever",
"vpiFork",
"vpiFuncCall",
"vpiFunction",
"vpiGate",
"vpiIf",
"vpiIfElse",
"vpiInitial",
"vpiIntegerVar",
"vpiInterModPath",
"vpiIterator",
"vpiIODecl",
"vpiMemory",
"vpiMemoryWord",
"vpiModPath",
"vpiModule",
"vpiNamedBegin",
"vpiNamedEvent",
"vpiNamedFork",
"vpiNet",
"vpiNetBit",
"vpiNullStmt",
"vpiOperation",
"vpiParamAssign",
"vpiParameter",
"vpiPartSelect",
"vpiPathTerm",
"vpiPort",
"vpiPortBit",
"vpiPrimTerm",
"vpiRealVar",
"vpiReg",
"vpiRegBit",
"vpiRelease",
"vpiRepeat",
"vpiRepeatControl",
"vpiSchedEvent",
"vpiSpecParam",
"vpiSwitch",
"vpiSysFuncCall",
"vpiSysTaskCall",
"vpiTableEntry",
"vpiTask",
"vpiTaskCall",
"vpiTchk",
"vpiTchkTerm",
"vpiTimeVar",
"vpiTimeQueue",
"vpiUdp",
"vpiUdpDefn",
"vpiUserSystf",
"vpiVarSelect",
"vpiWait",
"vpiWhile",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"vpiAttribute",
"vpiBitSelect",
"vpiCallback",
"vpiDelayTerm",
"vpiDelayDevice",
"vpiFrame",
"vpiGateArray",
"vpiModuleArray",
"vpiPrimitiveArray",
"vpiNetArray",
"vpiRange",
"vpiRegArray",
"vpiSwitchArray",
"vpiUdpArray",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"*undefined*",
"vpiContAssignBit",
"vpiNamedEventArray",
"vpiIndexedPartSelect",
"*undefined*",
"*undefined*",
"vpiGenScopeArray",
"vpiGenScope",
"vpiGenVar"
};
if (vpiVal < 0) return names[0];
return names[(vpiVal<=vpiGenVar)?vpiVal:0];
}
const char* VerilatedVpiError::strFromVpiMethod(PLI_INT32 vpiVal) {
static const char *names[] = {
"vpiCondition",
"vpiDelay",
"vpiElseStmt",
"vpiForIncStmt",
"vpiForInitStmt",
"vpiHighConn",
"vpiLhs",
"vpiIndex",
"vpiLeftRange",
"vpiLowConn",
"vpiParent",
"vpiRhs",
"vpiRightRange",
"vpiScope",
"vpiSysTfCall",
"vpiTchkDataTerm",
"vpiTchkNotifier",
"vpiTchkRefTerm",
"vpiArgument",
"vpiBit",
"vpiDriver",
"vpiInternalScope",
"vpiLoad",
"vpiModDataPathIn",
"vpiModPathIn",
"vpiModPathOut",
"vpiOperand",
"vpiPortInst",
"vpiProcess",
"vpiVariables",
"vpiUse",
"vpiExpr",
"vpiPrimitive",
"vpiStmt"
};
if (vpiVal>vpiStmt || vpiVal<vpiCondition) {
return "*undefined*";
}
return names[vpiVal-vpiCondition];
}
const char* VerilatedVpiError::strFromVpiCallbackReason(PLI_INT32 vpiVal) {
static const char *names[] = {
"*undefined*",
"cbValueChange",
"cbStmt",
"cbForce",
"cbRelease",
"cbAtStartOfSimTime",
"cbReadWriteSynch",
"cbReadOnlySynch",
"cbNextSimTime",
"cbAfterDelay",
"cbEndOfCompile",
"cbStartOfSimulation",
"cbEndOfSimulation",
"cbError",
"cbTchkViolation",
"cbStartOfSave",
"cbEndOfSave",
"cbStartOfRestart",
"cbEndOfRestart",
"cbStartOfReset",
"cbEndOfReset",
"cbEnterInteractive",
"cbExitInteractive",
"cbInteractiveScopeChange",
"cbUnresolvedSystf",
"cbAssign",
"cbDeassign",
"cbDisable",
"cbPLIError",
"cbSignal",
"cbNBASynch",
"cbAtEndOfSimTime"
};
if (vpiVal < 0) return names[0];
return names[(vpiVal<=cbAtEndOfSimTime)?vpiVal:0];
}
const char* VerilatedVpiError::strFromVpiProp(PLI_INT32 vpiVal) {
static const char *names[] = {
"*undefined or other*",
"vpiType",
"vpiName",
"vpiFullName",
"vpiSize",
"vpiFile",
"vpiLineNo",
"vpiTopModule",
"vpiCellInstance",
"vpiDefName",
"vpiProtected",
"vpiTimeUnit",
"vpiTimePrecision",
"vpiDefNetType",
"vpiUnconnDrive",
"vpiDefFile",
"vpiDefLineNo",
"vpiScalar",
"vpiVector",
"vpiExplicitName",
"vpiDirection",
"vpiConnByName",
"vpiNetType",
"vpiExplicitScalared",
"vpiExplicitVectored",
"vpiExpanded",
"vpiImplicitDecl",
"vpiChargeStrength",
"vpiArray",
"vpiPortIndex",
"vpiTermIndex",
"vpiStrength0",
"vpiStrength1",
"vpiPrimType",
"vpiPolarity",
"vpiDataPolarity",
"vpiEdge",
"vpiPathType",
"vpiTchkType",
"vpiOpType",
"vpiConstType",
"vpiBlocking",
"vpiCaseType",
"vpiFuncType",
"vpiNetDeclAssign",
"vpiUserDefn",
"vpiScheduled",
"*undefined*",
"*undefined*",
"vpiActive",
"vpiAutomatic",
"vpiCell",
"vpiConfig",
"vpiConstantSelect",
"vpiDecompile",
"vpiDefAttribute",
"vpiDelayType",
"vpiIteratorType",
"vpiLibrary",
"*undefined*",
"vpiOffset",
"vpiResolvedNetType",
"vpiSaveRestartID",
"vpiSaveRestartLocation",
"vpiValid",
"vpiSigned",
"vpiStop",
"vpiFinish",
"vpiReset",
"vpiSetInteractiveScope",
"vpiLocalParam",
"vpiModPathHasIfNone",
"vpiIndexedPartSelectType",
"vpiIsMemory",
"vpiIsProtected"
};
if (vpiVal == vpiUndefined) {
return "vpiUndefined";
}
return names[(vpiVal<=vpiIsProtected)?vpiVal:0];
}
+613 -98
View File
File diff suppressed because it is too large Load Diff
+5 -5
View File
@@ -7,7 +7,7 @@
* This file contains the constant definitions, structure definitions,
* and routine declarations used by SystemVerilog DPI.
*
* This file is from the SystemVerilog IEEE 1800-2009 Annex I.
* This file is from the SystemVerilog IEEE 1800-2012 Annex I.
*/
#ifndef INCLUDED_SVDPI
@@ -35,18 +35,18 @@ typedef signed __int8 int8_t;
#include <sys/types.h>
#endif
/* Use to export a symbol from application */
/* Use to import a symbol into dll */
#ifndef DPI_DLLISPEC
#if defined (_MSC_VER)
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#define DPI_DLLISPEC __declspec(dllimport)
#else
#define DPI_DLLISPEC
#endif
#endif
/* Use to import a symbol into application */
/* Use to export a symbol from dll */
#ifndef DPI_DLLESPEC
#if defined (_MSC_VER)
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#define DPI_DLLESPEC __declspec(dllexport)
#else
#define DPI_DLLESPEC
+21 -21
View File
@@ -1,7 +1,7 @@
/*******************************************************************************
* vpi_user.h
*
* IEEE Std 1800 Programming Language Interface (PLI)
* IEEE Std 1800-2012 Programming Language Interface (PLI)
*
* This file contains the constant definitions, structure definitions, and
* routine declarations used by the SystemVerilog Verification Procedural
@@ -61,9 +61,9 @@ typedef char PLI_BYTE8;
typedef unsigned char PLI_UBYTE8;
#endif
/* Use to export a symbol */
/* Use to import a symbol */
#if WIN32
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#ifndef PLI_DLLISPEC
#define PLI_DLLISPEC __declspec(dllimport)
#define VPI_USER_DEFINED_DLLISPEC 1
@@ -74,9 +74,9 @@ typedef unsigned char PLI_UBYTE8;
#endif
#endif
/* Use to import a symbol */
/* Use to export a symbol */
#if WIN32
#if (defined(_MSC_VER) || defined(__MINGW32__) || defined(__CYGWIN__))
#ifndef PLI_DLLESPEC
#define PLI_DLLESPEC __declspec(dllexport)
#define VPI_USER_DEFINED_DLLESPEC 1
@@ -438,12 +438,12 @@ typedef PLI_UINT32 *vpiHandle;
#define vpiPlusOp 2 /* unary plus */
#define vpiNotOp 3 /* unary not */
#define vpiBitNegOp 4 /* bitwise negation */
#define vpiUnaryAndOp 5 /* bitwise reduction and */
#define vpiUnaryNandOp 6 /* bitwise reduction nand */
#define vpiUnaryOrOp 7 /* bitwise reduction or */
#define vpiUnaryNorOp 8 /* bitwise reduction nor */
#define vpiUnaryXorOp 9 /* bitwise reduction xor */
#define vpiUnaryXNorOp 10 /* bitwise reduction xnor */
#define vpiUnaryAndOp 5 /* bitwise reduction AND */
#define vpiUnaryNandOp 6 /* bitwise reduction NAND */
#define vpiUnaryOrOp 7 /* bitwise reduction OR */
#define vpiUnaryNorOp 8 /* bitwise reduction NOR */
#define vpiUnaryXorOp 9 /* bitwise reduction XOR */
#define vpiUnaryXNorOp 10 /* bitwise reduction XNOR */
#define vpiSubOp 11 /* binary subtraction */
#define vpiDivOp 12 /* binary division */
#define vpiModOp 13 /* binary modulus */
@@ -459,17 +459,17 @@ typedef PLI_UINT32 *vpiHandle;
#define vpiRShiftOp 23 /* binary right shift */
#define vpiAddOp 24 /* binary addition */
#define vpiMultOp 25 /* binary multiplication */
#define vpiLogAndOp 26 /* binary logical and */
#define vpiLogOrOp 27 /* binary logical or */
#define vpiBitAndOp 28 /* binary bitwise and */
#define vpiBitOrOp 29 /* binary bitwise or */
#define vpiBitXorOp 30 /* binary bitwise xor */
#define vpiBitXNorOp 31 /* binary bitwise xnor */
#define vpiLogAndOp 26 /* binary logical AND */
#define vpiLogOrOp 27 /* binary logical OR */
#define vpiBitAndOp 28 /* binary bitwise AND */
#define vpiBitOrOp 29 /* binary bitwise OR */
#define vpiBitXorOp 30 /* binary bitwise XOR */
#define vpiBitXNorOp 31 /* binary bitwise XNOR */
#define vpiBitXnorOp vpiBitXNorOp /* added with 1364-2001 */
#define vpiConditionOp 32 /* ternary conditional */
#define vpiConcatOp 33 /* n-ary concatenation */
#define vpiMultiConcatOp 34 /* repeated concatenation */
#define vpiEventOrOp 35 /* event or */
#define vpiEventOrOp 35 /* event OR */
#define vpiNullOp 36 /* null operation */
#define vpiListOp 37 /* list of expressions */
#define vpiMinTypMaxOp 38 /* min:typ:max: delay expression */
@@ -536,7 +536,7 @@ typedef PLI_UINT32 *vpiHandle;
same subtypes as vpiNetType */
#define vpiSaveRestartID 62 /* unique ID for save/restart data */
#define vpiSaveRestartLocation 63 /* name of save/restart data file */
/* vpiValid,vpiValidTrue,vpiValidFalse are deprecated in 1800-2009 */
/* vpiValid,vpiValidTrue,vpiValidFalse were deprecated in 1800-2009 */
#define vpiValid 64 /* reentrant task/func frame or automatic
variable is valid */
#define vpiValidFalse 0
@@ -661,7 +661,7 @@ typedef struct t_vpi_arrayvalue
{
PLI_INT32 *integers; /* integer values */
PLI_INT16 *shortints; /* short integer values */
PLI_INT16 *longints; /* long integer values */
PLI_INT64 *longints; /* long integer values */
PLI_BYTE8 *rawvals; /* 2/4-state vector elements */
struct t_vpi_vecval *vectors; /* 4-state vector elements */
struct t_vpi_time *times; /* time values */
@@ -944,7 +944,7 @@ XXTERN PLI_INT32 vpi_compare_objects PROTO_PARAMS((vpiHandle object1,
vpiHandle object2));
XXTERN PLI_INT32 vpi_chk_error PROTO_PARAMS((p_vpi_error_info
error_info_p));
/* vpi_free_object() is deprecated in 1800-2009 */
/* vpi_free_object() was deprecated in 1800-2009 */
XXTERN PLI_INT32 vpi_free_object PROTO_PARAMS((vpiHandle object));
XXTERN PLI_INT32 vpi_release_handle PROTO_PARAMS((vpiHandle object));
XXTERN PLI_INT32 vpi_get_vlog_info PROTO_PARAMS((p_vpi_vlog_info
+1
View File
@@ -62,6 +62,7 @@ private:
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
AstNode* timesp = nodep->fmtp()->exprsp(); if (timesp) timesp->unlinkFrBack();
// cppcheck-suppress nullPointer
timesp = timesp->addNext(new AstTime(nodep->fileline()));
nodep->fmtp()->exprsp(timesp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
+7 -3
View File
@@ -764,6 +764,7 @@ void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
while (nodep) {
AstNode* niterp = nodep; // This address may get stomped via m_iterpp if the node is edited
ASTNODE_PREFETCH(nodep->m_nextp);
// cppcheck-suppress nullPointer
niterp->m_iterpp = &niterp;
niterp->accept(v, vup);
// accept may do a replaceNode and change niterp on us...
@@ -1041,7 +1042,7 @@ void AstNode::v3errorEnd(ostringstream& str) const {
nsstr<<str.str();
if (debug()) {
nsstr<<endl;
nsstr<<"-node: "<<this<<endl;
nsstr<<"-node: "; ((AstNode*)this)->dump(nsstr); nsstr<<endl;
}
m_fileline->v3errorEnd(nsstr);
} else {
@@ -1067,8 +1068,7 @@ void AstNode::dtypeChgWidth(int width, int widthMin) {
dtypeChgWidthSigned(width, widthMin, dtypep()->numeric());
}
void AstNode::dtypeChgWidthSigned(int width, int widthMin, bool issigned) {
AstNumeric numeric = issigned ? AstNumeric::SIGNED : AstNumeric::UNSIGNED;
void AstNode::dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric) {
if (!dtypep()) {
// We allow dtypep() to be null, as before/during widthing dtypes are not resolved
dtypeSetLogicSized(width, widthMin, numeric);
@@ -1099,6 +1099,10 @@ AstNodeDType* AstNode::findLogicDType(int width, int widthMin, AstNumeric numeri
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, width, widthMin, numeric);
}
AstNodeDType* AstNode::findLogicRangeDType(VNumRange range, int widthMin, AstNumeric numeric) const {
return v3Global.rootp()->typeTablep()
->findLogicBitDType(fileline(), AstBasicDTypeKwd::LOGIC, range, widthMin, numeric);
}
AstBasicDType* AstNode::findInsertSameDType(AstBasicDType* nodep) {
return v3Global.rootp()->typeTablep()
->findInsertSameDType(nodep);
+102 -24
View File
@@ -47,6 +47,7 @@ public:
// enum en {...};
// const char* ascii() const {...};
enum en m_e;
// cppcheck-suppress uninitVar // responsiblity of each subclass
inline AstType () {}
inline AstType (en _e) : m_e(_e) {}
explicit inline AstType (int _e) : m_e(static_cast<en>(_e)) {}
@@ -219,7 +220,16 @@ class AstAttrType {
public:
enum en {
ILLEGAL,
EXPR_BITS, // V3Const converts to constant
//
DIM_BITS, // V3Const converts to constant
DIM_DIMENSIONS, // V3Width converts to constant
DIM_HIGH, // V3Width processes
DIM_INCREMENT, // V3Width processes
DIM_LEFT, // V3Width processes
DIM_LOW, // V3Width processes
DIM_RIGHT, // V3Width processes
DIM_SIZE, // V3Width processes
DIM_UNPK_DIMENSIONS, // V3Width converts to constant
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
@@ -237,7 +247,10 @@ public:
enum en m_e;
const char* ascii() const {
static const char* names[] = {
"%E-AT", "EXPR_BITS", "MEMBER_BASE",
"%E-AT",
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
"MEMBER_BASE",
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
"VAR_ISOLATE_ASSIGNMENTS", "VAR_SC_BV", "VAR_SFORMAT"
@@ -527,8 +540,8 @@ public:
// See also AstRange, which is a symbolic version of this
struct VNumRange {
int m_msb; // MSB, MSB always >= LSB
int m_lsb; // LSB
int m_hi; // HI part, HI always >= LO
int m_lo; // LO
union {
int mu_flags;
struct {
@@ -537,33 +550,38 @@ struct VNumRange {
};
};
inline bool operator== (const VNumRange& rhs) const {
return m_msb == rhs.m_msb
&& m_lsb == rhs.m_lsb
return m_hi == rhs.m_hi
&& m_lo == rhs.m_lo
&& mu_flags == rhs.mu_flags; }
inline bool operator< (const VNumRange& rhs) const {
if ( (m_msb < rhs.m_msb)) return true;
if (!(m_msb == rhs.m_msb)) return false; // lhs > rhs
if ( (m_lsb < rhs.m_lsb)) return true;
if (!(m_lsb == rhs.m_lsb)) return false; // lhs > rhs
if ( (m_hi < rhs.m_hi)) return true;
if (!(m_hi == rhs.m_hi)) return false; // lhs > rhs
if ( (m_lo < rhs.m_lo)) return true;
if (!(m_lo == rhs.m_lo)) return false; // lhs > rhs
if ( (mu_flags < rhs.mu_flags)) return true;
if (!(mu_flags == rhs.mu_flags)) return false; // lhs > rhs
return false;
}
//
VNumRange() : m_msb(0), m_lsb(0), mu_flags(0) {}
VNumRange() : m_hi(0), m_lo(0), mu_flags(0) {}
VNumRange(int hi, int lo, bool littleEndian)
: m_hi(0), m_lo(0), mu_flags(0)
{ init(hi,lo,littleEndian); }
~VNumRange() {}
// MEMBERS
void init(int msb, int lsb, bool littleEndian) {
m_msb=msb; m_lsb=lsb; mu_flags=0; m_ranged=true; m_littleEndian=littleEndian;
void init(int hi, int lo, bool littleEndian) {
m_hi=hi; m_lo=lo; mu_flags=0; m_ranged=true; m_littleEndian=littleEndian;
}
int msb() const { return m_msb; }
int lsb() const { return m_lsb; }
int left() const { return littleEndian()?lsb():msb(); } // How to show a declaration
int right() const { return littleEndian()?msb():lsb(); }
int hi() const { return m_hi; }
int lo() const { return m_lo; }
int left() const { return littleEndian()?lo():hi(); } // How to show a declaration
int right() const { return littleEndian()?hi():lo(); }
int elements() const { return hi()-lo()+1; }
bool ranged() const { return m_ranged; }
bool littleEndian() const { return m_littleEndian; }
int hiMaxSelect() const { return (lo()<0 ? hi()-lo() : hi()); } // Maximum value a [] select may index
bool representableByWidth() const // Could be represented by just width=1, or [width-1:0]
{ return (!m_ranged || (m_lsb==0 && m_msb>=1 && !m_littleEndian)); }
{ return (!m_ranged || (m_lo==0 && m_hi>=1 && !m_littleEndian)); }
};
//######################################################################
@@ -765,7 +783,7 @@ protected:
RelinkWhatEn m_chg;
AstNode** m_iterpp;
public:
AstNRelinker() { m_backp=NULL; m_chg=RELINK_BAD; m_iterpp=NULL;}
AstNRelinker() { m_oldp=NULL; m_backp=NULL; m_chg=RELINK_BAD; m_iterpp=NULL;}
void relink(AstNode* newp);
AstNode* oldp() const { return m_oldp; }
void dump(ostream& str=cout) const;
@@ -1057,7 +1075,7 @@ public:
void dtypeFrom(AstNode* fromp) { if (fromp) { dtypep(fromp->dtypep()); }}
void dtypeChgSigned(bool flag=true);
void dtypeChgWidth(int width, int widthMin);
void dtypeChgWidthSigned(int width, int widthMin, bool issigned);
void dtypeChgWidthSigned(int width, int widthMin, AstNumeric numeric);
void dtypeSetBitSized(int width, int widthMin, AstNumeric numeric) { dtypep(findBitDType(width,widthMin,numeric)); }
void dtypeSetLogicSized(int width, int widthMin, AstNumeric numeric) { dtypep(findLogicDType(width,widthMin,numeric)); }
void dtypeSetLogicBool() { dtypep(findLogicBoolDType()); }
@@ -1074,6 +1092,7 @@ public:
AstNodeDType* findUInt64DType() { return findBasicDType(AstBasicDTypeKwd::UINT64); } // Twostate
AstNodeDType* findBitDType(int width, int widthMin, AstNumeric numeric) const;
AstNodeDType* findLogicDType(int width, int widthMin, AstNumeric numeric) const;
AstNodeDType* findLogicRangeDType(VNumRange range, int widthMin, AstNumeric numeric) const;
AstNodeDType* findBasicDType(AstBasicDTypeKwd kwd) const;
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
@@ -1117,6 +1136,7 @@ public:
virtual bool isPure() const { return true; } // Else a $display, etc, that must be ordered with other displays
virtual bool isBrancher() const { return false; } // Changes control flow, disable some optimizations
virtual bool isGateOptimizable() const { return true; } // Else a AstTime etc that can't be pushed out
virtual bool isGateDedupable() const { return isGateOptimizable(); } // GateDedupable is a slightly larger superset of GateOptimzable (eg, AstNodeIf)
virtual bool isSubstOptimizable() const { return true; } // Else a AstTime etc that can't be substituted out
virtual bool isPredictOptimizable() const { return true; } // Else a AstTime etc which output can't be predicted from input
virtual bool isOutputter() const { return false; } // Else creates output or exits, etc, not unconsumed
@@ -1370,6 +1390,7 @@ public:
void addIfsp(AstNode* newp) { addOp2p(newp); }
void addElsesp(AstNode* newp) { addOp3p(newp); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isGateDedupable() const { return true; }
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
@@ -1498,7 +1519,7 @@ public:
//
// Changing the width may confuse the data type resolution, so must clear TypeTable cache after use.
void widthForce(int width, int sized) { m_width=width; m_widthMin=sized; }
// For backward compatibility AstArrayDType and others inherit width and signing from the subDType/base type
// For backward compatibility inherit width and signing from the subDType/base type
void widthFromSub(AstNodeDType* nodep) { m_width=nodep->m_width; m_widthMin=nodep->m_widthMin; m_numeric=nodep->m_numeric; }
//
int width() const { return m_width; }
@@ -1514,8 +1535,8 @@ public:
bool generic() const { return m_generic; }
void generic(bool flag) { m_generic = flag; }
AstNodeDType* dtypeDimensionp(int depth);
pair<uint32_t,uint32_t> dimensions();
uint32_t arrayElements(); // 1, or total multiplication of all dimensions
pair<uint32_t,uint32_t> dimensions(bool includeBasic);
uint32_t arrayUnpackedElements(); // 1, or total multiplication of all dimensions
static int uniqueNumInc() { return ++s_uniqueNum; }
};
@@ -1551,6 +1572,54 @@ public:
MemberNameMap::const_iterator it = m_members.find(name);
return (it==m_members.end()) ? NULL : it->second;
}
int lsb() const { return 0; }
int msb() const { return dtypep()->width()-1; } // Packed classes look like arrays
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
};
struct AstNodeArrayDType : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
private:
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
AstNode* rangenp() const { return op2p(); } // op2 = Array(s) of variable
public:
AstNodeArrayDType(FileLine* fl) : AstNodeDType(fl) {
m_refDTypep = NULL;
}
ASTNODE_BASE_FUNCS(NodeArrayDType)
virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str);
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
virtual bool same(AstNode* samep) const {
AstNodeArrayDType* sp = samep->castNodeArrayDType();
return (msb()==sp->msb()
&& subDTypep()==sp->subDTypep()
&& rangenp()->sameTree(sp->rangenp())); } // HashedDT doesn't recurse, so need to check children
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
AstRange* rangep() const { return op2p()->castRange(); } // op2 = Array(s) of variable
void rangep(AstRange* nodep);
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const;
int lsb() const;
int elementsConst() const;
VNumRange declRange() const;
};
struct AstNodeSel : public AstNodeBiop {
@@ -1684,13 +1753,14 @@ private:
bool m_modTrace:1; // Tracing this module
bool m_inLibrary:1; // From a library, no error if not used, never top level
bool m_dead:1; // LinkDot believes is dead; will remove in Dead visitors
bool m_internal:1; // Internally created
int m_level; // 1=top module, 2=cell off top module, ...
int m_varNum; // Incrementing variable number
public:
AstNodeModule(FileLine* fl, const string& name)
: AstNode (fl)
,m_name(name), m_origName(name)
,m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false)
,m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false), m_internal(false)
,m_level(0), m_varNum(0) { }
ASTNODE_BASE_FUNCS(NodeModule)
virtual void dump(ostream& str);
@@ -1717,6 +1787,8 @@ public:
bool modTrace() const { return m_modTrace; }
void dead(bool flag) { m_dead = flag; }
bool dead() const { return m_dead; }
void internal(bool flag) { m_internal = flag; }
bool internal() const { return m_internal; }
};
//######################################################################
@@ -1745,4 +1817,10 @@ inline bool AstNode::isAllOnesV() { return (this->castConst() && this->castConst
inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); }
inline void AstNodeArrayDType::rangep(AstRange* nodep) { setOp2p(nodep); }
inline int AstNodeArrayDType::msb() const { return rangep()->msbConst(); }
inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); }
#endif // Guard
+46 -36
View File
@@ -307,10 +307,12 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
// DECL: VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (DT RANGE3))))
// *or* VAR a (ARRAYSEL0 (ARRAYSEL1 (ARRAYSEL2 (ARRAYSEL3 (DT))))
// SEL1 needs to select from entire variable which is a pointer to ARRAYSEL0
// TODO this function should be removed in favor of recursing the dtype(),
// as that allows for more complicated data types.
int dim = 0;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
if ((dim++)==dimension) {
return dtypep;
}
@@ -340,11 +342,11 @@ AstNodeDType* AstNodeDType::dtypeDimensionp(int dimension) {
return NULL;
}
uint32_t AstNodeDType::arrayElements() {
uint32_t AstNodeDType::arrayUnpackedElements() {
uint32_t entries=1;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
if (AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType()) {
entries *= adtypep->elementsConst();
dtypep = adtypep->subDTypep();
}
@@ -356,21 +358,22 @@ uint32_t AstNodeDType::arrayElements() {
return entries;
}
pair<uint32_t,uint32_t> AstNodeDType::dimensions() {
pair<uint32_t,uint32_t> AstNodeDType::dimensions(bool includeBasic) {
// How many array dimensions (packed,unpacked) does this Var have?
uint32_t packed = 0;
uint32_t unpacked = 0;
for (AstNodeDType* dtypep=this; dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
if (adtypep->isPacked()) packed += 1;
else unpacked += 1;
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
if (adtypep->castPackArrayDType()) packed++;
else unpacked++;
dtypep = adtypep->subDTypep();
continue;
}
else {
// AstBasicDType - nothing below, 1
break;
else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
if (includeBasic && adtypep->isRanged()) packed++;
}
break;
}
return make_pair(packed, unpacked);
}
@@ -384,26 +387,12 @@ int AstNodeDType::widthPow2() const {
return 1;
}
// Special operators
int AstArraySel::dimension(AstNode* nodep) {
// How many dimensions is this reference from the base variable?
// nodep is typically the fromp() of a select; thus the first select
// is selecting from the entire variable type - effectively dimension 0.
// Dimension passed to AstVar::dtypeDimensionp; see comments there
int dim = 0;
while (nodep) {
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }
if (nodep->castNodePreSel()) { dim++; nodep=nodep->castNodePreSel()->fromp(); continue; }
break;
}
return dim;
}
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
// Else AstArraySel etc; search for the base
while (nodep) {
if (nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); continue; }
else if (nodep->castSel()) { nodep=nodep->castSel()->fromp(); continue; }
// AstNodeSelPre stashes the associated variable under a ATTROF of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
// AstNodeSelPre stashes the associated variable under an ATTROF of AstAttrType::VAR_BASE/MEMBER_BASE so it isn't constified
else if (nodep->castAttrOf()) { nodep=nodep->castAttrOf()->fromp(); continue; }
else if (nodep->castNodePreSel()) {
if (nodep->castNodePreSel()->attrp()) {
@@ -555,7 +544,7 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
LogicMap::const_iterator it = mapr.find(widths);
if (it != mapr.end()) return it->second;
//
AstBasicDType* new1p = new AstBasicDType(fl, AstBasicDTypeKwd::BIT, numeric, width, widthMin);
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, width, widthMin);
// Because the detailed map doesn't update this map,
// check the detailed map for this same node, and if found update this map
// Also adds this new node to the detailed map
@@ -567,6 +556,15 @@ AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kw
return newp;
}
AstBasicDType* AstTypeTable::findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
VNumRange range, int widthMin, AstNumeric numeric) {
AstBasicDType* new1p = new AstBasicDType(fl, kwd, numeric, range, widthMin);
AstBasicDType* newp = findInsertSameDType(new1p);
if (newp != new1p) new1p->deleteTree();
else addTypesp(newp);
return newp;
}
AstBasicDType* AstTypeTable::findInsertSameDType(AstBasicDType* nodep) {
VBasicTypeKey key (nodep->width(), nodep->widthMin(), nodep->numeric(),
nodep->keyword(), nodep->nrange());
@@ -667,10 +665,6 @@ void AstNode::dump(ostream& str) {
if (name()!="") str<<" "<<AstNode::quoteName(name());
}
void AstArrayDType::dump(ostream& str) {
this->AstNodeDType::dump(str);
if (isPacked()) str<<" [PACKED]";
}
void AstArraySel::dump(ostream& str) {
this->AstNode::dump(str);
str<<" [start:"<<start()<<"] [length:"<<length()<<"]";
@@ -701,18 +695,18 @@ void AstDisplay::dump(ostream& str) {
this->AstNode::dump(str);
//str<<" "<<displayType().ascii();
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstEnumItemRef::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
@@ -750,6 +744,15 @@ void AstNodeDType::dumpSmall(ostream& str) {
if (!widthSized()) str<<"/"<<widthMin();
str<<")";
}
void AstNodeArrayDType::dumpSmall(ostream& str) {
this->AstNodeDType::dumpSmall(str);
if (castPackArrayDType()) str<<"p"; else str<<"u";
str<<"["<<declRange().left()<<":"<<declRange().right()<<"]";
}
void AstNodeArrayDType::dump(ostream& str) {
this->AstNodeDType::dump(str);
str<<" ["<<declRange().left()<<":"<<declRange().right()<<"]";
}
void AstNodeModule::dump(ostream& str) {
this->AstNode::dump(str);
str<<" L"<<level();
@@ -761,6 +764,13 @@ void AstPackageImport::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> "<<packagep();
}
void AstSel::dump(ostream& str) {
this->AstNode::dump(str);
if (declRange().ranged()) {
str<<" decl["<<declRange().left()<<":"<<declRange().right()<<"]";
if (declElWidth()!=1) str<<"/"<<declElWidth();
}
}
void AstTypeTable::dump(ostream& str) {
this->AstNode::dump(str);
for (int i=0; i<(int)(AstBasicDTypeKwd::_ENUM_MAX); ++i) {
+165 -61
View File
@@ -65,6 +65,11 @@ public:
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { m_num.width(32,false); dtypeSetLogicSized(32,m_num.widthMin(),
AstNumeric::UNSIGNED); }
class Signed32 {}; // for creator type-overload selection
AstConst(FileLine* fl, Signed32, int32_t num) // Signed 32-bit integer of specified value
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { m_num.width(32,32); dtypeSetLogicSized(32,m_num.widthMin(),
AstNumeric::SIGNED); }
class RealDouble {}; // for creator type-overload selection
AstConst(FileLine* fl, RealDouble, double num)
:AstNodeMath(fl)
@@ -137,6 +142,11 @@ public:
m_littleEndian = false;
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
}
AstRange(FileLine* fl, VNumRange range)
:AstNode(fl) {
m_littleEndian = range.littleEndian();
setOp2p(new AstConst(fl,range.hi())); setOp3p(new AstConst(fl,range.lo()));
}
ASTNODE_NODE_FUNCS(Range, RANGE)
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
@@ -223,62 +233,54 @@ public:
void name(const string& flag) { m_name = flag; }
};
struct AstArrayDType : public AstNodeDType {
struct AstPackArrayDType : public AstNodeArrayDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
private:
AstNodeDType* m_refDTypep; // Elements of this type (after widthing)
bool m_packed;
public:
AstArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep, bool isPacked=false)
: AstNodeDType(fl), m_packed(isPacked) {
AstPackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
childDTypep(dtp); // Only for parser
refDTypep(NULL);
setOp2p(rangep);
dtypep(NULL); // V3Width will resolve
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
}
AstArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep, bool isPacked=false)
: AstNodeDType(fl), m_packed(isPacked) {
AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
refDTypep(dtp);
setOp2p(rangep);
dtypep(this);
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
}
ASTNODE_NODE_FUNCS(ArrayDType, ARRAYDTYPE)
virtual void dump(ostream& str);
virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
|| (!m_refDTypep && childDTypep())); }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
virtual bool same(AstNode* samep) const {
AstArrayDType* sp = samep->castArrayDType();
return (m_packed==sp->m_packed
&& msb()==sp->msb()
&& subDTypep()==sp->subDTypep()
&& rangep()->sameTree(sp->rangep())); } // HashedDT doesn't recurse, so need to check children
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m_refDTypep),V3Hash(msb()),V3Hash(lsb())); }
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Range of variable
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* subDTypep() const { return m_refDTypep ? m_refDTypep : childDTypep(); }
void refDTypep(AstNodeDType* nodep) { m_refDTypep = nodep; }
virtual AstNodeDType* virtRefDTypep() const { return m_refDTypep; }
virtual void virtRefDTypep(AstNodeDType* nodep) { refDTypep(nodep); }
AstRange* rangep() const { return op2p()->castRange(); } // op2 = Array(s) of variable
void rangep(AstRange* nodep) { setOp2p(nodep); }
// METHODS
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const { return rangep()->msbConst(); }
int lsb() const { return rangep()->lsbConst(); }
int elementsConst() const { return rangep()->elementsConst(); }
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
bool isPacked() const { return m_packed; }
ASTNODE_NODE_FUNCS(PackArrayDType, PACKARRAYDTYPE)
};
struct AstUnpackArrayDType : public AstNodeArrayDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
public:
AstUnpackArrayDType(FileLine* fl, VFlagChildDType, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
childDTypep(dtp); // Only for parser
refDTypep(NULL);
setOp2p(rangep);
dtypep(NULL); // V3Width will resolve
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
}
AstUnpackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
refDTypep(dtp);
setOp2p(rangep);
dtypep(this);
// For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
widthFromSub(subDTypep());
}
ASTNODE_NODE_FUNCS(UnpackArrayDType, UNPACKARRAYDTYPE)
};
struct AstBasicDType : public AstNodeDType {
@@ -310,6 +312,11 @@ public:
: AstNodeDType(fl) {
init(kwd, numer, wantwidth, widthmin, NULL);
}
AstBasicDType(FileLine* fl, AstBasicDTypeKwd kwd, AstNumeric numer, VNumRange range, int widthmin)
: AstNodeDType(fl) {
init(kwd, numer, range.elements(), widthmin, NULL);
m.m_nrange = range; // as init() presumes lsb==0, but range.lsb() might not be
}
// See also addRange in verilog.y
private:
void init(AstBasicDTypeKwd kwd, AstNumeric numer,
@@ -346,7 +353,7 @@ private:
public:
ASTNODE_NODE_FUNCS(BasicDType, BASICDTYPE)
virtual void dump(ostream& str);
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.msb())); }
virtual V3Hash sameHash() const { return V3Hash(V3Hash(m.m_keyword), V3Hash(m.m_nrange.hi())); }
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; }
virtual string name() const { return m.m_keyword.ascii(); }
@@ -371,13 +378,13 @@ public:
bool isZeroInit() const { return keyword().isZeroInit(); }
bool isRanged() const { return rangep() || m.m_nrange.ranged(); }
const VNumRange& nrange() const { return m.m_nrange; } // Generally the msb/lsb/etc funcs should be used instead
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.msb()); }
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lsb()); }
int msb() const { return (rangep() ? rangep()->msbConst() : m.m_nrange.hi()); }
int lsb() const { return (rangep() ? rangep()->lsbConst() : m.m_nrange.lo()); }
int left() const { return littleEndian()?lsb():msb(); } // How to show a declaration
int right() const { return littleEndian()?msb():lsb(); }
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
bool littleEndian() const { return (rangep() ? rangep()->littleEndian() : m.m_nrange.littleEndian()); }
bool implicit() const { return keyword() == AstBasicDTypeKwd::LOGIC_IMPLICIT; }
VNumRange declRange() const { return isRanged() ? VNumRange(msb(), lsb(), littleEndian()) : VNumRange(); }
void cvtRangeConst() { // Convert to smaller represenation
if (rangep() && rangep()->msbp()->castConst() && rangep()->lsbp()->castConst()) {
m.m_nrange.init(rangep()->msbConst(), rangep()->lsbConst(),
@@ -626,9 +633,9 @@ private:
unsigned m_start;
unsigned m_length;
void init(AstNode* fromp) {
if (fromp && fromp->dtypep()->castArrayDType()) {
if (fromp && fromp->dtypep()->castNodeArrayDType()) {
// Strip off array to find what array references
dtypeFrom(fromp->dtypep()->castArrayDType()->subDTypep());
dtypeFrom(fromp->dtypep()->castNodeArrayDType()->subDTypep());
}
}
public:
@@ -658,7 +665,6 @@ public:
void start(unsigned start) { m_start = start; }
unsigned start() const { return m_start; }
// Special operators
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
virtual void dump(ostream& str);
};
@@ -724,8 +730,15 @@ struct AstSel : public AstNodeTriop {
// Multiple bit range extraction
// Parents: math|stmt
// Children: varref|arraysel, math, constant math
// Tempting to have an lvalue() style method here as LHS selects are quite
// different, but that doesn't play well with V3Inst and bidirects which don't know direction
private:
VNumRange m_declRange; // Range of the 'from' array if isRanged() is set, else invalid
int m_declElWidth; // If a packed array, the number of bits per element
public:
AstSel(FileLine* fl, AstNode* fromp, AstNode* lsbp, AstNode* widthp)
:AstNodeTriop(fl, fromp, lsbp, widthp) {
m_declElWidth = 1;
if (widthp->castConst()) {
dtypeSetLogicSized(widthp->castConst()->toUInt(),
widthp->castConst()->toUInt(),
@@ -735,9 +748,11 @@ struct AstSel : public AstNodeTriop {
AstSel(FileLine* fl, AstNode* fromp, int lsb, int bitwidth)
:AstNodeTriop(fl, fromp,
new AstConst(fl,lsb), new AstConst(fl,bitwidth)) {
m_declElWidth = 1;
dtypeSetLogicSized(bitwidth,bitwidth,AstNumeric::UNSIGNED);
}
ASTNODE_NODE_FUNCS(Sel, SEL)
virtual void dump(ostream& str);
virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) {
out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); }
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
@@ -759,6 +774,10 @@ struct AstSel : public AstNodeTriop {
int widthConst() const { return widthp()->castConst()->toSInt(); }
int lsbConst() const { return lsbp()->castConst()->toSInt(); }
int msbConst() const { return lsbConst()+widthConst()-1; }
VNumRange& declRange() { return m_declRange; }
void declRange(const VNumRange& flag) { m_declRange = flag; }
int declElWidth() const { return m_declElWidth; }
void declElWidth(int flag) { m_declElWidth = flag; }
};
struct AstMemberSel : public AstNodeMath {
@@ -796,6 +815,7 @@ struct AstVar : public AstNode {
// A variable (in/out/wire/reg/param) inside a module
private:
string m_name; // Name of variable
string m_origName; // Original name before dot addition
AstVarType m_varType; // Type of variable
bool m_input:1; // Input or inout
bool m_output:1; // Output or inout
@@ -839,7 +859,7 @@ private:
public:
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagChildDType, AstNodeDType* dtp)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
childDTypep(dtp); // Only for parser
@@ -847,7 +867,7 @@ public:
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstNodeDType* dtp)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
UASSERT(dtp,"AstVar created with no dtype");
@@ -855,21 +875,21 @@ public:
}
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagLogicPacked, int wantwidth)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
}
AstVar(FileLine* fl, AstVarType type, const string& name, VFlagBitPacked, int wantwidth)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
dtypeSetLogicSized(wantwidth,wantwidth,AstNumeric::UNSIGNED);
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstVar* examplep)
:AstNode(fl)
, m_name(name) {
, m_name(name), m_origName(name) {
init();
combineType(type);
if (examplep->childDTypep()) {
@@ -879,10 +899,13 @@ public:
}
ASTNODE_NODE_FUNCS(Var, VAR)
virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Var name
virtual string name() const { return m_name; } // * = Var name
virtual bool hasDType() const { return true; }
virtual bool maybePointedTo() const { return true; }
AstVarType varType() const { return m_varType; } // * = Type of variable
string origName() const { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
AstVarType varType() const { return m_varType; } // * = Type of variable
void varType(AstVarType type) { m_varType = type; }
void varType2Out() { m_tristate=0; m_input=0; m_output=1; }
void varType2In() { m_tristate=0; m_input=1; m_output=0; }
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
@@ -1279,7 +1302,7 @@ private:
string m_name; // Cell name
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
public:
AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
@@ -1327,6 +1350,25 @@ public:
virtual void name(const string& name) { m_name = name; }
};
struct AstBind : public AstNode {
// Parents: MODULE
// Children: CELL
private:
string m_name; // Binding to name
public:
AstBind(FileLine* fl, const string& name, AstNode* cellsp)
: AstNode(fl)
, m_name(name) {
if (!cellsp->castCell()) cellsp->v3fatalSrc("Only cells allowed to be bound");
addNOp1p(cellsp);
}
ASTNODE_NODE_FUNCS(Bind, BIND)
// ACCESSORS
virtual string name() const { return m_name; } // * = Bind Target name
virtual void name(const string& name) { m_name = name; }
AstNode* cellsp() const { return op1p(); } // op1= cells
};
struct AstPort : public AstNode {
// A port (in/out/inout) on a module
private:
@@ -2519,6 +2561,33 @@ struct AstFinal : public AstNode {
AstNode* bodysp() const { return op1p()->castNode(); } // op1 = Expressions to evaluate
};
struct AstInside : public AstNodeMath {
AstInside(FileLine* fl, AstNode* exprp, AstNode* itemsp)
: AstNodeMath(fl) {
addOp1p(exprp); addOp2p(itemsp);
dtypeSetLogicBool();
}
ASTNODE_NODE_FUNCS(Inside, INSIDE)
AstNode* exprp() const { return op1p()->castNode(); } // op1 = LHS expression to compare with
AstNode* itemsp() const { return op2p()->castNode(); } // op2 = RHS, possibly a list of expr or AstInsideRange
virtual string emitVerilog() { return "%l inside { %r }"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() { return false; } // NA
};
struct AstInsideRange : public AstNodeMath {
AstInsideRange(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeMath(fl) {
addOp1p(lhsp); addOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(InsideRange, INSIDERANGE)
AstNode* lhsp() const { return op1p()->castNode(); } // op1 = LHS
AstNode* rhsp() const { return op2p()->castNode(); } // op2 = RHS
virtual string emitVerilog() { return "[%l:%r]"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() { return false; } // NA
};
struct AstInitArray : public AstNode {
// Set a var to a large list of values
// The values must be in sorted order, and not exceed the size of the var's array.
@@ -2600,11 +2669,11 @@ public:
, m_showname(showname) {
dtypeFrom(varp);
m_code = 0;
m_codeInc = varp->dtypep()->arrayElements() * varp->dtypep()->widthWords();
m_codeInc = varp->dtypep()->arrayUnpackedElements() * varp->dtypep()->widthWords();
AstBasicDType* bdtypep = varp->basicp();
m_left = bdtypep ? bdtypep->left() : 0;
m_right = bdtypep ? bdtypep->right() : 0;
if (AstArrayDType* adtypep = varp->dtypeSkipRefp()->castArrayDType()) {
if (AstUnpackArrayDType* adtypep = varp->dtypeSkipRefp()->castUnpackArrayDType()) {
m_arrayLsb = adtypep->lsb();
m_arrayMsb = adtypep->msb();
} else {
@@ -2708,12 +2777,14 @@ private:
// Return a value of a attribute, for example a LSB or array LSB of a signal
AstAttrType m_attrType; // What sort of extraction
public:
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL)
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL, AstNode* dimp=NULL)
: AstNode(fl) {
setNOp1p(fromp);
setNOp2p(dimp);
m_attrType = attrtype; }
ASTNODE_NODE_FUNCS(AttrOf, ATTROF)
AstNode* fromp() const { return op1p(); }
AstNode* dimp() const { return op2p(); }
AstAttrType attrType() const { return m_attrType; }
virtual void dump(ostream& str=cout);
};
@@ -3113,6 +3184,20 @@ struct AstCast : public AstNode {
AstNodeDType* childDTypep() const { return op2p()->castNodeDType(); }
};
struct AstCastSize : public AstNode {
// Cast to specific size; signed/twostate inherited from lower element per IEEE
AstCastSize(FileLine* fl, AstNode* lhsp, AstConst* rhsp) : AstNode(fl) {
setOp1p(lhsp); setOp2p(rhsp);
}
ASTNODE_NODE_FUNCS(CastSize, CASTSIZE)
virtual string emitVerilog() { return "((%r)'(%l))"; }
virtual string emitC() { V3ERROR_NA; return ""; }
virtual bool cleanOut() { V3ERROR_NA; return true;} virtual bool cleanLhs() {return true;}
virtual bool sizeMattersLhs() {return false;}
AstNode* lhsp() const { return op1p(); }
AstNode* rhsp() const { return op2p(); }
};
struct AstCCast : public AstNodeUniop {
// Cast to C-based data type
private:
@@ -3932,7 +4017,7 @@ struct AstPattern : public AstNodeMath {
// Parents: AstNodeAssign, AstPattern, ...
// Children: expression, AstPattern, AstPatReplicate
AstPattern(FileLine* fl, AstNode* itemsp) : AstNodeMath(fl) {
addNOp1p(itemsp);
addNOp2p(itemsp);
}
ASTNODE_NODE_FUNCS(Pattern, PATTERN)
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
@@ -3941,7 +4026,11 @@ struct AstPattern : public AstNodeMath {
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() {V3ERROR_NA; return "";}
virtual int instrCount() const { return widthInstrs(); }
AstNode* itemsp() const { return op1p(); } // op1 = AstPatReplicate, AstPatMember, etc
AstNodeDType* getChildDTypep() const { return childDTypep(); }
AstNodeDType* childDTypep() const { return op1p()->castNodeDType(); } // op1 = Type assigning to
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
AstNode* itemsp() const { return op2p(); } // op2 = AstPatReplicate, AstPatMember, etc
};
struct AstPatMember : public AstNodeMath {
// Verilog '{a} or '{a{b}}
@@ -4459,6 +4548,8 @@ public:
AstBasicDType* findBasicDType(FileLine* fl, AstBasicDTypeKwd kwd);
AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
int width, int widthMin, AstNumeric numeric);
AstBasicDType* findLogicBitDType(FileLine* fl, AstBasicDTypeKwd kwd,
VNumRange range, int widthMin, AstNumeric numeric);
AstBasicDType* findInsertSameDType(AstBasicDType* nodep);
void clearCache();
void repairCache();
@@ -4474,11 +4565,14 @@ struct AstNetlist : public AstNode {
// Children: MODULEs & CFILEs
private:
AstTypeTable* m_typeTablep; // Reference to top type table, for faster lookup
AstPackage* m_dollarUnitPkgp;
public:
AstNetlist() : AstNode(new FileLine("AstRoot",0)) {
m_typeTablep = NULL;
m_dollarUnitPkgp = NULL;
}
ASTNODE_NODE_FUNCS(Netlist, NETLIST)
virtual bool broken() const { return (m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); }
AstNodeModule* modulesp() const { return op1p()->castNodeModule();} // op1 = List of modules
AstNodeModule* topModulep() const { return op1p()->castNodeModule(); } // * = Top module in hierarchy (first one added, for now)
void addModulep(AstNodeModule* modulep) { addOp1p(modulep); }
@@ -4488,6 +4582,16 @@ public:
void addMiscsp(AstNode* nodep) { addOp3p(nodep); }
AstTypeTable* typeTablep() { return m_typeTablep; }
void addTypeTablep(AstTypeTable* nodep) { m_typeTablep = nodep; addMiscsp(nodep); }
AstPackage* dollarUnitPkgp() const { return m_dollarUnitPkgp; }
AstPackage* dollarUnitPkgAddp() {
if (!m_dollarUnitPkgp) {
m_dollarUnitPkgp = new AstPackage(fileline(), AstPackage::dollarUnitName());
m_dollarUnitPkgp->inLibrary(true); // packages are always libraries; don't want to make them a "top"
m_dollarUnitPkgp->modTrace(false); // may reconsider later
m_dollarUnitPkgp->internal(true);
addModulep(m_dollarUnitPkgp);
}
return m_dollarUnitPkgp; }
};
//######################################################################
+1 -1
View File
@@ -153,7 +153,7 @@ private:
AstNode* addsp = NULL;
if (AstNode* stmtsp = nodep->stmtsp()) {
stmtsp->unlinkFrBackWithNext();
addsp = addsp->addNextNull(stmtsp);
if (addsp) { addsp = addsp->addNextNull(stmtsp); } else { addsp = stmtsp; }
}
if (addsp) {
nodep->replaceWith(addsp);
+8 -7
View File
@@ -86,16 +86,17 @@ private:
#endif
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
AstArrayDType* arrayp = varp->dtypeSkipRefp()->castArrayDType();
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
bool isArray = arrayp;
int msb = isArray ? arrayp->msb() : 0;
int lsb = isArray ? arrayp->lsb() : 0;
if (isArray && ((msb - lsb + 1) > DETECTARRAY_MAX_INDEXES)) {
bool isStruct = structp && structp->packed();
int elements = isArray ? arrayp->elementsConst() : 1;
if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect more than "<<cvtToStr(DETECTARRAY_MAX_INDEXES)
<<" array indexes (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName()<<endl
<<vscp->warnMore()
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(msb-lsb+1));
} else if (!isArray
<<"... Could recompile with DETECTARRAY_MAX_INDEXES increased to at least "<<cvtToStr(elements));
} else if (!isArray && !isStruct
&& !varp->dtypeSkipRefp()->castBasicDType()) {
if (debug()) varp->dumpTree(cout,"-DETECTARRAY-");
vscp->v3warn(E_DETECTARRAY, "Unsupported: Can't detect changes on complex variable (probably with UNOPTFLAT warning suppressed): "<<varp->prettyName());
@@ -109,7 +110,7 @@ private:
m_topModp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopetopp, newvarp);
m_scopetopp->addVarp(newvscp);
for (int index=lsb; index<=msb; ++index) {
for (int index=0; index<elements; ++index) {
AstChangeDet* changep
= new AstChangeDet (vscp->fileline(),
aselIfNeeded(isArray, index,
+34 -26
View File
@@ -370,37 +370,40 @@ private:
// Extraction checks
bool warnSelect(AstSel* nodep) {
AstNode* basefromp = AstArraySel::baseFromp(nodep);
if (m_doGenerate) {
// Never checked yet
V3Width::widthParamsEdit(nodep);
nodep->iterateChildren(*this); // May need "constifying"
}
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
AstVar* varp = varrefp->varp();
if (!varp->dtypep()) varp->v3fatalSrc("Data type lost");
AstBasicDType* bdtypep = varp->basicp(); if (!bdtypep) varp->v3fatalSrc("Select of non-selectable type");
if (m_warn
&& nodep->lsbp()->castConst()
&& nodep->widthp()->castConst()
&& (!bdtypep->isRanged() || bdtypep->msb())) { // else it's non-resolvable parameterized
if (nodep->lsbp()->castConst()->num().isFourState()
|| nodep->widthp()->castConst()->num().isFourState()) {
nodep->v3error("Selection index is constantly unknown or tristated: "
"lsb="<<nodep->lsbp()->name()<<" width="<<nodep->widthp()->name());
// Replacing nodep will make a mess above, so we replace the offender
replaceZero(nodep->lsbp());
}
else if ((nodep->msbConst() > bdtypep->msbMaxSelect())
|| (nodep->lsbConst() > bdtypep->msbMaxSelect())) {
// See also warning in V3Width
nodep->v3warn(SELRANGE, "Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<bdtypep->msbMaxSelect()<<":0"
<<(bdtypep->lsb()>=0 ? ""
:" (adjusted +"+cvtToStr(-bdtypep->lsb())+" to account for negative lsb)"));
// Don't replace with zero, we'll do it later
}
// Find range of dtype we are selecting from
// Similar code in V3Unknown::AstSel
bool doit = true;
if (m_warn
&& nodep->lsbp()->castConst()
&& nodep->widthp()->castConst()
&& doit) {
int maxDeclBit = nodep->declRange().hiMaxSelect()*nodep->declElWidth() + (nodep->declElWidth()-1);
if (nodep->lsbp()->castConst()->num().isFourState()
|| nodep->widthp()->castConst()->num().isFourState()) {
nodep->v3error("Selection index is constantly unknown or tristated: "
"lsb="<<nodep->lsbp()->name()<<" width="<<nodep->widthp()->name());
// Replacing nodep will make a mess above, so we replace the offender
replaceZero(nodep->lsbp());
}
else if (nodep->declRange().ranged()
&& (nodep->msbConst() > maxDeclBit
|| nodep->lsbConst() > maxDeclBit)) {
// See also warning in V3Width
// Must adjust by element width as declRange() is in number of elements
nodep->v3warn(SELRANGE, "Selection index out of range: "
<<(nodep->msbConst()/nodep->declElWidth())
<<":"<<(nodep->lsbConst()/nodep->declElWidth())
<<" outside "<<nodep->declRange().hiMaxSelect()<<":0"
<<(nodep->declRange().lo()>=0 ? ""
:(" (adjusted +"+cvtToStr(-nodep->declRange().lo())
+" to account for negative lsb)")));
UINFO(1," Related Raw index is "<<nodep->msbConst()<<":"<<nodep->lsbConst()<<endl);
// Don't replace with zero, we'll do it later
}
}
return false; // Not a transform, so NOP
@@ -1270,6 +1273,7 @@ private:
nodep->iterateChildren(*this);
if (m_doNConst
&& (nodep->sensp()->castConst()
|| nodep->sensp()->castEnumItemRef()
|| (nodep->varrefp() && nodep->varrefp()->varp()->isParam()))) {
// Constants in sensitivity lists may be removed (we'll simplify later)
if (nodep->isClocked()) { // A constant can never get a pos/negexge
@@ -1298,6 +1302,9 @@ private:
if (!senvarp) sensp->v3fatalSrc("Non-varref sensitivity variable");
sensp->replaceWith(senvarp);
sensp->deleteTree(); sensp=NULL;
} else if (!m_doNConst // Deal with later when doNConst missing
&& (nodep->sensp()->castEnumItemRef()
|| nodep->sensp()->castConst())) {
} else {
if (nodep->hasVar() && !nodep->varrefp()) nodep->v3fatalSrc("Null sensitivity variable");
}
@@ -1397,6 +1404,7 @@ private:
for (AstNodeSenItem* nextp, * senp = nodep->sensesp()->castNodeSenItem();
senp; senp=nextp) {
nextp=senp->nextp()->castNodeSenItem();
// cppcheck-suppress unassignedVariable // cppcheck bug
SenItemCmp cmp;
if (nextp && !cmp(senp, nextp)) {
// Something's out of order, sort it
+2 -2
View File
@@ -86,7 +86,7 @@ private:
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
}
if ((nodep->width()*nodep->dtypep()->arrayElements()) > 256) return "Wide bus/array > 256 bits";
if ((nodep->width()*nodep->dtypep()->arrayUnpackedElements()) > 256) return "Wide bus/array > 256 bits";
// We allow this, though tracing doesn't
// if (nodep->arrayp(1)) return "Unsupported: Multi-dimensional array";
return NULL;
@@ -209,7 +209,7 @@ private:
varp, chgVarp);
}
}
else if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
else if (AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType()) {
for (int index_docs=adtypep->lsb(); index_docs<=adtypep->msb()+1; ++index_docs) {
int index_code = index_docs - adtypep->lsb();
ToggleEnt newent (above.m_comment+string("[")+cvtToStr(index_docs)+"]",
+1 -1
View File
@@ -206,7 +206,7 @@ private:
AstNodeModule* nextmodp;
for (AstNodeModule* modp = v3Global.rootp()->modulesp(); modp; modp=nextmodp) {
nextmodp = modp->nextp()->castNodeModule();
if (modp->level()>2 && modp->user1()==0) {
if (modp->level()>2 && modp->user1()==0 && !modp->internal()) {
// > 2 because L1 is the wrapper, L2 is the top user module
UINFO(4," Dead module "<<modp<<endl);
// And its children may now be killable too; correct counts
+33 -33
View File
@@ -321,12 +321,12 @@ public:
{
AstVarRef* varrefp = nodep->memp()->castVarRef();
if (!varrefp) { nodep->v3error("Readmem loading non-variable"); }
else if (AstArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castArrayDType()) {
puts(cvtToStr(varrefp->varp()->dtypep()->arrayElements()));
else if (AstUnpackArrayDType* adtypep = varrefp->varp()->dtypeSkipRefp()->castUnpackArrayDType()) {
puts(cvtToStr(varrefp->varp()->dtypep()->arrayUnpackedElements()));
array_lsb = adtypep->lsb();
}
else {
nodep->v3error("Readmem loading non-arrayed variable");
nodep->v3error("Readmem loading other than unpacked-array variable");
}
}
putbs(", ");
@@ -889,8 +889,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
puts(nodep->name());
if (isArray) {
for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
}
@@ -910,8 +910,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (isArray) {
if (nodep->isWide()) puts("W");
puts("("+nodep->name());
for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(","+cvtToStr(basicp->msb())+","+cvtToStr(basicp->lsb()));
@@ -932,8 +932,8 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
// strings and other fundamental c types
puts(nodep->vlArgType(true,false));
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(";\n");
@@ -958,12 +958,13 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=nodep->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
puts("["+cvtToStr(arrayp->elementsConst())+"]");
}
puts(","+cvtToStr(basicp->msb())+","+cvtToStr(basicp->lsb()));
if (basicp->isWide()) puts(","+cvtToStr(basicp->widthWords()));
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
puts(","+cvtToStr(basicp->lsb()+nodep->width())+","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
}
@@ -1328,7 +1329,7 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
}
else if (AstInitArray* initarp = varp->valuep()->castInitArray()) {
AstConst* constsp = initarp->initsp()->castConst();
if (AstArrayDType* arrayp = varp->dtypeSkipRefp()->castArrayDType()) {
if (AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType()) {
for (int i=0; i<arrayp->elementsConst(); i++) {
if (!constsp) initarp->v3fatalSrc("Not enough values in array initalizement");
emitSetVarConstant(varp->name()+"["+cvtToStr(i)+"]", constsp);
@@ -1341,8 +1342,8 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
else {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=varp->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
@@ -1367,17 +1368,16 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
} else {
puts(varp->name());
for (int v=0; v<vects; ++v) puts( "[__Vi"+cvtToStr(v)+"]");
if (zeroit) {
// We want to force an initial edge on uninitialized clocks (from 'X' to
// whatever the first value is). Since the class is instantiated before
// initial blocks are evaluated, this should not clash with any initial
// block settings. Clocks are always BIT datatypes, so zeroit is true.
if (v3Global.opt.xInitialEdge()
&& (0 == varp->name().find("__Vclklast__"))) {
puts(" = 1;\n");
} else {
puts(" = 0;\n");
}
// If --x-initial-edge is set, we want to force an initial
// edge on uninitialized clocks (from 'X' to whatever the
// first value is). Since the class is instantiated before
// initial blocks are evaluated, this should not clash
// with any initial block settings.
if (zeroit || (v3Global.opt.xInitialEdge() && varp->isUsedClock())) {
puts(" = 0;\n");
} else if (v3Global.opt.xInitialEdge()
&& (0 == varp->name().find("__Vclklast__"))) {
puts(" = 1;\n");
} else {
puts(" = VL_RAND_RESET_");
emitIQW(varp);
@@ -1508,8 +1508,8 @@ void EmitCImp::emitSavableImp(AstNodeModule* modp) {
else {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=varp->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
@@ -1599,8 +1599,8 @@ void EmitCImp::emitSensitives() {
if (varp->isInput() && (varp->isScSensitive() || varp->isUsedClock())) {
int vects = 0;
// This isn't very robust and may need cleanup for other data types
for (AstArrayDType* arrayp=varp->dtypeSkipRefp()->castArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castArrayDType()) {
for (AstUnpackArrayDType* arrayp=varp->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
int vecnum = vects++;
if (arrayp->msb() < arrayp->lsb()) varp->v3fatalSrc("Should have swapped msb & lsb earlier.");
string ivar = string("__Vi")+cvtToStr(vecnum);
@@ -1697,7 +1697,7 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
int sigbytes = varp->dtypeSkipRefp()->widthAlignBytes();
int sortbytes = sortmax-1;
if (varp->isUsedClock() && varp->widthMin()==1) sortbytes = 0;
else if (varp->dtypeSkipRefp()->castArrayDType()) sortbytes=8;
else if (varp->dtypeSkipRefp()->castUnpackArrayDType()) sortbytes=8;
else if (varp->basicp() && varp->basicp()->isOpaque()) sortbytes=7;
else if (varp->isScBv()) sortbytes=6;
else if (sigbytes==8) sortbytes=5;
@@ -2234,7 +2234,7 @@ class EmitCTrace : EmitCStmts {
if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
varrefp->iterate(*this); // Put var name out
// Tracing only supports 1D arrays
if (varp->dtypeSkipRefp()->castArrayDType()) {
if (varp->dtypeSkipRefp()->castUnpackArrayDType()) {
if (arrayindex==-2) puts("[i]");
else if (arrayindex==-1) puts("[0]");
else puts("["+cvtToStr(arrayindex)+"]");
+8 -7
View File
@@ -454,29 +454,30 @@ void EmitCSyms::emitSymImp() {
AstScope* scopep = it->second.m_scopep;
AstVar* varp = it->second.m_varp;
//
int dim=0;
int pdim=0;
int udim=0;
string bounds;
if (AstBasicDType* basicp = varp->basicp()) {
// Range is always first, it's not in "C" order
if (basicp->isRanged()) {
bounds += " ,"; bounds += cvtToStr(basicp->msb());
bounds += ","; bounds += cvtToStr(basicp->lsb());
dim++;
pdim++;
}
for (AstNodeDType* dtypep=varp->dtypep(); dtypep; ) {
dtypep = dtypep->skipRefp(); // Skip AstRefDType/AstTypedef, or return same node
if (AstArrayDType* adtypep = dtypep->castArrayDType()) {
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
bounds += " ,"; bounds += cvtToStr(adtypep->msb());
bounds += ","; bounds += cvtToStr(adtypep->lsb());
dim++;
if (dtypep->castPackArrayDType()) pdim++; else udim++;
dtypep = adtypep->subDTypep();
}
else break; // AstBasicDType - nothing below, 1
}
}
//
if (dim>2) {
puts("//UNSUP "); // VerilatedImp can't deal with >2d arrays
if (pdim>1 || udim>1) {
puts("//UNSUP "); // VerilatedImp can't deal with >2d or packed arrays
}
puts("__Vscope_"+it->second.m_scopeName+".varInsert(__Vfinal,");
putsQuoted(it->second.m_varBasePretty);
@@ -496,7 +497,7 @@ void EmitCSyms::emitSymImp() {
if (varp->isSigUserRWPublic()) puts("|VLVF_PUB_RW");
else if (varp->isSigUserRdPublic()) puts("|VLVF_PUB_RD");
puts(",");
puts(cvtToStr(dim));
puts(cvtToStr(pdim+udim));
puts(bounds);
puts(");\n");
}
+8 -4
View File
@@ -440,6 +440,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstAttrOf* nodep, AstNUser*) {
putfs(nodep,"$_ATTROF(");
nodep->fromp()->iterateAndNext(*this);
if (nodep->dimp()) {
putbs(",");
nodep->dimp()->iterateAndNext(*this);
}
puts(")");
}
virtual void visit(AstNodeCond* nodep, AstNUser*) {
@@ -495,10 +499,10 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstConstDType* nodep, AstNUser*) {
putfs(nodep,"const ");
nodep->subDTypep()->iterateAndNext(*this);
nodep->subDTypep()->accept(*this);
}
virtual void visit(AstArrayDType* nodep, AstNUser*) {
nodep->subDTypep()->iterateAndNext(*this);
virtual void visit(AstNodeArrayDType* nodep, AstNUser*) {
nodep->subDTypep()->accept(*this);
nodep->rangep()->iterateAndNext(*this);
}
virtual void visit(AstNodeClassDType* nodep, AstNUser*) {
@@ -509,7 +513,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts("}");
}
virtual void visit(AstMemberDType* nodep, AstNUser*) {
nodep->subDTypep()->iterateAndNext(*this);
nodep->subDTypep()->accept(*this);
puts(" ");
puts(nodep->name());
puts("}");
+1 -1
View File
@@ -294,7 +294,7 @@ protected:
int nameToNumber(const string& filename);
const string numberToName(int filenameno) const { return m_names[filenameno]; }
const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
void numberToLang(int filenameno, const V3LangCode l) { m_languages[filenameno] = l; }
void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
void fileNameNumMapDumpXml(ostream& os);
static const string filenameLetters(int fileno);
+1 -3
View File
@@ -162,13 +162,11 @@ inline void V3FileDependImp::writeTimes(const string& filename, const string& cm
*ofp<<"# DESCR"<<"IPTION: Verilator output: Timestamp data for --skip-identical. Delete at will."<<endl;
*ofp<<"C \""<<cmdline<<"\""<<endl;
#ifndef _WIN32
sync(); // Push files so sizes look correct
#endif
for (set<DependFile>::iterator iter=m_filenameList.begin();
iter!=m_filenameList.end(); ++iter) {
// Read stats of files we create after we're done making them (execpt for this file, of course)
DependFile* dfp = (DependFile*)&(*iter);
V3Options::fileNfsFlush(dfp->filename());
dfp->loadStats();
off_t showSize = iter->size();
if (dfp->filename() == filename) showSize=0; // We're writing it, so need to ignore it
+319 -19
View File
@@ -41,6 +41,7 @@
#include "V3Graph.h"
#include "V3Const.h"
#include "V3Stats.h"
#include "V3Hashed.h"
typedef list<AstNodeVarRef*> GateVarRefList;
@@ -55,21 +56,33 @@ public:
}
};
//######################################################################
class GateLogicVertex;
class GateVarVertex;
class GateGraphBaseVisitor {
public:
virtual AstNUser* visit(GateLogicVertex* vertexp, AstNUser* vup=NULL) =0;
virtual AstNUser* visit(GateVarVertex* vertexp, AstNUser* vup=NULL) =0;
};
//######################################################################
// Support classes
class GateEitherVertex : public V3GraphVertex {
AstScope* m_scopep;
bool m_reducible; // True if this node should be able to be eliminated
bool m_dedupable; // True if this node should be able to be deduped
bool m_consumed; // Output goes to something meaningful
public:
GateEitherVertex(V3Graph* graphp, AstScope* scopep)
: V3GraphVertex(graphp), m_scopep(scopep), m_reducible(true), m_consumed(false) {}
: V3GraphVertex(graphp), m_scopep(scopep), m_reducible(true), m_dedupable(true), m_consumed(false) {}
virtual ~GateEitherVertex() {}
// Accessors
// ACCESSORS
virtual string dotStyle() const { return m_consumed?"":"dotted"; }
AstScope* scopep() const { return m_scopep; }
bool reducible() const { return m_reducible; }
bool dedupable() const { return m_dedupable; }
void setConsumed(const char* consumedReason) {
m_consumed = true;
//UINFO(0,"\t\tSetConsumed "<<consumedReason<<" "<<this<<endl);
@@ -79,6 +92,23 @@ public:
m_reducible = false;
//UINFO(0," NR: "<<nonReducibleReason<<" "<<name()<<endl);
}
void clearDedupable(const char* nonDedupableReason) {
m_dedupable = false;
//UINFO(0," ND: "<<nonDedupableReason<<" "<<name()<<endl);
}
void clearReducibleAndDedupable(const char* nonReducibleReason) {
clearReducible(nonReducibleReason);
clearDedupable(nonReducibleReason);
}
virtual AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) =0;
// Returns only the result from the LAST vertex iterated over
AstNUser* iterateInEdges(GateGraphBaseVisitor& v, AstNUser* vup=NULL) {
AstNUser* retp = NULL;
for (V3GraphEdge* edgep = inBeginp(); edgep; edgep = edgep->inNextp()) {
retp = dynamic_cast<GateEitherVertex*>(edgep->fromp())->accept(v, vup);
}
return retp;
}
};
class GateVarVertex : public GateEitherVertex {
@@ -92,7 +122,7 @@ public:
: GateEitherVertex(graphp, scopep), m_varScp(varScp), m_isTop(false)
, m_isClock(false), m_rstSyncNodep(NULL), m_rstAsyncNodep(NULL) {}
virtual ~GateVarVertex() {}
// Accessors
// ACCESSORS
AstVarScope* varScp() const { return m_varScp; }
virtual string name() const { return (cvtToStr((void*)m_varScp)+" "+varScp()->name()); }
virtual string dotColor() const { return "blue"; }
@@ -104,6 +134,16 @@ public:
void rstSyncNodep(AstNode* nodep) { m_rstSyncNodep=nodep; }
AstNode* rstAsyncNodep() const { return m_rstAsyncNodep; }
void rstAsyncNodep(AstNode* nodep) { m_rstAsyncNodep=nodep; }
// METHODS
void propagateAttrClocksFrom(GateVarVertex* fromp) {
// Propagate clock and general attribute onto this node
varScp()->varp()->propagateAttrFrom(fromp->varScp()->varp());
if (fromp->isClock()) {
varScp()->varp()->usedClock(true);
setIsClock();
}
}
AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) { return v.visit(this,vup); }
};
class GateLogicVertex : public GateEitherVertex {
@@ -114,12 +154,13 @@ public:
GateLogicVertex(V3Graph* graphp, AstScope* scopep, AstNode* nodep, AstActive* activep, bool slow)
: GateEitherVertex(graphp,scopep), m_nodep(nodep), m_activep(activep), m_slow(slow) {}
virtual ~GateLogicVertex() {}
// Accessors
// ACCESSORS
virtual string name() const { return (cvtToStr((void*)m_nodep)+"@"+scopep()->prettyName()); }
virtual string dotColor() const { return "yellow"; }
AstNode* nodep() const { return m_nodep; }
AstActive* activep() const { return m_activep; }
bool slow() const { return m_slow; }
AstNUser* accept(GateGraphBaseVisitor& v, AstNUser* vup=NULL) { return v.visit(this,vup); }
};
//######################################################################
@@ -134,6 +175,7 @@ private:
// STATE
bool m_buffersOnly; // Set when we only allow simple buffering, no equations (for clocks)
AstNodeVarRef* m_lhsVarRef; // VarRef on lhs of assignment (what we're replacing)
bool m_dedupe; // Set when we use isGateDedupable instead of isGateOptimizable
// METHODS
void clearSimple(const char* because) {
@@ -193,7 +235,7 @@ private:
virtual void visit(AstNode* nodep, AstNUser*) {
// *** Special iterator
if (!m_isSimple) return; // Fastpath
if (!nodep->isGateOptimizable()
if (!(m_dedupe ? nodep->isGateDedupable() : nodep->isGateOptimizable())
|| !nodep->isPure()
|| nodep->isBrancher()) {
UINFO(5, "Non optimizable type: "<<nodep<<endl);
@@ -203,11 +245,12 @@ private:
}
public:
// CONSTUCTORS
GateOkVisitor(AstNode* nodep, bool buffersOnly) {
GateOkVisitor(AstNode* nodep, bool buffersOnly, bool dedupe) {
m_isSimple = true;
m_substTreep = NULL;
m_buffersOnly = buffersOnly;
m_lhsVarRef = NULL;
m_dedupe = dedupe;
// Iterate
nodep->accept(*this);
// Check results
@@ -258,6 +301,7 @@ private:
bool m_inSlow; // Inside a slow structure
V3Double0 m_statSigs; // Statistic tracking
V3Double0 m_statRefs; // Statistic tracking
V3Double0 m_statDedupLogic; // Statistic tracking
// METHODS
void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) {
@@ -265,9 +309,10 @@ private:
UINFO(4," STMT "<<nodep<<endl);
// m_activep is null under AstCFunc's, that's ok.
m_logicVertexp = new GateLogicVertex(&m_graph, m_scopep, nodep, m_activep, m_inSlow);
if (!m_activeReducible) nonReducibleReason="Block Unreducible";
if (nonReducibleReason) {
m_logicVertexp->clearReducible(nonReducibleReason);
m_logicVertexp->clearReducibleAndDedupable(nonReducibleReason);
} else if (!m_activeReducible) {
m_logicVertexp->clearReducible("Block Unreducible"); // Sequential logic is dedupable
}
if (consumeReason) m_logicVertexp->setConsumed(consumeReason);
if (nodep->castSenItem()) m_logicVertexp->setConsumed("senItem");
@@ -284,13 +329,13 @@ private:
varscp->user1p(vertexp);
if (varscp->varp()->isSigPublic()) {
// Public signals shouldn't be changed, pli code might be messing with them
vertexp->clearReducible("SigPublic");
vertexp->clearReducibleAndDedupable("SigPublic");
vertexp->setConsumed("SigPublic");
}
if (varscp->varp()->isIO() && varscp->scopep()->isTop()) {
// We may need to convert to/from sysc/reg sigs
vertexp->setIsTop();
vertexp->clearReducible("isTop");
vertexp->clearReducibleAndDedupable("isTop");
vertexp->setConsumed("isTop");
}
if (varscp->varp()->isUsedClock()) vertexp->setConsumed("clock");
@@ -305,6 +350,7 @@ private:
void consumedMarkRecurse(GateEitherVertex* vertexp);
void consumedMove();
void replaceAssigns();
void dedupe();
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -319,6 +365,8 @@ private:
optimizeSignals(false);
// Then propagate more complicated equations
optimizeSignals(true);
// Remove redundant logic
if (v3Global.opt.oDedupe()) dedupe();
// Warn
warnSignals();
consumedMark();
@@ -443,6 +491,7 @@ private:
public:
// CONSTUCTORS
GateVisitor(AstNode* nodep) {
AstNode::user1ClearTree();
m_logicVertexp = NULL;
m_scopep = NULL;
m_modp = NULL;
@@ -455,6 +504,7 @@ public:
virtual ~GateVisitor() {
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
}
};
@@ -464,7 +514,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->inEmpty()) {
vvertexp->clearReducible("inEmpty"); // Can't deal with no sources
vvertexp->clearReducibleAndDedupable("inEmpty"); // Can't deal with no sources
if (!vvertexp->isTop() // Ok if top inputs are driverless
&& !vvertexp->varScp()->varp()->valuep()
&& !vvertexp->varScp()->varp()->isSigPublic()) {
@@ -480,7 +530,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
}
}
else if (!vvertexp->inSize1()) {
vvertexp->clearReducible("size!1"); // Can't deal with more than one src
vvertexp->clearReducibleAndDedupable("size!1"); // Can't deal with more than one src
}
// Reduce it?
if (!vvertexp->reducible()) {
@@ -493,7 +543,7 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
AstNode* logicp = logicVertexp->nodep();
if (logicVertexp->reducible()) {
// Can we eliminate?
GateOkVisitor okVisitor(logicp, vvertexp->isClock());
GateOkVisitor okVisitor(logicp, vvertexp->isClock(), false);
bool multiInputs = okVisitor.rhsVarRefs().size() > 1;
// Was it ok?
bool doit = okVisitor.isSimple();
@@ -548,12 +598,8 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
UINFO(9," Point-to-new vertex "<<newvarscp<<endl);
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
new V3GraphEdge(&m_graph, varvertexp, consumeVertexp, 1);
newvarscp->varp()->propagateAttrFrom(vvertexp->varScp()->varp());
if (vvertexp->isClock()) {
// Propagate clock attribute onto generating node
newvarscp->varp()->usedClock(true);
varvertexp->setIsClock();
}
// Propagate clock attribute onto generating node
varvertexp->propagateAttrClocksFrom(vvertexp);
}
// Remove the edge
edgep->unlinkDelete(); edgep=NULL;
@@ -725,6 +771,8 @@ private:
// However a VARREF should point to the original as it's otherwise confusing
// to throw warnings that point to a PIN rather than where the pin us used.
if (substp->castVarRef()) substp->fileline(nodep->fileline());
// Make the substp an rvalue like nodep. This facilitate the hashing in dedupe.
if (AstNodeVarRef* varrefp = substp->castNodeVarRef()) varrefp->lvalue(false);
nodep->replaceWith(substp);
nodep->deleteTree(); nodep=NULL;
}
@@ -756,6 +804,258 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
}
}
//######################################################################
// Auxiliary hash class for GateDedupeVarVisitor
class GateDedupeHash : public V3HashedUserCheck {
private:
// NODE STATE
// Ast*::user2p -> parent AstNodeAssign* for this rhsp
// Ast*::user3p -> AstNode* checked in test for duplicate
// Ast*::user5p -> AstNode* checked in test for duplicate
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
AstUser3InUse m_inuser3;
AstUser5InUse m_inuser5;
V3Hashed m_hashed; // Hash, contains rhs of assigns
void hash(AstNode* nodep) {
// !NULL && the object is hashable
if (nodep && !nodep->sameHash().isIllegal()) {
m_hashed.hash(nodep);
}
}
bool sameHash(AstNode* node1p, AstNode* node2p) {
return (node1p && node2p
&& !node1p->sameHash().isIllegal()
&& !node2p->sameHash().isIllegal()
&& m_hashed.sameNodes(node1p,node2p));
}
bool same(AstNUser* node1p, AstNUser* node2p) {
return node1p == node2p || sameHash((AstNode*)node1p,(AstNode*)node2p);
}
public:
bool check(AstNode* node1p,AstNode* node2p) {
return same(node1p->user3p(),node2p->user3p()) && same(node1p->user5p(),node2p->user5p())
&& node1p->user2p()->castNode()->type() == node2p->user2p()->castNode()->type()
;
}
AstNodeAssign* hashAndFindDupe(AstNodeAssign* assignp, AstNode* extra1p, AstNode* extra2p) {
AstNode *rhsp = assignp->rhsp();
rhsp->user2p(assignp);
rhsp->user3p(extra1p);
rhsp->user5p(extra2p);
hash(extra1p);
hash(extra2p);
V3Hashed::iterator inserted = m_hashed.hashAndInsert(rhsp);
V3Hashed::iterator dupit = m_hashed.findDuplicate(rhsp, this);
// Even though rhsp was just inserted, V3Hashed::findDuplicate doesn't
// return anything in the hash that has the same pointer (V3Hashed.cpp::findDuplicate)
// So dupit is either a different, duplicate rhsp, or the end of the hash.
if (dupit != m_hashed.end()) {
m_hashed.erase(inserted);
return m_hashed.iteratorNodep(dupit)->user2p()->castNode()->castNodeAssign();
}
return NULL;
}
};
//######################################################################
// Have we seen the rhs of this assign before?
class GateDedupeVarVisitor : public GateBaseVisitor {
// Given a node, it is visited to try to find the AstNodeAssign under it that can used for dedupe.
// Right now, only the following node trees are supported for dedupe.
// 1. AstNodeAssign
// 2. AstAlways -> AstNodeAssign
// (Note, the assign must also be the only node under the always)
// 3. AstAlways -> AstNodeIf -> AstNodeAssign
// (Note, the IF must be the only node under the always,
// and the assign must be the only node under the if, other than the ifcond)
// Any other ordering or node type, except for an AstComment, makes it not dedupable
private:
// STATE
GateDedupeHash m_hash; // Hash used to find dupes of rhs of assign
AstNodeAssign* m_assignp; // Assign found for dedupe
AstNode* m_ifCondp; // IF condition that assign is under
bool m_always; // Assign is under an always
bool m_dedupable; // Determined the assign to be dedupable
// VISITORS
virtual void visit(AstNodeAssign* assignp, AstNUser*) {
if (m_dedupable) {
// I think we could safely dedupe an always block with multiple non-blocking statements, but erring on side of caution here
if (!m_assignp) {
m_assignp = assignp;
} else {
m_dedupable = false;
}
}
}
virtual void visit(AstAlways* alwaysp, AstNUser*) {
if (m_dedupable) {
if (!m_always) {
m_always = true;
alwaysp->bodysp()->iterateAndNext(*this);
} else {
m_dedupable = false;
}
}
}
// Ugly support for latches of the specific form -
// always @(...)
// if (...)
// foo = ...; // or foo <= ...;
virtual void visit(AstNodeIf* ifp, AstNUser*) {
if (m_dedupable) {
if (m_always && !m_ifCondp && !ifp->elsesp()) { //we're under an always, this is the first IF, and there's no else
m_ifCondp = ifp->condp();
ifp->ifsp()->iterateAndNext(*this);
} else {
m_dedupable = false;
}
}
}
virtual void visit(AstComment*, AstNUser*) {} // NOP
//--------------------
// Default
virtual void visit(AstNode*, AstNUser*) {
m_dedupable = false;
}
public:
// CONSTUCTORS
GateDedupeVarVisitor() {}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = NULL;
m_ifCondp = NULL;
m_always = false;
m_dedupable = true;
nodep->accept(*this);
if (m_dedupable && m_assignp) {
AstNode* lhsp = m_assignp->lhsp();
// Possible todo, handle more complex lhs expressions
if (AstNodeVarRef* lhsVarRefp = lhsp->castNodeVarRef()) {
if (lhsVarRefp->varScopep() != consumerVarScopep) consumerVarScopep->v3fatalSrc("Consumer doesn't match lhs of assign");
if (AstNodeAssign* dup = m_hash.hashAndFindDupe(m_assignp,activep,m_ifCondp)) {
return (AstNodeVarRef*) dup->lhsp();
}
}
}
return NULL;
}
};
//######################################################################
// Recurse through the graph, looking for duplicate expressions on the rhs of an assign
class GateDedupeGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
// AstVarScope::user2p -> bool: already visited
// AstUser2InUse m_inuser2; (Allocated for use in GateVisitor)
V3Double0 m_numDeduped; // Statistic tracking
GateDedupeVarVisitor m_varVisitor; // Looks for a dupe of the logic
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
// Check that we haven't been here before
if (vvertexp->varScp()->user2()) return NULL;
vvertexp->varScp()->user2(true);
AstNodeVarRef* dupVarRefp = (AstNodeVarRef*) vvertexp->iterateInEdges(*this, (AstNUser*) vvertexp);
if (dupVarRefp && vvertexp->inSize1()) {
V3GraphEdge* edgep = vvertexp->inBeginp();
GateLogicVertex* lvertexp = (GateLogicVertex*)edgep->fromp();
if (!vvertexp->dedupable()) vvertexp->varScp()->v3fatalSrc("GateLogicVertex* visit should have returned NULL if consumer var vertex is not dedupable.");
GateOkVisitor okVisitor(lvertexp->nodep(), false, true);
if (okVisitor.isSimple()) {
AstVarScope* dupVarScopep = dupVarRefp->varScopep();
GateVarVertex* dupVvertexp = (GateVarVertex*) (dupVarScopep->user1p());
UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl);
m_numDeduped++;
// Replace all of this varvertex's consumers with dupVarRefp
for (V3GraphEdge* outedgep = vvertexp->outBeginp();outedgep;) {
GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(outedgep->top());
AstNode* consumerp = consumeVertexp->nodep();
GateElimVisitor elimVisitor(consumerp,vvertexp->varScp(),dupVarRefp);
outedgep = outedgep->relinkFromp(dupVvertexp);
}
// Propogate attributes
dupVvertexp->propagateAttrClocksFrom(vvertexp);
// Remove inputs links
while (V3GraphEdge* inedgep = vvertexp->inBeginp()) {
inedgep->unlinkDelete(); inedgep=NULL;
}
// replaceAssigns() does the deleteTree on lvertexNodep in a later step
AstNode* lvertexNodep = lvertexp->nodep();
lvertexNodep->unlinkFrBack();
vvertexp->varScp()->valuep(lvertexNodep);
lvertexNodep = NULL;
vvertexp->user(true);
lvertexp->user(true);
}
}
return NULL;
}
// Returns a varref that has the same logic input
virtual AstNUser* visit(GateLogicVertex* lvertexp, AstNUser* vup) {
lvertexp->iterateInEdges(*this);
GateVarVertex* consumerVvertexpp = (GateVarVertex*) vup;
if (lvertexp->dedupable() && consumerVvertexpp->dedupable()) {
AstNode* nodep = lvertexp->nodep();
AstVarScope* consumerVarScopep = consumerVvertexpp->varScp();
// TODO: Doing a simple pointer comparison of activep won't work
// optimally for statements under generated clocks. Statements under
// different generated clocks will never compare as equal, even if the
// generated clocks are deduped into one clock.
AstActive* activep = lvertexp->activep();
return (AstNUser*) m_varVisitor.findDupe(nodep, consumerVarScopep, activep);
}
return NULL;
}
public:
GateDedupeGraphVisitor() {}
void dedupeTree(GateVarVertex* vvertexp) {
vvertexp->accept(*this);
}
V3Double0 numDeduped() { return m_numDeduped; }
};
//----------------------------------------------------------------------
void GateVisitor::dedupe() {
AstNode::user2ClearTree();
GateDedupeGraphVisitor deduper;
// Traverse starting from each of the clocks
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isClock()) {
deduper.dedupeTree(vvertexp);
}
}
}
// Traverse starting from each of the outputs
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
if (vvertexp->isTop() && vvertexp->varScp()->varp()->isOutput()) {
deduper.dedupeTree(vvertexp);
}
}
}
m_statDedupLogic += deduper.numDeduped();
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+23 -5
View File
@@ -39,9 +39,14 @@ int V3Graph::debug() { return max(V3Error::debugDefault(), s_debug); }
//######################################################################
// Vertices
V3GraphVertex::V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old)
: m_fanout(old.m_fanout), m_color(old.m_color), m_rank(old.m_rank) {
m_userp = NULL;
verticesPushBack(graphp);
}
V3GraphVertex::V3GraphVertex(V3Graph* graphp)
: m_fanout(0), m_color(0), m_rank(0)
{
: m_fanout(0), m_color(0), m_rank(0) {
m_userp = NULL;
verticesPushBack(graphp);
}
@@ -125,9 +130,9 @@ ostream& operator<<(ostream& os, V3GraphVertex* vertexp) {
//######################################################################
// Edges
V3GraphEdge::V3GraphEdge(V3Graph* graphp,
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable) {
void V3GraphEdge::init(V3Graph* graphp,
V3GraphVertex* fromp, V3GraphVertex* top, int weight,
bool cutable) {
UASSERT(fromp, "Null from pointer\n");
UASSERT(top, "Null to pointer\n");
m_fromp = fromp;
@@ -140,6 +145,14 @@ V3GraphEdge::V3GraphEdge(V3Graph* graphp,
inPushBack();
}
V3GraphEdge* V3GraphEdge::relinkFromp(V3GraphVertex* newFromp) {
V3GraphEdge *oldNxt = outNextp();
m_outs.unlink(m_fromp->m_outs, this);
m_fromp = newFromp;
outPushBack();
return oldNxt;
}
void V3GraphEdge::unlinkDelete() {
// Unlink from side
m_outs.unlink(m_fromp->m_outs, this);
@@ -267,6 +280,11 @@ void V3Graph::dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgrap
}
}
//! Variant of dumpDotFilePrefixed without --dump option check
void V3Graph::dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph) {
dumpDotFile(v3Global.debugFilename(nameComment)+".dot", colorAsSubgraph);
}
void V3Graph::dumpDotFile(const string& filename, bool colorAsSubgraph) {
// This generates a file used by graphviz, http://www.graphviz.org
// "hardcoded" parameters:
+29 -7
View File
@@ -119,13 +119,17 @@ public:
/// Remove any redundant edges, weights become SUM of any other weight
void removeRedundantEdgesSum(V3EdgeFuncP edgeFuncp);
/// Call loopsVertexCb on any loops starting where specified
/// Call loopsVertexCb on any one loop starting where specified
void reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp);
/// Build a subgraph of all loops starting where specified
void subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp, V3Graph* loopGraphp);
/// Debugging
void dump(ostream& os=cout);
void dumpDotFile(const string& filename, bool colorAsSubgraph);
void dumpDotFilePrefixed(const string& nameComment, bool colorAsSubgraph=false);
void dumpDotFilePrefixedAlways(const string& nameComment, bool colorAsSubgraph=false);
void userClearVertices();
void userClearEdges();
static void test();
@@ -159,12 +163,18 @@ protected:
void rank(uint32_t rank) { m_rank = rank; }
void inUnlink() { m_ins.reset(); } // Low level; normally unlinkDelete is what you want
void outUnlink() { m_outs.reset(); } // Low level; normally unlinkDelete is what you want
protected:
// CONSTRUCTORS
V3GraphVertex(V3Graph* graphp, const V3GraphVertex& old);
public:
// CONSTRUCTION
V3GraphVertex(V3Graph* graphp);
//! Clone copy constructor. Doesn't copy edges or user/userp.
virtual V3GraphVertex* clone(V3Graph* graphp) const {
return new V3GraphVertex(graphp, *this); }
virtual ~V3GraphVertex() {}
void unlinkEdges(V3Graph* graphp);
void unlinkDelete(V3Graph* graphp);
// ACCESSORS
virtual string name() const { return ""; }
virtual string dotColor() const { return "black"; }
@@ -207,6 +217,9 @@ ostream& operator<<(ostream& os, V3GraphVertex* vertexp);
class V3GraphEdge {
// Wires/variables aren't edges. Edges have only a single to/from vertex
public:
// ENUMS
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
protected:
friend class V3Graph; friend class V3GraphVertex;
friend class GraphAcyc; friend class GraphAcycEdge;
@@ -222,15 +235,23 @@ protected:
uint32_t m_user; // Marker for some algorithms
};
// METHODS
void init(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false);
void cut() { m_weight = 0; } // 0 weight is same as disconnected
void outPushBack();
void inPushBack();
// CONSTRUCTORS
protected:
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, const V3GraphEdge& old) {
init(graphp, fromp, top, old.m_weight, old.m_cutable);
}
public:
// ENUMS
enum Cuttable { NOT_CUTABLE = false, CUTABLE = true }; // For passing to V3GraphEdge
// CONSTRUCTION
// Add DAG from one node to the specified node
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false);
//! Add DAG from one node to the specified node
V3GraphEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top, int weight, bool cutable=false) {
init(graphp, fromp, top, weight, cutable);
}
//! Clone copy constructor. Doesn't copy existing vertices or user/userp.
virtual V3GraphEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new V3GraphEdge(graphp, fromp, top, *this); }
virtual ~V3GraphEdge() {}
// METHODS
virtual string name() const { return m_fromp->name()+"->"+m_top->name(); }
@@ -242,6 +263,7 @@ public:
return top()->sortCmp(rhsp->top());
}
void unlinkDelete();
V3GraphEdge* relinkFromp(V3GraphVertex* newFromp);
// ACCESSORS
int weight() const { return m_weight; }
void weight(int weight) { m_weight=weight; }
+55 -1
View File
@@ -376,6 +376,58 @@ void V3Graph::reportLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp) {
GraphAlgRLoops (this, edgeFuncp, vertexp);
}
//######################################################################
//######################################################################
// Algorithms - subtrees
class GraphAlgSubtrees : GraphAlg {
private:
V3Graph* m_loopGraphp;
//! Iterate through all connected nodes of a graph with a loop or loops.
V3GraphVertex* vertexIterateAll(V3GraphVertex* vertexp) {
if (V3GraphVertex* newVertexp = (V3GraphVertex*)vertexp->userp()) {
return newVertexp;
} else {
newVertexp = vertexp->clone(m_loopGraphp);
vertexp->userp(newVertexp);
for (V3GraphEdge* edgep = vertexp->outBeginp();
edgep; edgep=edgep->outNextp()) {
if (followEdge(edgep)) {
V3GraphEdge* newEdgep = (V3GraphEdge*)edgep->userp();
if (!newEdgep) {
V3GraphVertex* newTop = vertexIterateAll(edgep->top());
newEdgep = edgep->clone(m_loopGraphp, newVertexp,
newTop);
edgep->userp(newEdgep);
}
}
}
return newVertexp;
}
}
public:
GraphAlgSubtrees(V3Graph* graphp, V3Graph* loopGraphp,
V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp)
: GraphAlg(graphp, edgeFuncp), m_loopGraphp (loopGraphp) {
// Vertex::m_userp - New vertex if we have seen this vertex already
// Edge::m_userp - New edge if we have seen this edge already
m_graphp->userClearVertices();
m_graphp->userClearEdges();
(void) vertexIterateAll(vertexp);
}
~GraphAlgSubtrees() {}
};
//! Report the entire connected graph with a loop or loops
void V3Graph::subtreeLoops(V3EdgeFuncP edgeFuncp, V3GraphVertex* vertexp,
V3Graph* loopGraphp) {
GraphAlgSubtrees (this, loopGraphp, edgeFuncp, vertexp);
}
//######################################################################
//######################################################################
// Algorithms - make non cutable
@@ -465,7 +517,9 @@ void V3Graph::order() {
}
}
// Sort list of vertices by rank, then fanout
// Sort list of vertices by rank, then fanout. Fanout is a bit of a
// misnomer. It is the sum of all the fanouts of nodes reached from a node
// *plus* the count of edges in to that node.
sortVertices();
// Sort edges by rank then fanout of node they point to
sortEdges();
+19 -2
View File
@@ -105,12 +105,16 @@ public:
//######################################################################
// Hashed class functions
void V3Hashed::hashAndInsert(AstNode* nodep) {
V3Hashed::iterator V3Hashed::hashAndInsert(AstNode* nodep) {
hash(nodep);
return m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
}
void V3Hashed::hash(AstNode* nodep) {
UINFO(8," hashI "<<nodep<<endl);
if (!nodep->user4p()) {
HashedVisitor visitor (nodep);
}
m_hashMmap.insert(make_pair(nodeHash(nodep), nodep));
}
bool V3Hashed::sameNodes(AstNode* node1p, AstNode* node2p) {
@@ -189,3 +193,16 @@ V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep) {
return end();
}
V3Hashed::iterator V3Hashed::findDuplicate(AstNode* nodep, V3HashedUserCheck* checkp) {
UINFO(8," findD "<<nodep<<endl);
if (!nodep->user4p()) nodep->v3fatalSrc("Called findDuplicate on non-hashed node");
pair <HashMmap::iterator,HashMmap::iterator> eqrange = mmap().equal_range(nodeHash(nodep));
for (HashMmap::iterator eqit = eqrange.first; eqit != eqrange.second; ++eqit) {
AstNode* node2p = eqit->second;
if (nodep != node2p && checkp->check(nodep,node2p) && sameNodes(nodep, node2p)) {
return eqit;
}
}
return end();
}
+8 -1
View File
@@ -45,6 +45,11 @@ public:
//============================================================================
struct V3HashedUserCheck {
// Functor for V3Hashed::findDuplicate
virtual bool check(AstNode*,AstNode*) =0;
};
class V3Hashed : public VHashedBase {
// NODE STATE
// AstNode::user4() -> V3Hash. Hash value of this node (hash of 0 is illegal)
@@ -70,10 +75,12 @@ public:
// METHODS
void clear() { m_hashMmap.clear(); AstNode::user4ClearTree(); }
void hashAndInsert(AstNode* nodep); // Hash the node, and insert into map
iterator hashAndInsert(AstNode* nodep); // Hash the node, and insert into map. Return iterator to inserted
void hash(AstNode* nodep); // Only hash the node
bool sameNodes(AstNode* node1p, AstNode* node2p); // After hashing, and tell if identical
void erase(iterator it); // Remove node from structures
iterator findDuplicate(AstNode* nodep); // Return duplicate in hash, if any
iterator findDuplicate(AstNode* nodep, V3HashedUserCheck* checkp); // Extra user checks for sameness
AstNode* iteratorNodep(iterator it) { return it->second; }
void dumpFile(const string& filename, bool tree);
void dumpFilePrefixed(const string& nameComment, bool tree=false);
+7 -6
View File
@@ -198,6 +198,7 @@ private:
AstNode* exprp = nodep->exprp()->unlinkFrBack();
bool inputPin = nodep->modVarp()->isInput();
if (!inputPin && !exprp->castVarRef()
&& !exprp->castConcat() // V3Const will collapse the SEL with the one we're about to make
&& !exprp->castSel()) { // V3Const will collapse the SEL with the one we're about to make
nodep->v3error("Unsupported: Per-bit array instantiations with output connections to non-wires.");
// Note spec allows more complicated matches such as slices and such
@@ -265,10 +266,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
// Done. Constant.
} else {
// Make a new temp wire
//if (1||debug()>=9) { pinp->dumpTree(cout,"in_pin:"); }
//if (1||debug()>=9) { pinp->dumpTree(cout,"-in_pin:"); }
AstNode* pinexprp = pinp->exprp()->unlinkFrBack();
string newvarname = ((pinVarp->isOutput() ? "__Vcellout__" : "__Vcellinp__")
+cellp->name()+"__"+pinp->name());
string newvarname = ((string)(pinVarp->isOutput() ? "__Vcellout" : "__Vcellinp")
+(forTristate?"t":"") // Prevent name conflict if both tri & non-tri add signals
+"__"+cellp->name()+"__"+pinp->name());
AstVar* newvarp = new AstVar (pinVarp->fileline(), AstVarType::MODULETEMP, newvarname, pinVarp);
// Important to add statement next to cell, in case there is a generate with same named cell
cellp->addNextHere(newvarp);
@@ -291,15 +293,14 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, true));
} else {
// V3 width should have range/extended to make the widths correct
if (pinexprp->width() != pinVarp->width()) pinp->v3fatalSrc("Input pin width mismatch");
assignp = new AstAssignW (pinp->fileline(),
new AstVarRef(pinp->fileline(), newvarp, true),
pinexprp);
pinp->exprp(new AstVarRef (pinexprp->fileline(), newvarp, false));
}
if (assignp) cellp->addNextHere(assignp);
//if (1||debug()) { pinp->dumpTree(cout," out:"); }
//if (1||debug()) { assignp->dumpTree(cout," aout:"); }
//if (debug()) { pinp->dumpTree(cout,"- out:"); }
//if (debug()) { assignp->dumpTree(cout,"- aout:"); }
}
return assignp;
}
+5 -2
View File
@@ -41,6 +41,7 @@ public:
L1364_2005,
L1800_2005,
L1800_2009,
L1800_2012,
// ***Add new elements below also***
_ENUM_END
};
@@ -52,11 +53,13 @@ public:
"1364-2001",
"1364-2005",
"1800-2005",
"1800-2009"
"1800-2009",
"1800-2012"
};
return names[m_e];
};
static V3LangCode mostRecent() { return V3LangCode(L1800_2009); }
static V3LangCode mostRecent() { return V3LangCode(L1800_2012); }
bool systemVerilog() const { return m_e == L1800_2005 || m_e == L1800_2009 || m_e == L1800_2012; }
bool legal() const { return m_e != L_ERROR; }
//
enum en m_e;
+48 -17
View File
@@ -90,6 +90,7 @@ private:
// NODE STATE
// Entire netlist:
// AstNodeModule::user1p() // V3GraphVertex* Vertex describing this module
// AstCell::user1() // bool Did it.
// Allocated across all readFiles in V3Global::readFiles:
// AstNode::user4p() // VSymEnt* Package and typedef symbol names
AstUser1InUse m_inuser1;
@@ -121,6 +122,27 @@ private:
return (nodep->user1p()->castGraphVertex());
}
AstNodeModule* resolveModule(AstNode* nodep, const string& modName) {
AstNodeModule* modp = m_mods.rootp()->findIdFallback(modName)->nodep()->castNodeModule();
if (!modp) {
// Read-subfile
// If file not found, make AstNotFoundModule, rather than error out.
// We'll throw the error when we know the module will really be needed.
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
parser.parseFile(nodep->fileline(), modName, false, "");
V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names
readModNames();
// Check again
modp = m_mods.rootp()->findIdFallback(modName)->nodep()->castNodeModule();
if (!modp) {
// This shouldn't throw a message as parseFile will create a AstNotFoundModule for us
nodep->v3error("Can't resolve module reference: "<<modName);
}
}
return modp;
}
// VISITs
virtual void visit(AstNetlist* nodep, AstNUser*) {
AstNode::user1ClearTree();
@@ -158,7 +180,8 @@ private:
m_modp = nodep;
UINFO(2,"Link Module: "<<nodep<<endl);
if (nodep->fileline()->filebasenameNoExt() != nodep->prettyName()
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename())) {
&& !v3Global.opt.isLibraryFile(nodep->fileline()->filename())
&& !nodep->internal()) {
// We only complain once per file, otherwise library-like files have a huge mess of warnings
if (m_declfnWarned.find(nodep->fileline()->filename()) == m_declfnWarned.end()) {
m_declfnWarned.insert(nodep->fileline()->filename());
@@ -180,6 +203,7 @@ private:
if (!m_libVertexp) m_libVertexp = new LibraryVertex(&m_graph);
new V3GraphEdge(&m_graph, m_libVertexp, vertex(nodep), 1, false);
}
// Note AstBind also has iteration on cells
nodep->iterateChildren(*this);
nodep->checkTree();
m_modp = NULL;
@@ -192,28 +216,35 @@ private:
new V3GraphEdge(&m_graph, vertex(m_modp), vertex(nodep->packagep()), 1, false);
}
virtual void visit(AstBind* nodep, AstNUser*) {
// Bind: Has cells underneath that need to be put into the new module, and cells which need resolution
// TODO this doesn't allow bind to dotted hier names, that would require
// this move to post param, which would mean we do not auto-read modules
// and means we cannot compute module levels until later.
UINFO(4,"Link Bind: "<<nodep<<endl);
AstNodeModule* modp = resolveModule(nodep,nodep->name());
if (modp) {
AstNode* cellsp = nodep->cellsp()->unlinkFrBackWithNext();
// Module may have already linked, so need to pick up these new cells
AstNodeModule* oldModp = m_modp;
{
m_modp = modp;
modp->addStmtp(cellsp); // Important that this adds to end, as next iterate assumes does all cells
cellsp->iterateAndNext(*this);
}
m_modp = oldModp;
}
pushDeletep(nodep->unlinkFrBack());
}
virtual void visit(AstCell* nodep, AstNUser*) {
// Cell: Resolve its filename. If necessary, parse it.
if (nodep->user1SetOnce()) return; // AstBind and AstNodeModule may call a cell twice
if (!nodep->modp()) {
UINFO(4,"Link Cell: "<<nodep<<endl);
// Use findIdFallback instead of findIdFlat; it doesn't matter for now
// but we might support modules-under-modules someday.
AstNodeModule* modp = m_mods.rootp()->findIdFallback(nodep->modName())->nodep()->castNodeModule();
if (!modp) {
// Read-subfile
// If file not found, make AstNotFoundModule, rather than error out.
// We'll throw the error when we know the module will really be needed.
V3Parse parser (v3Global.rootp(), m_filterp, m_parseSymp);
parser.parseFile(nodep->fileline(), nodep->modName(), false, "");
V3Error::abortIfErrors();
// We've read new modules, grab new pointers to their names
readModNames();
// Check again
modp = m_mods.rootp()->findIdFallback(nodep->modName())->nodep()->castNodeModule();
if (!modp) {
nodep->v3error("Can't resolve module reference: "<<nodep->modName());
}
}
AstNodeModule* modp = resolveModule(nodep,nodep->modName());
if (modp) {
nodep->modp(modp);
// Track module depths, so can sort list from parent down to children
+17 -5
View File
@@ -103,6 +103,7 @@ public:
if (!diddump && v3Global.opt.dumpTree()) {
diddump = true;
m_syms.dumpFilePrefixed("linkdot-preerr");
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
}
}
@@ -660,7 +661,7 @@ private:
// Find under either a task or the module's vars
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
if (!foundp && m_modSymp && nodep->name() == m_modSymp->nodep()->name()) foundp = m_modSymp; // Conflicts with modname?
AstVar* findvarp = foundp->nodep()->castVar();
AstVar* findvarp = foundp ? foundp->nodep()->castVar() : NULL;
bool ins=false;
if (!foundp) {
ins=true;
@@ -729,7 +730,7 @@ private:
// Find under either a task or the module's vars
VSymEnt* foundp = m_curSymp->findIdFallback(nodep->name());
if (!foundp && m_modSymp && nodep->name() == m_modSymp->nodep()->name()) foundp = m_modSymp; // Conflicts with modname?
AstEnumItem* findvarp = foundp->nodep()->castEnumItem();
AstEnumItem* findvarp = foundp ? foundp->nodep()->castEnumItem() : NULL;
bool ins=false;
if (!foundp) {
ins=true;
@@ -1113,10 +1114,14 @@ private:
}
virtual void visit(AstScope* nodep, AstNUser*) {
UINFO(8," "<<nodep<<endl);
VSymEnt* oldModSymp = m_modSymp;
VSymEnt* oldCurSymp = m_curSymp;
checkNoDot(nodep);
m_ds.m_dotSymp = m_curSymp = m_statep->getScopeSym(nodep);
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getScopeSym(nodep);
nodep->iterateChildren(*this);
m_ds.m_dotSymp = m_curSymp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
m_modSymp = oldModSymp;
m_curSymp = oldCurSymp;
}
virtual void visit(AstCellInline* nodep, AstNUser*) {
checkNoDot(nodep);
@@ -1319,6 +1324,7 @@ private:
newp = new AstVarRef(nodep->fileline(), nodep->name(), false); // lvalue'ness computed later
newp->varp(varp);
newp->packagep(foundp->packagep());
UINFO(9," new "<<newp<<endl);
}
nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
m_ds.m_dotPos = DP_MEMBER;
@@ -1441,10 +1447,15 @@ private:
AstVarRef* newvscp = new AstVarRef(nodep->fileline(), vscp, nodep->lvalue());
nodep->replaceWith(newvscp);
nodep->deleteTree(); nodep=NULL;
UINFO(9," new "<<newvscp<<endl); // Also prints taskp
}
}
}
}
virtual void visit(AstEnumItemRef* nodep, AstNUser*) {
// EnumItemRef may be under a dot. Should already be resolved.
nodep->iterateChildren(*this);
}
virtual void visit(AstVar* nodep, AstNUser*) {
checkNoDot(nodep);
nodep->iterateChildren(*this);
@@ -1498,7 +1509,7 @@ private:
VSymEnt* foundp = NULL;
AstNodeFTask* taskp = NULL;
foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
taskp = foundp->nodep()->castNodeFTask(); // Maybe NULL
taskp = foundp ? foundp->nodep()->castNodeFTask() : NULL; // Maybe NULL
if (taskp) {
nodep->taskp(taskp);
nodep->packagep(foundp->packagep());
@@ -1563,6 +1574,7 @@ private:
m_ds.init(m_curSymp);
nodep->rhsp()->iterateAndNext(*this);
nodep->thsp()->iterateAndNext(*this);
nodep->attrp()->iterateAndNext(*this);
}
m_ds = lastStates;
}
+3 -2
View File
@@ -183,7 +183,8 @@ private:
}
}
}
if (!nodep->sensp()->castNodeVarRef()) {
if (!nodep->sensp()->castNodeVarRef()
&& !nodep->sensp()->castEnumItemRef()) { // V3Const will cleanup
if (debug()) nodep->dumpTree(cout,"-tree: ");
nodep->v3error("Unsupported: Complex statement in sensitivity list");
}
@@ -203,7 +204,7 @@ private:
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) { // Maybe varxref - so need to clone
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
varrefp->cloneTree(false)));
} else if (AstMemberSel* fromp = nodep->fromp()->castMemberSel()) {
} else if (AstMemberSel* fromp = basefromp->castMemberSel()) {
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::MEMBER_BASE,
fromp->cloneTree(false)));
} else {
+3 -3
View File
@@ -79,7 +79,7 @@ public:
void pushBack (V3List<T>& listr, T newp) {
// "this" must be a element inside of *newp
// cppcheck-suppress thisSubtraction
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
size_t offset = (size_t)(vluint8_t*)(this) - (size_t)(vluint8_t*)(newp);
m_nextp = NULL;
if (!listr.m_headp) listr.m_headp = newp;
m_prevp = listr.m_tailp;
@@ -89,7 +89,7 @@ public:
void pushFront (V3List<T>& listr, T newp) {
// "this" must be a element inside of *newp
// cppcheck-suppress thisSubtraction
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(newp);
size_t offset = (size_t)(vluint8_t*)(this) - (size_t)(vluint8_t*)(newp);
m_nextp = listr.m_headp;
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = newp;
listr.m_headp = newp;
@@ -100,7 +100,7 @@ public:
void unlink (V3List<T>& listr, T oldp) {
// "this" must be a element inside of *oldp
// cppcheck-suppress thisSubtraction
size_t offset = (vluint8_t*)(this) - (vluint8_t*)(oldp);
size_t offset = (size_t)(vluint8_t*)(this) - (size_t)(vluint8_t*)(oldp);
if (m_nextp) baseToListEnt(m_nextp,offset)->m_prevp = m_prevp;
else listr.m_tailp = m_prevp;
if (m_prevp) baseToListEnt(m_prevp,offset)->m_nextp = m_nextp;
+10
View File
@@ -625,6 +625,16 @@ bool V3Number::isLt(const V3Number& rhs) const {
}
return 0;
}
bool V3Number::isLtXZ(const V3Number& rhs) const {
// Include X/Z in comparisons for sort ordering
for (int bit=0; bit<max(this->width(),rhs.width()); bit++) {
if (this->bitIs1(bit) && rhs.bitIs0(bit)) { return 1; }
if (rhs.bitIs1(bit) && this->bitIs0(bit)) { return 0; }
if (this->bitIsXZ(bit)) { return 1; }
if (rhs.bitIsXZ(bit)) { return 0; }
}
return 0;
}
int V3Number::widthMin() const {
for(int bit=width()-1; bit>0; bit--) {
+2 -1
View File
@@ -166,6 +166,7 @@ public:
bool isEqAllOnes(int optwidth=0) const;
bool isCaseEq(const V3Number& rhsp) const; // operator==
bool isLt(const V3Number& rhsp) const; // operator<
bool isLtXZ(const V3Number& rhsp) const; // operator< with XZ compared
void isSigned(bool ssigned) { m_signed=ssigned; }
bool isUnknown() const;
uint32_t toUInt() const;
@@ -180,7 +181,7 @@ public:
uint32_t mostSetBitP1() const; // Highest bit set plus one, IE for 16 return 5, for 0 return 0.
// Operators
bool operator<(const V3Number& rhs) const { return isLt(rhs); }
bool operator<(const V3Number& rhs) const { return isLtXZ(rhs); }
// STATICS
static int log2b(uint32_t num);
+22 -5
View File
@@ -28,6 +28,7 @@
#include <cctype>
#include <dirent.h>
#include <unistd.h>
#include <fcntl.h>
#include <set>
#include <list>
#include <map>
@@ -77,7 +78,7 @@ struct V3OptionsImp {
}
}
}
void addLangExt(const string &langext, const V3LangCode lc) {
void addLangExt(const string& langext, const V3LangCode& lc) {
// New language extension replaces any pre-existing one.
(void)m_langExts.erase(langext);
m_langExts[langext] = lc;
@@ -98,7 +99,7 @@ void V3Options::addIncDirUser(const string& incdir) {
void V3Options::addIncDirFallback(const string& incdir) {
m_impp->addIncDirFallback(incdir);
}
void V3Options::addLangExt(const string &langext, const V3LangCode lc) {
void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
m_impp->addLangExt(langext, lc);
}
void V3Options::addLibExtV(const string& libext) {
@@ -277,6 +278,17 @@ bool V3Options::fileStatNormal(const string& filename) {
return true;
}
void V3Options::fileNfsFlush(const string& filename) {
// NFS caches stat() calls so to get up-to-date information must
// do a open or opendir on the filename.
// Faster to just try both rather than check if a file is a dir.
if (DIR* dirp = opendir(filename.c_str())) {
closedir(dirp);
} else if (int fd = ::open(filename.c_str(), O_RDONLY)) {
if (fd>0) ::close(fd);
}
}
string V3Options::fileExists (const string& filename) {
// Surprisingly, for VCS and other simulators, this process
// is quite slow; presumably because of re-reading each directory
@@ -661,14 +673,15 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strncmp (sw, "+incdir+", 8)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
}
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2009)
else if (parseLangExt(sw, "+systemverilogext+", V3LangCode::L1800_2012)
|| parseLangExt(sw, "+verilog1995ext+", V3LangCode::L1364_1995)
|| parseLangExt(sw, "+verilog2001ext+", V3LangCode::L1364_2001)
|| parseLangExt(sw, "+1364-1995ext+", V3LangCode::L1364_1995)
|| parseLangExt(sw, "+1364-2001ext+", V3LangCode::L1364_2001)
|| parseLangExt(sw, "+1364-2005ext+", V3LangCode::L1364_2005)
|| parseLangExt(sw, "+1800-2005ext+", V3LangCode::L1800_2005)
|| parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009)) {
|| parseLangExt(sw, "+1800-2009ext+", V3LangCode::L1800_2009)
|| parseLangExt(sw, "+1800-2012ext+", V3LangCode::L1800_2012)) {
// Nothing to do here - all done in the test
}
@@ -729,6 +742,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
else if ( onoff (sw, "-public", flag/*ref*/) ) { m_public = flag; }
else if ( onoff (sw, "-report-unoptflat", flag/*ref*/) ) { m_reportUnoptflat = flag; }
else if ( onoff (sw, "-savable", flag/*ref*/) ) { m_savable = flag; }
else if ( !strcmp (sw, "-sc") ) { m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
else if ( onoff (sw, "-skip-identical", flag/*ref*/) ) { m_skipIdentical = flag; }
@@ -753,6 +767,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'a': m_oTable = flag; break;
case 'b': m_oCombine = flag; break;
case 'c': m_oConst = flag; break;
case 'd': m_oDedupe = flag; break;
case 'e': m_oCase = flag; break;
case 'f': m_oFlopGater = flag; break;
case 'g': m_oGate = flag; break;
@@ -1117,7 +1132,7 @@ string V3Options::parseFileArg(const string& optdir, const string& relfilename)
//! Utility to see if we have a language extension argument and if so add it.
bool V3Options::parseLangExt (const char* swp, //!< argument text
const char* langswp, //!< option to match
const V3LangCode lc) { //!< language code
const V3LangCode& lc) { //!< language code
int len = strlen(langswp);
if (!strncmp(swp, langswp, len)) {
addLangExt(swp + len, lc);
@@ -1200,6 +1215,7 @@ V3Options::V3Options() {
m_traceDups = false;
m_traceUnderscore = false;
m_underlineZero = false;
m_reportUnoptflat = false;
m_xInitialEdge = false;
m_xmlOnly = false;
@@ -1289,6 +1305,7 @@ void V3Options::optimize(int level) {
m_oSubst = flag;
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = level >= 3;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+8 -2
View File
@@ -36,6 +36,7 @@
class V3OptionsImp;
class FileLine;
struct stat;
typedef vector<string> V3StringList;
typedef set<string> V3StringSet;
@@ -88,6 +89,7 @@ class V3Options {
bool m_traceDups; // main switch: --trace-dups
bool m_traceUnderscore;// main switch: --trace-underscore
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
bool m_reportUnoptflat; // main switch: --report-unoptflat
bool m_xInitialEdge; // main switch: --x-initial-edge
bool m_xmlOnly; // main switch: --xml-netlist
@@ -130,6 +132,7 @@ class V3Options {
bool m_oCase; // main switch: -Oe: case tree conversion
bool m_oCombine; // main switch: -Ob: common icode packing
bool m_oConst; // main switch: -Oc: constant folding
bool m_oDedupe; // main switch: -Od: logic deduplication
bool m_oExpand; // main switch: -Ox: expansion of C macros
bool m_oFlopGater; // main switch: -Of: flop gater detection
bool m_oGate; // main switch: -Og: gate wire elimination
@@ -150,7 +153,7 @@ class V3Options {
void addFuture(const string& flag);
void addIncDirUser(const string& incdir); // User requested
void addIncDirFallback(const string& incdir); // Low priority if not found otherwise
void addLangExt(const string &langext, const V3LangCode lc);
void addLangExt(const string& langext, const V3LangCode& lc);
void addLibExtV(const string& libext);
void optimize(int level);
void showVersion(bool verbose);
@@ -158,7 +161,7 @@ class V3Options {
bool onoff(const char* sw, const char* arg, bool& flag);
bool suffixed(const char* sw, const char* arg);
string parseFileArg(const string& optdir, const string& relfilename);
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode lc);
bool parseLangExt(const char* swp, const char* langswp, const V3LangCode& lc);
string filePathCheckOneDir(const string& modname, const string& dirname);
static string getenvStr(const string& envvar, const string& defaultValue);
@@ -220,6 +223,7 @@ class V3Options {
bool lintOnly() const { return m_lintOnly; }
bool ignc() const { return m_ignc; }
bool inhibitSim() const { return m_inhibitSim; }
bool reportUnoptflat() const { return m_reportUnoptflat; }
bool xInitialEdge() const { return m_xInitialEdge; }
bool xmlOnly() const { return m_xmlOnly; }
@@ -265,6 +269,7 @@ class V3Options {
bool oCase() const { return m_oCase; }
bool oCombine() const { return m_oCombine; }
bool oConst() const { return m_oConst; }
bool oDedupe() const { return m_oDedupe; }
bool oExpand() const { return m_oExpand; }
bool oFlopGater() const { return m_oFlopGater; }
bool oGate() const { return m_oGate; }
@@ -321,6 +326,7 @@ class V3Options {
V3LangCode fileLanguage(const string &filename);
static bool fileStatDir (const string& filename);
static bool fileStatNormal (const string& filename);
static void fileNfsFlush(const string& filename);
// METHODS (other OS)
static void throwSigsegv();
+117 -1
View File
@@ -232,6 +232,26 @@ public:
~OrderUser() {}
};
//######################################################################
// Comparator classes
//! Comparator for width of associated variable
struct OrderVarWidthCmp {
bool operator() (OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) {
return vsv1p->varScp()->varp()->width()
> vsv2p->varScp()->varp()->width();
}
};
//! Comparator for fanout of vertex
struct OrderVarFanoutCmp {
bool operator() (OrderVarStdVertex* vsv1p, OrderVarStdVertex* vsv2p) {
return vsv1p->fanout() > vsv2p->fanout();
}
};
//######################################################################
// Order class functions
@@ -285,6 +305,7 @@ private:
protected:
friend class OrderMoveDomScope;
V3List<OrderMoveDomScope*> m_pomReadyDomScope; // List of ready domain/scope pairs, by loopId
vector<OrderVarStdVertex*> m_unoptflatVars; // Vector of variables in UNOPTFLAT loop
private:
// STATS
@@ -418,10 +439,99 @@ private:
if (tempWeight) edgep->weight(1); // Else the below loop detect can't see the loop
m_graph.reportLoops(&OrderEdge::followComboConnected, vertexp); // calls OrderGraph::loopsVertexCb
if (tempWeight) edgep->weight(0);
if (v3Global.opt.reportUnoptflat()) {
// Report candidate variables for splitting
reportLoopVars(vertexp);
// Do a subgraph for the UNOPTFLAT loop
OrderGraph loopGraph;
m_graph.subtreeLoops(&OrderEdge::followComboConnected,
vertexp, &loopGraph);
loopGraph.dumpDotFilePrefixedAlways("unoptflat");
}
}
}
}
//! Find all variables in an UNOPTFLAT loop
//!
//! Ignore vars that are 1-bit wide and don't worry about generated
//! variables (PRE and POST vars, __Vdly__, __Vcellin__ and __VCellout).
//! What remains are candidates for splitting to break loops.
//!
//! node->user3 is used to mark if we have done a particular variable.
//! vertex->user is used to mark if we have seen this vertex before.
//!
//! @todo We could be cleverer in the future and consider just
//! the width that is generated/consumed.
void reportLoopVars(OrderVarVertex* vertexp) {
m_graph.userClearVertices();
AstNode::user3ClearTree();
m_unoptflatVars.clear();
reportLoopVarsIterate (vertexp, vertexp->color());
AstNode::user3ClearTree();
m_graph.userClearVertices();
// May be very large vector, so only report the "most important"
// elements. Up to 10 of the widest
cerr<<V3Error::msgPrefix()
<<" Widest candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
AstVar* varp = vsvertexp->varScp()->varp();
cerr<<V3Error::msgPrefix()<<" "
<<varp->fileline()<<" "<<varp->prettyName()<<dec
<<", width "<<varp->width()<<", fanout "
<<vsvertexp->fanout()<<endl;
}
// Up to 10 of the most fanned out
cerr<<V3Error::msgPrefix()
<<" Most fanned out candidate vars to split:"<<endl;
sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
OrderVarFanoutCmp());
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
AstVar* varp = vsvertexp->varScp()->varp();
cerr<<V3Error::msgPrefix()<<" "
<<varp->fileline()<<" "<<varp->prettyName()
<<", width "<<dec<<varp->width()
<<", fanout "<<vsvertexp->fanout()<<endl;
}
m_unoptflatVars.clear();
}
void reportLoopVarsIterate(V3GraphVertex* vertexp, uint32_t color) {
if (vertexp->user()) return; // Already done
vertexp->user(1);
if (OrderVarStdVertex* vsvertexp = dynamic_cast<OrderVarStdVertex*>(vertexp)) {
// Only reporting on standard variable vertices
AstVar* varp = vsvertexp->varScp()->varp();
if (!varp->user3()) {
string name = varp->prettyName();
if ((varp->width() != 1)
&& (name.find("__Vdly") == string::npos)
&& (name.find("__Vcell") == string::npos)) {
// Variable to report on and not yet done
m_unoptflatVars.push_back(vsvertexp);
}
varp->user3Inc();
}
}
// Iterate through all the to and from vertices of the same color
for (V3GraphEdge* edgep = vertexp->outBeginp(); edgep;
edgep = edgep->outNextp()) {
if (edgep->top()->color() == color) {
reportLoopVarsIterate(edgep->top(), color);
}
}
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep;
edgep = edgep->inNextp()) {
if (edgep->fromp()->color() == color) {
reportLoopVarsIterate(edgep->fromp(), color);
}
}
}
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
{
@@ -1600,7 +1710,10 @@ void OrderVisitor::process() {
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_preasn_done", true);
#else
// Break cycles
// Break cycles. Each strongly connected subgraph (including cutable
// edges) will have its own color, and corresponds to a loop in the
// original graph. However the new graph will be acyclic (the removed
// edges are actually still there, just with weight 0).
UINFO(2," Acyclic & Order...\n");
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_acyc");
@@ -1611,6 +1724,9 @@ void OrderVisitor::process() {
m_graph.order();
m_graph.dumpDotFilePrefixed("orderg_order");
// This finds everything that can be traced from an input (which by
// definition are the source clocks). After this any vertex which was
// traced has isFromInput() true.
UINFO(2," Process Clocks...\n");
processInputs(); // must be before processCircular
+107 -41
View File
@@ -123,6 +123,15 @@ public:
virtual void loopsVertexCb(V3GraphVertex* vertexp);
};
//! Graph for UNOPTFLAT loops
class UnoptflatGraph : public OrderGraph {
public:
UnoptflatGraph() {}
virtual ~UnoptflatGraph() {}
// Methods
virtual void loopsVertexCb(V3GraphVertex* vertexp);
};
//######################################################################
// Vertex types
@@ -131,12 +140,16 @@ class OrderEitherVertex : public V3GraphVertex {
AstSenTree* m_domainp; // Clock domain (NULL = to be computed as we iterate)
OrderLoopId m_inLoop; // Loop number vertex is in
bool m_isFromInput; // From input, or derrived therefrom (conservatively false)
protected:
OrderEitherVertex(V3Graph* graphp, const OrderEitherVertex& old)
: V3GraphVertex(graphp, old), m_scopep(old.m_scopep), m_domainp(old.m_domainp)
, m_inLoop(old.m_inLoop), m_isFromInput(old.m_isFromInput) {}
public:
OrderEitherVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp)
: V3GraphVertex(graphp), m_scopep(scopep), m_domainp(domainp)
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {
}
, m_inLoop(LOOPID_UNKNOWN), m_isFromInput(false) {}
virtual ~OrderEitherVertex() {}
virtual OrderEitherVertex* clone(V3Graph* graphp) const = 0;
// Methods
virtual OrderVEdgeType type() const = 0;
virtual bool domainMatters() = 0; // Must be in same domain when cross edge to this vertex
@@ -152,12 +165,16 @@ public:
};
class OrderInputsVertex : public OrderEitherVertex {
OrderInputsVertex(V3Graph* graphp, const OrderInputsVertex& old)
: OrderEitherVertex(graphp, old) {}
public:
OrderInputsVertex(V3Graph* graphp, AstSenTree* domainp)
: OrderEitherVertex(graphp, NULL, domainp) {
isFromInput(true); // By definition
}
virtual ~OrderInputsVertex() {}
virtual OrderInputsVertex* clone(V3Graph* graphp) const {
return new OrderInputsVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_INPUTS; }
virtual string name() const { return "*INPUTS*"; }
virtual string dotColor() const { return "green"; }
@@ -166,10 +183,14 @@ public:
};
class OrderSettleVertex : public OrderEitherVertex {
OrderSettleVertex(V3Graph* graphp, const OrderSettleVertex& old)
: OrderEitherVertex(graphp, old) {}
public:
OrderSettleVertex(V3Graph* graphp, AstSenTree* domainp)
: OrderEitherVertex(graphp, NULL, domainp) {}
virtual ~OrderSettleVertex() {}
virtual OrderSettleVertex* clone(V3Graph* graphp) const {
return new OrderSettleVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_SETTLE; }
virtual string name() const { return "*SETTLE*"; }
virtual string dotColor() const { return "green"; }
@@ -180,10 +201,15 @@ public:
class OrderLogicVertex : public OrderEitherVertex {
AstNode* m_nodep;
OrderMoveVertex* m_moveVxp;
protected:
OrderLogicVertex(V3Graph* graphp, const OrderLogicVertex& old)
: OrderEitherVertex(graphp, old), m_nodep(old.m_nodep), m_moveVxp(old.m_moveVxp) {}
public:
OrderLogicVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstNode* nodep)
: OrderEitherVertex(graphp, scopep, domainp), m_nodep(nodep), m_moveVxp(NULL) {}
virtual ~OrderLogicVertex() {}
virtual OrderLogicVertex* clone(V3Graph* graphp) const {
return new OrderLogicVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOGIC; }
virtual bool domainMatters() { return true; }
// Accessors
@@ -198,11 +224,14 @@ class OrderVarVertex : public OrderEitherVertex {
AstVarScope* m_varScp;
OrderVarVertex* m_pilNewVertexp; // for processInsLoopNewVar
bool m_isClock; // Used as clock
protected:
OrderVarVertex(V3Graph* graphp, const OrderVarVertex& old)
: OrderEitherVertex(graphp, old)
, m_varScp(old.m_varScp), m_pilNewVertexp(old.m_pilNewVertexp), m_isClock(old.m_isClock) {}
public:
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
, m_pilNewVertexp(NULL), m_isClock(false)
{}
, m_pilNewVertexp(NULL), m_isClock(false) {}
virtual ~OrderVarVertex() {}
virtual OrderVarVertex* clone (V3Graph* graphp) const = 0;
virtual OrderVEdgeType type() const = 0;
@@ -215,66 +244,71 @@ public:
};
class OrderVarStdVertex : public OrderVarVertex {
OrderVarStdVertex(V3Graph* graphp, const OrderVarStdVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarStdVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
: OrderVarVertex(graphp, scopep, varScp) {}
virtual ~OrderVarStdVertex() {}
virtual OrderVarStdVertex* clone(V3Graph* graphp) const {
return new OrderVarStdVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSTD; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarStdVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+"\\n "+varScp()->name());}
virtual string dotColor() const { return "skyblue"; }
virtual bool domainMatters() { return true; }
};
class OrderVarPreVertex : public OrderVarVertex {
OrderVarPreVertex(V3Graph* graphp, const OrderVarPreVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPreVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual ~OrderVarPreVertex() {}
virtual OrderVarPreVertex* clone(V3Graph* graphp) const {
return new OrderVarPreVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPRE; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPreVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" PRE\\n "+varScp()->name());}
virtual string dotColor() const { return "lightblue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarPostVertex : public OrderVarVertex {
OrderVarPostVertex(V3Graph* graphp, const OrderVarPostVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPostVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual OrderVarPostVertex* clone(V3Graph* graphp) const {
return new OrderVarPostVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPOST; }
virtual ~OrderVarPostVertex() {}
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPostVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" POST\\n "+varScp()->name());}
virtual string dotColor() const { return "CadetBlue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarPordVertex : public OrderVarVertex {
OrderVarPordVertex(V3Graph* graphp, const OrderVarPordVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarPordVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarPordVertex(graphp, scopep(), varScp());
}
virtual ~OrderVarPordVertex() {}
virtual OrderVarPordVertex* clone(V3Graph* graphp) const {
return new OrderVarPordVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARPORD; }
virtual string name() const { return (cvtToStr((void*)varScp())+" PORD\\n "+varScp()->name());}
virtual string dotColor() const { return "NavyBlue"; }
virtual bool domainMatters() { return false; }
};
class OrderVarSettleVertex : public OrderVarVertex {
OrderVarSettleVertex(V3Graph* graphp, const OrderVarSettleVertex& old)
: OrderVarVertex(graphp, old) {}
public:
OrderVarSettleVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderVarVertex(graphp, scopep,varScp) {}
virtual ~OrderVarSettleVertex() {}
virtual OrderVarSettleVertex* clone(V3Graph* graphp) const {
return new OrderVarSettleVertex(graphp, *this); }
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_VARSETTLE; }
virtual OrderVarVertex* clone (V3Graph* graphp) const {
return new OrderVarSettleVertex(graphp, scopep(), varScp());
}
virtual string name() const { return (cvtToStr((void*)varScp())+" STL\\n "+varScp()->name());}
virtual string dotColor() const { return "PowderBlue"; }
virtual bool domainMatters() { return false; }
@@ -288,13 +322,18 @@ class OrderLoopBeginVertex : public OrderLogicVertex {
// However, a LoopBeginVertex is not "under" the loop per se, and it may be under another loop.
OrderLoopId m_loopId; // Arbitrary # to ID this loop
uint32_t m_loopColor; // Color # of loop (for debug)
OrderLoopBeginVertex(V3Graph* graphp, const OrderLoopBeginVertex& old)
: OrderLogicVertex(graphp, *this)
, m_loopId(old.m_loopId), m_loopColor(old.m_loopColor) {}
public:
OrderLoopBeginVertex(V3Graph* graphp, AstScope* scopep, AstSenTree* domainp, AstUntilStable* nodep,
OrderLoopId loopId, uint32_t loopColor)
: OrderLogicVertex(graphp, scopep, domainp, nodep)
, m_loopId(loopId), m_loopColor(loopColor) {
}
, m_loopId(loopId), m_loopColor(loopColor) {}
virtual ~OrderLoopBeginVertex() {}
virtual OrderLoopBeginVertex* clone(V3Graph* graphp) const {
return new OrderLoopBeginVertex(graphp, *this);
}
// Methods
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOOPBEGIN; }
virtual string name() const { return "LoopBegin_"+cvtToStr(loopId())+"_c"+cvtToStr(loopColor()); }
@@ -306,17 +345,22 @@ public:
};
class OrderLoopEndVertex : public OrderLogicVertex {
// A end vertex points to the *same nodep* as the Begin,
// as we need it to be a logic vertex for moving, but don't need a permanent node.
// We won't add to the output graph though, so it shouldn't matter.
// A end vertex points to the *same nodep* as the Begin, as we need it to
// be a logic vertex for moving, but don't need a permanent node. We
// won't add to the output graph though, so it shouldn't matter.
OrderLoopBeginVertex* m_beginVertexp; // Corresponding loop begin
OrderLoopEndVertex(V3Graph* graphp, const OrderLoopEndVertex& old)
: OrderLogicVertex(graphp, old), m_beginVertexp(old.m_beginVertexp) {}
public:
OrderLoopEndVertex(V3Graph* graphp, OrderLoopBeginVertex* beginVertexp)
: OrderLogicVertex(graphp, beginVertexp->scopep(), beginVertexp->domainp(), beginVertexp->nodep())
: OrderLogicVertex(graphp, beginVertexp->scopep(),
beginVertexp->domainp(), beginVertexp->nodep())
, m_beginVertexp(beginVertexp) {
inLoop(beginVertexp->loopId());
}
virtual ~OrderLoopEndVertex() {}
virtual OrderLoopEndVertex* clone(V3Graph* graphp) const {
return new OrderLoopEndVertex(graphp, *this); }
// Methods
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_LOOPEND; }
virtual string name() const { return "LoopEnd_"+cvtToStr(inLoop())+"_c"+cvtToStr(loopColor()); }
@@ -342,10 +386,17 @@ protected:
// for the head of the list, see the same var name under OrderVisitor
V3ListEnt<OrderMoveVertex*> m_pomWaitingE; // List of nodes needing inputs to become ready
V3ListEnt<OrderMoveVertex*> m_readyVerticesE;// List of ready under domain/scope
// CONSTRUCTORS
OrderMoveVertex(V3Graph* graphp, const OrderMoveVertex& old)
: V3GraphVertex(graphp, old), m_logicp(old.m_logicp), m_state(old.m_state)
, m_domScopep(old.m_domScopep) {}
public:
OrderMoveVertex(V3Graph* graphp, OrderLogicVertex* logicp)
: V3GraphVertex(graphp), m_logicp(logicp), m_state(POM_WAIT), m_domScopep(NULL) {}
virtual ~OrderMoveVertex() {}
virtual OrderMoveVertex* clone(V3Graph* graphp) const {
return new OrderMoveVertex(graphp, *this);
}
virtual OrderVEdgeType type() const { return OrderVEdgeType::VERTEX_MOVE; }
virtual string dotColor() const { return logicp()->dotColor(); }
virtual string name() const {
@@ -376,18 +427,22 @@ public:
// Edge types
class OrderEdge : public V3GraphEdge {
protected:
OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderEdge& old)
: V3GraphEdge(graphp, fromp, top, old) {}
public:
OrderEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
int weight, bool cutable=false)
: V3GraphEdge(graphp, fromp, top, weight, cutable) {}
virtual ~OrderEdge() {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_STD; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderEdge(graphp, fromp, top, *this);
}
// When ordering combo blocks with stronglyConnected, follow edges not involving pre/pos variables
virtual bool followComboConnected() const { return true; }
virtual bool followSequentConnected() const { return true; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderEdge(graphp, fromp, top, weight(), cutable());
}
static bool followComboConnected(const V3GraphEdge* edgep) {
const OrderEdge* oedgep = dynamic_cast<const OrderEdge*>(edgep);
if (!oedgep) v3fatalSrc("Following edge of non-OrderEdge type");
@@ -403,14 +458,17 @@ public:
class OrderChangeDetEdge : public OrderEdge {
// Edge created from variable to OrderLoopEndVertex
// Indicates a change detect will be required for this loop construct
OrderChangeDetEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderChangeDetEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderChangeDetEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_MEDIUM, false) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_CHANGEDET; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderChangeDetEdge(graphp, fromp, top);
}
virtual ~OrderChangeDetEdge() {}
virtual OrderChangeDetEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderChangeDetEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "blue"; }
};
@@ -418,14 +476,17 @@ class OrderComboCutEdge : public OrderEdge {
// Edge created from output of combo logic
// Breakable if the output var is also a input,
// in which case we'll need a change detect loop around this var.
OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderComboCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderComboCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_COMBOCUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderComboCutEdge(graphp, fromp, top);
}
virtual ~OrderComboCutEdge() {}
virtual OrderComboCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderComboCutEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "yellowGreen"; }
virtual bool followComboConnected() const { return true; }
virtual bool followSequentConnected() const { return true; }
@@ -435,14 +496,17 @@ class OrderPostCutEdge : public OrderEdge {
// Edge created from output of post assignment
// Breakable if the output var feeds back to input combo logic or another clock pin
// in which case we'll need a change detect loop around this var.
OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderPostCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderPostCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_COMBO, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_POSTCUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPostCutEdge(graphp, fromp, top);
}
virtual ~OrderPostCutEdge() {}
virtual OrderPostCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPostCutEdge(graphp, fromp, top, *this);
}
virtual string dotColor() const { return "PaleGreen"; }
virtual bool followComboConnected() const { return false; }
virtual bool followSequentConnected() const { return true; }
@@ -452,16 +516,18 @@ class OrderPreCutEdge : public OrderEdge {
// Edge created from var_PREVAR->consuming logic vertex
// Always breakable, just results in performance loss
// in which case we can't optimize away the pre/post delayed assignments
OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top,
const OrderPreCutEdge& old)
: OrderEdge(graphp, fromp, top, old) {}
public:
OrderPreCutEdge(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top)
: OrderEdge(graphp, fromp, top, WEIGHT_PRE, CUTABLE) {}
virtual OrderVEdgeType type() const { return OrderVEdgeType::EDGE_PRECUT; }
virtual OrderEdge* clone (V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPreCutEdge(graphp, fromp, top);
virtual OrderPreCutEdge* clone(V3Graph* graphp, V3GraphVertex* fromp, V3GraphVertex* top) const {
return new OrderPreCutEdge(graphp, fromp, top, *this);
}
virtual ~OrderPreCutEdge() {}
virtual string dotColor() const { return "khaki"; }
virtual bool followComboConnected() const { return false; }
virtual bool followSequentConnected() const { return false; }
};
+5 -4
View File
@@ -94,8 +94,8 @@ private:
if (varp->isGParam()) {
char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[ch]*256 + ch);
usedLetter[ch]++;
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
usedLetter[static_cast<int>(ch)]++;
}
}
}
@@ -324,13 +324,13 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
if (nodep->paramsp()) {
UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants
if (debug()>9) nodep->dumpTree(cout,"cell:\t");
if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
// Evaluate all module constants
V3Const::constifyParamsEdit(nodep);
// Make sure constification worked
// Must be a separate loop, as constant conversion may have changed some pointers.
//if (debug()) nodep->dumpTree(cout,"cel2:\t");
//if (debug()) nodep->dumpTree(cout,"-cel2:\t");
string longname = nodep->modp()->name();
bool any_overrides = false;
longname += "_";
@@ -442,6 +442,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Delete the parameters from the cell; they're not relevant any longer.
nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
}
// Now remember to process the child module at the end of the module
+1
View File
@@ -77,6 +77,7 @@ struct V3ParseBisonYYSType {
AstPackageRef* packagerefp;
AstParseRef* parserefp;
AstPatMember* patmemberp;
AstPattern* patternp;
AstPin* pinp;
AstRange* rangep;
AstSenTree* sentreep;
+20
View File
@@ -70,6 +70,26 @@ protected:
s_preprocp->defineCmdLine(prefl,"verilator3", "1"); // LEAK_OK
s_preprocp->defineCmdLine(prefl,"systemc_clock", "/*verilator systemc_clock*/"); // LEAK_OK
s_preprocp->defineCmdLine(prefl,"coverage_block_off", "/*verilator coverage_block_off*/"); // LEAK_OK
if (prefl->language().systemVerilog()) {
// Synthesis compatibility
s_preprocp->defineCmdLine(prefl,"SYSTEMVERILOG", "1"); // LEAK_OK
// IEEE predefined
s_preprocp->defineCmdLine(prefl,"SV_COV_START", "0");
s_preprocp->defineCmdLine(prefl,"SV_COV_STOP", "1");
s_preprocp->defineCmdLine(prefl,"SV_COV_RESET", "2");
s_preprocp->defineCmdLine(prefl,"SV_COV_CHECK", "3");
s_preprocp->defineCmdLine(prefl,"SV_COV_MODULE", "10");
s_preprocp->defineCmdLine(prefl,"SV_COV_HIER", "11");
s_preprocp->defineCmdLine(prefl,"SV_COV_ASSERTION", "20");
s_preprocp->defineCmdLine(prefl,"SV_COV_FSM_STATE", "21");
s_preprocp->defineCmdLine(prefl,"SV_COV_STATEMENT", "22");
s_preprocp->defineCmdLine(prefl,"SV_COV_TOGGLE", "23");
s_preprocp->defineCmdLine(prefl,"SV_COV_OVERFLOW", "-2");
s_preprocp->defineCmdLine(prefl,"SV_COV_ERROR", "-1");
s_preprocp->defineCmdLine(prefl,"SV_COV_NOCOV", "0");
s_preprocp->defineCmdLine(prefl,"SV_COV_OK", "1");
s_preprocp->defineCmdLine(prefl,"SV_COV_PARTIAL", "2");
}
}
}
+8 -2
View File
@@ -46,8 +46,10 @@ private:
// NODE STATE
// AstVar::user1p -> AstVarScope replacement for this variable
// AstTask::user2p -> AstTask*. Replacement task
// AstVar::user3p -> AstVarScope for packages
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// STATE, inside processing a single module
AstNodeModule* m_modp; // Current module
@@ -201,10 +203,12 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
// Make new scope variable
if (!nodep->user1p()) {
if (m_modp->castPackage()
? !nodep->user3p() : !nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);
nodep->user1p(varscp);
if (m_modp->castPackage()) nodep->user3p(varscp);
m_scopep->addVarp(varscp);
}
}
@@ -212,7 +216,9 @@ private:
// VarRef needs to point to VarScope
// Make sure variable has made user1p.
nodep->varp()->accept(*this);
AstVarScope* varscp = (AstVarScope*)nodep->varp()->user1p();
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
}
+14 -13
View File
@@ -76,8 +76,8 @@ class SliceCloneVisitor : public AstNVisitor {
if (m_vecIdx == (int)m_selBits.size()) {
m_selBits.push_back(vector<unsigned>());
AstVar* varp = m_refp->varp();
pair<uint32_t,uint32_t> arrDim = varp->dtypep()->dimensions();
uint32_t dimensions = arrDim.first + arrDim.second;
pair<uint32_t,uint32_t> arrDim = varp->dtypep()->dimensions(false);
uint32_t dimensions = arrDim.second;
for (uint32_t i = 0; i < dimensions; ++i) {
m_selBits[m_vecIdx].push_back(0);
}
@@ -233,6 +233,7 @@ class SliceVisitor : public AstNVisitor {
if (!selp) {
nodep->user1p(fromp->castVarRef());
selp = NULL;
break;
} else {
fromp = selp->fromp();
if (fromp) ++dim;
@@ -252,7 +253,7 @@ class SliceVisitor : public AstNVisitor {
AstNode* topp = nodep;
for (unsigned i = start; i < start + count; ++i) {
AstNodeDType* dtypep = varp->dtypep()->dtypeDimensionp(i-1);
AstArrayDType* adtypep = dtypep->castArrayDType();
AstUnpackArrayDType* adtypep = dtypep->castUnpackArrayDType();
if (!adtypep) nodep->v3fatalSrc("insertImplicit tried to expand an array without an ArrayDType");
vlsint32_t msb = adtypep->msb();
vlsint32_t lsb = adtypep->lsb();
@@ -291,8 +292,8 @@ class SliceVisitor : public AstNVisitor {
// The LHS/RHS of an Assign may be to a Var that is an array. In this
// case we need to create a slice accross the entire Var
if (m_assignp && !nodep->backp()->castArraySel()) {
pair<uint32_t,uint32_t> arrDim = nodep->varp()->dtypep()->dimensions();
uint32_t dimensions = arrDim.first + arrDim.second;
pair<uint32_t,uint32_t> arrDim = nodep->varp()->dtypep()->dimensions(false);
uint32_t dimensions = arrDim.second; // unpacked only
if (dimensions > 0) {
AstVarRef* clonep = nodep->cloneTree(false);
clonep->user1p(nodep);
@@ -306,7 +307,7 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstExtend* nodep, AstNUser*) {
m_extend = true;
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions");
m_assignError = true;
}
nodep->iterateChildren(*this);
@@ -325,8 +326,8 @@ class SliceVisitor : public AstNVisitor {
if (nodep->user3()) return; // Prevent recursion on just created nodes
unsigned dim = explicitDimensions(nodep);
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
pair<uint32_t,uint32_t> arrDim = refp->varp()->dtypep()->dimensions();
uint32_t implicit = (arrDim.first + arrDim.second) - dim;
pair<uint32_t,uint32_t> arrDim = refp->varp()->dtypep()->dimensions(false);
uint32_t implicit = (arrDim.second) - dim;
if (implicit > 0) {
AstArraySel* newp = insertImplicit(nodep->cloneTree(false), dim+1, implicit);
nodep->replaceWith(newp); nodep = newp;
@@ -337,7 +338,7 @@ class SliceVisitor : public AstNVisitor {
m_assignp->v3error("Slices of arrays in assignments must have the same unpacked dimensions");
} else if (!m_assignp->user2()) {
if (m_extend && clones > 1 && !m_assignError) {
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions");
m_assignError = true;
}
if (clones > 1 && !refp->lvalue() && refp->varp() == m_lhsVarRefp->varp()
@@ -353,7 +354,7 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstSel* nodep, AstNUser*) {
m_extend = true;
if (m_assignp && m_assignp->user2() > 1 && !m_assignError) {
m_assignp->v3error("Unsupported: Assignment between packed arrays of different dimensions");
m_assignp->v3error("Unsupported: Assignment between unpacked arrays of different dimensions");
m_assignError = true;
}
nodep->iterateChildren(*this);
@@ -427,13 +428,13 @@ class SliceVisitor : public AstNVisitor {
nodep->iterateChildren(*this);
} else {
AstVarRef* refp = findVarRefRecurse(nodep->lhsp());
ArrayDimensions varDim = refp->varp()->dtypep()->dimensions();
ArrayDimensions varDim = refp->varp()->dtypep()->dimensions(false);
if ((int)(dim - varDim.second) < 0) {
// Unpacked dimensions are referenced first, make sure we have them all
nodep->v3error("Unary operator used across unpacked dimensions");
} else if ((int)(dim - (varDim.first + varDim.second)) < 0) {
} else if ((int)(dim - (varDim.second)) < 0) {
// Implicit packed dimensions are allowed, make them explicit
uint32_t newDim = (varDim.first + varDim.second) - dim;
uint32_t newDim = (varDim.second) - dim;
AstNode* clonep = nodep->lhsp()->cloneTree(false);
clonep->user1p(refp);
AstNode* newp = insertImplicit(clonep, dim+1, newDim);
+2 -2
View File
@@ -93,7 +93,7 @@ private:
nodep->iterateChildren(*this);
if (m_counting && nodep->dtypep()) {
if (nodep->isUsedClock()) ++m_statVarClock;
if (nodep->dtypeSkipRefp()->castArrayDType()) ++m_statVarArray;
if (nodep->dtypeSkipRefp()->castUnpackArrayDType()) ++m_statVarArray;
else m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes();
if (int(m_statVarWidths.size()) <= nodep->width()) {
m_statVarWidths.resize(nodep->width()+5);
@@ -197,7 +197,7 @@ public:
V3Stats::addStat(m_stage, "Instruction count, TOTAL", m_statInstr);
V3Stats::addStat(m_stage, "Instruction count, fast", m_statInstrFast);
// Vars
V3Stats::addStat(m_stage, "Vars, arrayed", m_statVarArray);
V3Stats::addStat(m_stage, "Vars, unpacked arrayed", m_statVarArray);
V3Stats::addStat(m_stage, "Vars, clock attribute", m_statVarClock);
V3Stats::addStat(m_stage, "Var space, non-arrays, bytes", m_statVarBytes);
if (m_statVarScpBytes) {
+2 -2
View File
@@ -225,10 +225,10 @@ public:
VSymMap doneSyms;
os<<"SymEnt Dump:\n";
m_symRootp->dumpIterate(os, doneSyms, indent, 9999, "$root");
bool first = false;
bool first = true;
for (SymStack::iterator it = m_symsp.begin(); it != m_symsp.end(); ++it) {
if (doneSyms.find(*it) == doneSyms.end()) {
if (!first++) os<<"%%Warning: SymEnt Orphans:\n";
if (first) { first=false; os<<"%%Warning: SymEnt Orphans:\n"; }
(*it)->dumpIterate(os, doneSyms, indent, 9999, "Orphan");
}
}
+8 -7
View File
@@ -189,10 +189,10 @@ private:
// Change it variable
FileLine* fl = nodep->fileline();
AstNodeDType* dtypep
= new AstArrayDType (fl,
nodep->findBitDType(m_outVarps.size(),
m_outVarps.size(), AstNumeric::UNSIGNED),
new AstRange (fl, VL_MASK_I(m_inWidth), 0), false);
= new AstUnpackArrayDType (fl,
nodep->findBitDType(m_outVarps.size(),
m_outVarps.size(), AstNumeric::UNSIGNED),
new AstRange (fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
AstVar* chgVarp
= new AstVar (fl, AstVarType::MODULETEMP,
@@ -237,8 +237,8 @@ private:
AstVar* outvarp = outvscp->varp();
FileLine* fl = nodep->fileline();
AstNodeDType* dtypep
= new AstArrayDType (fl, outvarp->dtypep(),
new AstRange (fl, VL_MASK_I(m_inWidth), 0), false);
= new AstUnpackArrayDType (fl, outvarp->dtypep(),
new AstRange (fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
AstVar* tablevarp
= new AstVar (fl, AstVarType::MODULETEMP,
@@ -349,7 +349,8 @@ private:
AstVarScope* vsc2p= *it;
AstVar* var2p = vsc2p->varp();
if (var1p->width() == var2p->width()
&& var1p->dtypep()->arrayElements() == var2p->dtypep()->arrayElements()) {
&& (var1p->dtypep()->arrayUnpackedElements()
== var2p->dtypep()->arrayUnpackedElements())) {
AstNode* init1p = var1p->valuep()->castInitArray();
AstNode* init2p = var2p->valuep()->castInitArray();
if (init1p->sameTree(init2p)) {
+3 -3
View File
@@ -75,10 +75,10 @@ private:
return "Inlined leading underscore";
}
if ((int)nodep->width() > v3Global.opt.traceMaxWidth()) return "Wide bus > --trace-max-width bits";
if ((int)nodep->dtypep()->arrayElements() > v3Global.opt.traceMaxArray()) return "Wide memory > --trace-max-array ents";
if ((int)nodep->dtypep()->arrayUnpackedElements() > v3Global.opt.traceMaxArray()) return "Wide memory > --trace-max-array ents";
if (!(nodep->dtypeSkipRefp()->castBasicDType()
|| (nodep->dtypeSkipRefp()->castArrayDType()
&& (nodep->dtypeSkipRefp()->castArrayDType()->subDTypep()
|| (nodep->dtypeSkipRefp()->castUnpackArrayDType()
&& (nodep->dtypeSkipRefp()->castUnpackArrayDType()->subDTypep()
->skipRefp()->castBasicDType())))) {
return "Unsupported: Multi-dimensional array";
}
+42 -38
View File
@@ -20,7 +20,7 @@
// V3Tristate's Transformations:
//
// Modify the design to expand tristate logic into its
// corresponding two state reprasentation. At the lowest levels,
// corresponding two state representation. At the lowest levels,
//
// In detail:
//
@@ -46,12 +46,15 @@
// logic that they may go through until they hit the module level. At
// the module level, all the output enable signals from what can be
// many tristate drivers are combined together to produce a single
// driver and output enable. If the signal propigates up into higher
// driver and output enable. If the signal propagates up into higher
// modules, then new ports are created with for the signal with
// suffixes __en and __out. The original port is turned from an inout
// to an input and the __out port carries the output driver signal and
// the __en port carried the output enable for that driver.
//
// Note 1800-2012 adds user defined resolution functions. This suggests
// long term this code should be scoped-based and resolve all nodes at once
// rather than hierarchically.
//*************************************************************************
#include "config_build.h"
@@ -222,6 +225,7 @@ public:
}
}
m_graph.clear();
AstNode::user5ClearTree(); // Wipe all node user5p's that point to vertexes
}
void graphWalk(AstNodeModule* nodep) {
//if (debug()>=9) m_graph.dumpDotFilePrefixed("tri_pre__"+nodep->name());
@@ -252,7 +256,7 @@ public:
TristateVertex* vertexp = (TristateVertex*)(nodep->user5p());
if (!vertexp) {
// Not v3errorSrc as no reason to stop the world
nodep->v3error("Unsupported tristate constuct (not in propagation graph): "<<nodep->prettyTypeName());
nodep->v3error("Unsupported tristate construct (not in propagation graph): "<<nodep->prettyTypeName());
} else {
// We don't warn if no vertexp->isTristate() as the creation process makes midling nodes that don't have it set
vertexp->processed(true);
@@ -445,7 +449,7 @@ class TristateVisitor : public TristateBaseVisitor {
} else {
if (oldpullp->direction() != pullp->direction()) {
pullp->v3error("Unsupported: Conflicting pull directions.");
oldpullp->v3error("... Location of conflicing pull.");
oldpullp->v3error("... Location of conflicting pull.");
}
}
}
@@ -494,6 +498,7 @@ class TristateVisitor : public TristateBaseVisitor {
// Now go through the lhs driver map and generate the output
// enable logic for any tristates.
// Note there might not be any drivers.
for (VarMap::iterator nextit, it = m_lhsmap.begin(); it != m_lhsmap.end(); it = nextit) {
nextit = it; ++nextit;
AstVar* invarp = (*it).first;
@@ -508,7 +513,7 @@ class TristateVisitor : public TristateBaseVisitor {
continue;
}
m_statTriSigs++;
++m_statTriSigs;
m_tgraph.didProcess(invarp);
UINFO(8, " TRISTATE EXPANDING:" << invarp << endl);
@@ -518,8 +523,8 @@ class TristateVisitor : public TristateBaseVisitor {
// if this is the top level so that we can force the final
// tristate resolution at the top.
AstVar* envarp = NULL;
AstVar* outvarp = NULL;
AstVar* lhsp = invarp;
AstVar* outvarp = NULL; // __out
AstVar* lhsp = invarp; // Variable to assign drive-value to (<in> or __out)
if (!nodep->isTop() && invarp->isIO()) {
// This var becomes an input
invarp->varType2In(); // convert existing port to type input
@@ -589,12 +594,10 @@ class TristateVisitor : public TristateBaseVisitor {
undrivenp = ((!undrivenp) ? tmp
: new AstAnd(nodep->fileline(), tmp, undrivenp));
}
if (!undrivenp) { // No drivers on the bus
V3Number ones(nodep->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(nodep->fileline(), ones);
}
if (!outvarp) {
// This is the final resolution of the tristate, so we apply
// the pull direction to any undriven pins.
@@ -617,7 +620,7 @@ class TristateVisitor : public TristateBaseVisitor {
new AstVarRef(envarp->fileline(),
envarp, true), enp));
}
// __out (child) or <in> (parent) = drive-value expression
AstNode* assp = new AstAssignW(lhsp->fileline(),
new AstVarRef(lhsp->fileline(),
lhsp,
@@ -661,7 +664,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstConst* enp = new AstConst(fl, numz0);
nodep->replaceWith(newconstp);
pushDeletep(nodep); nodep = NULL;
newconstp->user1p(enp);
newconstp->user1p(enp); // propagate up constant with non-Z bits as 1
}
}
}
@@ -698,7 +701,7 @@ class TristateVisitor : public TristateBaseVisitor {
// two expressions with the same conditional.
AstNode* enp = new AstCond(nodep->fileline(), condp->cloneTree(false), en1p, en2p);
UINFO(9," newcond "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up COND(lhsp->enable, rhsp->enable)
expr1p->user1p(NULL);
expr2p->user1p(NULL);
}
@@ -735,7 +738,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstNode* enp = new AstSel(nodep->fileline(), en1p,
nodep->lsbp()->cloneTree(true), nodep->widthp()->cloneTree(true));
UINFO(9," newsel "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up SEL(fromp->enable, value)
m_tgraph.didProcess(nodep);
}
}
@@ -783,7 +786,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstNode* en2p = getEnp(expr2p);
AstNode* enp = new AstConcat(nodep->fileline(), en1p, en2p);
UINFO(9," newconc "<<enp<<endl);
nodep->user1p(enp);
nodep->user1p(enp); // propagate up CONCAT(lhsp->enable, rhsp->enable)
expr1p->user1p(NULL);
expr2p->user1p(NULL);
}
@@ -925,14 +928,14 @@ class TristateVisitor : public TristateBaseVisitor {
checkUnhandled(nodep);
// Unsupported: A === 3'b000 should compare with the enables, but we don't do
// so at present, we only compare if there is a z in the equation.
// Otherwise we'd need to attach an enable to every signal, then optimize then
// Otherwise we'd need to attach an enable to every signal, then optimize them
// away later when we determine the signal has no tristate
nodep->iterateChildren(*this);
UINFO(9,dbgState()<<nodep<<endl);
AstConst* constp = nodep->lhsp()->castConst(); // Constification always moves const to LHS
AstVarRef* varrefp = nodep->rhsp()->castVarRef(); // Input variable
if (constp && constp->user1p() && varrefp) {
// 3'b1z0 -> ((3'b101 == __en) && (3'b100 == __in))
// 3'b1z0 -> ((3'b101 == in__en) && (3'b100 == in))
varrefp->unlinkFrBack();
FileLine* fl = nodep->fileline();
V3Number oneIfEn = constp->user1p()->castNode()->castConst()->num(); // visit(AstConst) already split into en/ones
@@ -1021,19 +1024,20 @@ class TristateVisitor : public TristateBaseVisitor {
// ENABLE: -> (VARREF(trisig__pinen)
// Added complication is the signal may be an output/inout or just input with tie off (or not) up top
// PIN PORT NEW PORTS AND CONNECTIONS
// N/C input in(from-resolver), __out(to-resolver-only), __en(to-resolver-only)
// N/C input in(from-resolver), __en(to-resolver-only), __out(to-resolver-only)
// N/C inout Spec says illegal
// N/C output Unsupported; Illegal?
// wire input in(from-resolver-with-wire-value), __out(to-resolver-only), __en(to-resolver-only)
// wire inout in, __out, __en
// wire output in, __out, __en
// const input in(from-resolver-with-const-value), __out(to-resolver-only), __en(to-resolver-only)
// const inout Spec says illegal
// const output Unsupported; Illegal?
// wire input in(from-resolver-with-wire-value), __en(from-resolver-wire), __out(to-resolver-only)
// wire inout in, __en, __out
// wire output in, __en, __out
// const input in(from-resolver-with-const-value), __en(from-resolver-const), __out(to-resolver-only)
// const inout Spec says illegal
// const output Unsupported; Illegal?
virtual void visit(AstPin* nodep, AstNUser*) {
if (m_graphing) {
if (nodep->user2() & U2_GRAPHING) return; // This pin is already expanded
nodep->user2(U2_GRAPHING);
// Find child module's new variables.
AstVar* enModVarp = (AstVar*) nodep->modVarp()->user1p();
if (!enModVarp) {
if (nodep->exprp()) {
@@ -1048,7 +1052,7 @@ class TristateVisitor : public TristateBaseVisitor {
if (debug()>=9) nodep->dumpTree(cout,"-pin-pre: ");
// Empty/in-only; need Z to propagate
bool inOnlyProcessing = (nodep->exprp()
bool inDeclProcessing = (nodep->exprp()
&& nodep->modVarp()->isInOnly()
// Need to consider the original state instead of current state
// as we converted tristates to inputs, which do not want to have this.
@@ -1060,7 +1064,7 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->modVarp()->isOutput()));
m_tgraph.setTristate(ucVarp);
// We don't need a driver on the wire; the lack of one will default to tristate
} else if (inOnlyProcessing) { // Not an input that was a converted tristate
} else if (inDeclProcessing) { // Not an input that was a converted tristate
// Input only may have driver in underneath module which would stomp
// the input value. So make a temporary connection.
AstAssignW* reAssignp = V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp, true, true);
@@ -1077,7 +1081,7 @@ class TristateVisitor : public TristateBaseVisitor {
AstVar* enVarp = new AstVar(nodep->fileline(),
AstVarType::MODULETEMP,
nodep->name() + "__en" + cvtToStr(m_unique++),
VFlagLogicPacked(), enModVarp->width());
VFlagBitPacked(), enModVarp->width());
UINFO(9," newenv "<<enVarp<<endl);
AstPin* enpinp = new AstPin(nodep->fileline(),
nodep->pinNum(),
@@ -1107,9 +1111,9 @@ class TristateVisitor : public TristateBaseVisitor {
outpinp->user2(U2_BOTH); // don't iterate the pin later
nodep->addNextHere(outpinp);
// Simplify
if (inOnlyProcessing) { // Not an input that was a converted tristate
if (inDeclProcessing) { // Not an input that was a converted tristate
// The pin is an input, but we need an output
// The if() above is neded because the Visitor is simple, it will flip ArraySel's and such,
// The if() above is needed because the Visitor is simple, it will flip ArraySel's and such,
// but if the pin is an input the earlier reconnectSimple made it a VarRef without any ArraySel, etc
TristatePinVisitor visitor (outexprp, m_tgraph, true);
}
@@ -1127,29 +1131,29 @@ class TristateVisitor : public TristateBaseVisitor {
if (debug()>=9 && inAssignp) inAssignp->dumpTree(cout,"-pin-as: ");
// Connect enable to output signal
AstVarRef* outrefp;
AstVarRef* exprrefp; // Tristate variable that the Pin's expression refers to
if (!outAssignp) {
outrefp = outpinp->exprp()->castVarRef();
exprrefp = outpinp->exprp()->castVarRef();
} else {
outrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin
exprrefp = outAssignp->rhsp()->castVarRef(); // This should be the same var as the output pin
}
if (!outrefp) { // deal with simple varref port
if (!exprrefp) { // deal with simple varref port
// pinReconnect should have converted this
nodep->v3error("Unsupported tristate port expression: "<<nodep->exprp()->prettyTypeName());
} else {
UINFO(9,"outref "<<outrefp<<endl);
outrefp->user1p(enrefp); // Mark as now tristated; iteration will pick it up from there
UINFO(9,"outref "<<exprrefp<<endl);
exprrefp->user1p(enrefp); // Mark as now tristated; iteration will pick it up from there
if (!outAssignp) {
mapInsertLhsVarRef(outrefp); // insertTristates will convert
mapInsertLhsVarRef(exprrefp); // insertTristates will convert
// // to a varref to the __out# variable
} // else the assignment deals with the connection
}
// Propagate any pullups/pulldowns upwards if necessary
if (outrefp) {
if (exprrefp) {
if (AstPull* pullp = (AstPull*) nodep->modVarp()->user3p()) {
UINFO(9, "propagate pull on "<<outrefp<<endl);
setPullDirection(outrefp->varp(), pullp);
UINFO(9, "propagate pull on "<<exprrefp<<endl);
setPullDirection(exprrefp->varp(), pullp);
}
}
+21 -14
View File
@@ -168,6 +168,11 @@ private:
m_constXCvt = true;
nodep->bodysp()->iterateAndNext(*this);
}
virtual void visit(AstNodeDType* nodep, AstNUser*) {
m_constXCvt = false; // Avoid loosing the X's in casex
nodep->iterateChildren(*this);
m_constXCvt = true;
}
void visitEqNeqCase(AstNodeBiop* nodep) {
UINFO(4," N/EQCASE->EQ "<<nodep<<endl);
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
@@ -283,6 +288,7 @@ private:
} else {
// Make a Vxrand variable
// We use the special XTEMP type so it doesn't break pure functions
if (!m_modp) nodep->v3fatalSrc("X number not under module");
string newvarname = ((string)"__Vxrand"
+cvtToStr(m_modp->varNumGetInc()));
AstVar* newvarp
@@ -323,16 +329,14 @@ private:
nodep->iterateChildren(*this);
if (!nodep->user1SetOnce()) {
// Guard against reading/writing past end of bit vector array
int maxmsb = 0;
bool lvalue = false;
AstNode* basefromp = AstArraySel::baseFromp(nodep);
bool lvalue = false;
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
lvalue = varrefp->lvalue();
maxmsb = (varrefp->varp()->width()-1);
} else {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
maxmsb = basefromp->width()-1;
}
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
int maxmsb = nodep->fromp()->dtypep()->width()-1;
int maxlsb = maxmsb - nodep->width() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
@@ -375,22 +379,25 @@ private:
if (debug()==9) nodep->dumpTree(cout,"-in: ");
// Guard against reading/writing past end of arrays
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
int dimension = AstArraySel::dimension(nodep->fromp());
int maxmsb = 0;
bool lvalue = false;
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
AstArrayDType* adtypep = varrefp->varp()->dtypep()->dtypeDimensionp(dimension)->castArrayDType();
if (!adtypep) nodep->v3fatalSrc("ArraySel to type without array at same depth");
lvalue = varrefp->lvalue();
maxmsb = adtypep->elementsConst()-1;
} else if (AstConst* lhconstp = basefromp->castConst()) {
} else if (basefromp->castConst()) {
// If it's a PARAMETER[bit], then basefromp may be a constant instead of a varrefp
maxmsb = lhconstp->width();
} else {
nodep->v3fatalSrc("No VarRef or Const under ArraySel\n");
}
// Find range of dtype we are selecting from
int declElements = -1;
AstNodeDType* dtypep = nodep->fromp()->dtypep()->skipRefp();
if (!dtypep) nodep->v3fatalSrc("Select of non-selectable type");
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
declElements = adtypep->elementsConst();
} else {
nodep->v3error("Select from non-array "<<dtypep->prettyTypeName());
}
if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb);
V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), declElements-1);
// See if the condition is constant true
AstNode* condp = new AstLte (nodep->fileline(),
+338 -73
View File
@@ -95,7 +95,9 @@ public:
WidthVP(int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(NULL), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, Stage stage)
: m_width(0), m_widthMin(0), m_dtypep(dtypep), m_stage(stage) {}
: m_width(dtypep->width()), m_widthMin(dtypep->widthMin()), m_dtypep(dtypep), m_stage(stage) {}
WidthVP(AstNodeDType* dtypep, int width, int widthMin, Stage stage)
: m_width(width), m_widthMin(widthMin), m_dtypep(dtypep), m_stage(stage) {}
int width() const { return m_width; }
int widthMin() const { return m_widthMin?m_widthMin:m_width; }
AstNodeDType* dtypep() const { return m_dtypep; }
@@ -115,12 +117,11 @@ private:
// STATE
bool m_paramsOnly; // Computing parameter value; limit operation
AstRange* m_cellRangep; // Range for arrayed instantiations, NULL for normal instantiations
AstNodeCase* m_casep; // Current case statement CaseItem is under
AstFunc* m_funcp; // Current function
AstInitial* m_initialp; // Current initial block
AstAttrOf* m_attrp; // Current attribute
AstNodeDType* m_assDTypep; // Assign LHS data type for assignment pattern
bool m_doGenerate; // Do errors later inside generate statement
int m_dtTables; // Number of created data type tables
// CLASSES
#define ANYSIZE 0
@@ -359,10 +360,25 @@ private:
}
}
virtual void visit(AstRange* nodep, AstNUser* vup) {
// If there's an edit, then processes the edit'ee (can't just rely on iterateChildren because sometimes we for(...) here ourself
// Real: Not allowed
// Signed: unsigned output, input either
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
// Convert all range values to constants
UINFO(6,"RANGE "<<nodep<<endl);
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant");
checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant");
int msb = nodep->msbConst();
int lsb = nodep->lsbConst();
if (msb<lsb) {
// Little endian bits are legal, just remember to swap
// Warning is in V3Width to avoid false warnings when in "off" generate if's
nodep->littleEndian(!nodep->littleEndian());
// Internally we'll always have msb() be the greater number
// We only need to correct when doing [] AstSel extraction,
// and when tracing the vector.
nodep->msbp()->swapWith(nodep->lsbp());
}
if (vup->c()->prelim()) {
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
@@ -371,7 +387,7 @@ private:
int width = nodep->elementsConst();
if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"<<hex<<width);
// Note width() not set on range; use elementsConst()
if (nodep->littleEndian()) {
if (nodep->littleEndian() && !nodep->backp()->castUnpackArrayDType()) {
nodep->v3warn(LITENDIAN,"Little bit endian vector: MSB < LSB of bit range: "<<nodep->lsbConst()<<":"<<nodep->msbConst());
}
}
@@ -395,7 +411,7 @@ private:
nodep->dtypeSetLogicBool(); return;
}
int width = nodep->widthConst();
nodep->dtypeSetLogicSized(width,width,AstNumeric::UNSIGNED);
if (!nodep->dtypep()) nodep->v3fatalSrc("dtype wasn't set") // by V3WidthSel
if (nodep->lsbp()->castConst()
&& nodep->msbConst() < nodep->lsbConst()) {
nodep->v3error("Unsupported: MSB < LSB of bit extract: "
@@ -415,31 +431,29 @@ private:
}
// Check bit indexes.
// What is the MSB? We want the true MSB, not one starting at 0,
// because a 4 bit index is required to look at a one-bit variable[15:15]
// because a 4 bit index is required to look at a one-bit variable[15:15] and 5 bits for [15:-2]
int frommsb = nodep->fromp()->width() - 1;
int fromlsb = 0;
AstNodeVarRef* varrp = nodep->fromp()->castNodeVarRef();
if (varrp
&& varrp->varp()->basicp()
&& varrp->varp()->basicp()->isRanged()) { // Selecting a bit from a multibit register
frommsb = varrp->varp()->basicp()->msbMaxSelect(); // Corrected for negative lsb
fromlsb = varrp->varp()->basicp()->lsb();
int elw = nodep->declElWidth(); // Must adjust to tell user bit ranges
if (nodep->declRange().ranged()) {
frommsb = nodep->declRange().hiMaxSelect()*elw + (elw-1); // Corrected for negative lsb
fromlsb = nodep->declRange().lo()*elw;
} else {
//nodep->v3fatalSrc("Should have been declRanged in V3WidthSel");
}
int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,FINAL).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,FINAL).p());
if (widthBad(nodep->lsbp(),selwidth,selwidth)
&& nodep->lsbp()->width()!=32) {
nodep->v3warn(WIDTH,"Bit extraction of var["<<frommsb<<":"<<fromlsb<<"] requires "
<<selwidth<<" bit index, not "
<<nodep->lsbp()->width()
<<(nodep->lsbp()->width()!=nodep->lsbp()->widthMin()
?" or "+cvtToStr(nodep->lsbp()->widthMin()):"")
<<" bits.");
if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) {
nodep->v3warn(WIDTH,"Bit extraction of var["<<(frommsb/elw)<<":"<<(fromlsb/elw)<<"] requires "
<<(selwidth/elw)<<" bit index, not "
<<(nodep->lsbp()->width()/elw)
<<(nodep->lsbp()->width()!=nodep->lsbp()->widthMin()
?" or "+cvtToStr(nodep->lsbp()->widthMin()/elw):"")
<<" bits.");
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
}
}
if (nodep->lsbp()->castConst() && nodep->msbConst() > frommsb) {
@@ -458,8 +472,6 @@ private:
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<frommsb<<":"<<fromlsb);
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related dtype: "<<varrp->varp()->dtypep()<<endl);
}
}
// iterate FINAL is two blocks above
@@ -482,15 +494,11 @@ private:
checkCvtUS(nodep->bitp());
//
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
int dimension = AstArraySel::dimension(nodep->fromp());
AstNodeVarRef* varrp = basefromp->castNodeVarRef();
if (!varrp) nodep->v3fatalSrc("No VarRef found under ArraySel(s)");
//
int frommsb;
int fromlsb;
AstNodeDType* ddtypep = varrp->varp()->dtypep()->dtypeDimensionp(dimension);
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
if (AstUnpackArrayDType* adtypep = fromDtp->castUnpackArrayDType()) {
frommsb = adtypep->msb();
fromlsb = adtypep->lsb();
if (fromlsb>frommsb) {int t=frommsb; frommsb=fromlsb; fromlsb=t; }
@@ -499,6 +507,8 @@ private:
nodep->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
}
else {
// Note PackArrayDType doesn't use an ArraySel but a normal Sel.
UINFO(1," Related dtype: "<<fromDtp<<endl);
nodep->v3fatalSrc("Array reference exceeds dimension of array");
frommsb = fromlsb = 0;
}
@@ -514,8 +524,7 @@ private:
<<" bits.");
if (!nodep->fileline()->warnIsOff(V3ErrorCode::WIDTH)) {
UINFO(1," Related node: "<<nodep<<endl);
if (varrp) UINFO(1," Related var: "<<varrp->varp()<<endl);
if (varrp) UINFO(1," Related depth: "<<dimension<<" dtype: "<<ddtypep<<endl);
UINFO(1," Related dtype: "<<nodep->dtypep()<<endl);
}
}
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
@@ -524,22 +533,34 @@ private:
virtual void visit(AstSelBit* nodep, AstNUser* vup) {
// Just a quick check as after V3Param these nodes instead are AstSel's
nodep->fromp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->rhsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->thsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->attrp()->iterateAndNext(*this,WidthVP(0,0,FINAL).p());
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelBit should disappear after widthSel");
}
virtual void visit(AstSelExtract* nodep, AstNUser* vup) {
// Just a quick check as after V3Param these nodes instead are AstSel's
nodep->fromp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->rhsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->thsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->attrp()->iterateAndNext(*this,WidthVP(0,0,FINAL).p());
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelExtract should disappear after widthSel");
}
virtual void visit(AstSelPlus* nodep, AstNUser* vup) {
nodep->fromp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->rhsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->thsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->attrp()->iterateAndNext(*this,WidthVP(0,0,FINAL).p());
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelPlus should disappear after widthSel");
}
virtual void visit(AstSelMinus* nodep, AstNUser* vup) {
nodep->fromp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->rhsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->thsp()->iterateAndNext(*this,WidthVP(0,0,PRELIM).p()); //FINAL in AstSel
nodep->attrp()->iterateAndNext(*this,WidthVP(0,0,FINAL).p());
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelMinus should disappear after widthSel");
@@ -635,14 +656,41 @@ private:
m_attrp = nodep;
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
// Don't iterate children, don't want to lose VarRef.
if (nodep->attrType()==AstAttrType::EXPR_BITS) {
if (!nodep->fromp() || !nodep->fromp()->widthMin()) nodep->v3fatalSrc("Unsized expression");
V3Number num (nodep->fileline(), 32, nodep->fromp()->width());
nodep->replaceWith(new AstConst(nodep->fileline(), num)); nodep->deleteTree(); nodep=NULL;
} else if (nodep->attrType()==AstAttrType::VAR_BASE) {
if (nodep->attrType()==AstAttrType::VAR_BASE) {
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
} else if (nodep->attrType()==AstAttrType::MEMBER_BASE) {
// Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
} else if (nodep->attrType()==AstAttrType::DIM_DIMENSIONS
|| nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS) {
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->dimensions(true);
int val = (nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS
? dim.second : (dim.first+dim.second));
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
} else if (nodep->attrType()==AstAttrType::DIM_BITS
|| nodep->attrType()==AstAttrType::DIM_HIGH
|| nodep->attrType()==AstAttrType::DIM_INCREMENT
|| nodep->attrType()==AstAttrType::DIM_LEFT
|| nodep->attrType()==AstAttrType::DIM_LOW
|| nodep->attrType()==AstAttrType::DIM_RIGHT
|| nodep->attrType()==AstAttrType::DIM_SIZE) {
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->skipRefp()->dimensions(true);
uint32_t maxdim = dim.first+dim.second;
if (!nodep->dimp() || nodep->dimp()->castConst() || maxdim<1) {
int dim = !nodep->dimp() ? 1 : nodep->dimp()->castConst()->toSInt();
int val = dimensionValue(nodep->fromp()->dtypep(), nodep->attrType(), dim);
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
}
else { // Need a runtime lookup table. Yuk.
if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType());
AstNode* dimp = nodep->dimp()->unlinkFrBack();
AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp);
nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
}
} else { // Everything else resolved earlier
nodep->dtypeSetLogicSized(32,1,AstNumeric::UNSIGNED); // Approximation, unsized 32
UINFO(1,"Missing ATTR type case node: "<<nodep<<endl);
@@ -655,7 +703,7 @@ private:
}
// DTYPES
virtual void visit(AstArrayDType* nodep, AstNUser*) {
virtual void visit(AstNodeArrayDType* nodep, AstNUser*) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
if (nodep->childDTypep()) nodep->refDTypep(moveChildDTypeEdit(nodep));
// Iterate into subDTypep() to resolve that type and update pointer.
@@ -663,7 +711,13 @@ private:
// Cleanup array size
nodep->rangep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->dtypep(nodep); // The array itself, not subDtype
nodep->widthFromSub(nodep->subDTypep());
if (nodep->castUnpackArrayDType()) {
// Historically array elements have width of the ref type not the full array
nodep->widthFromSub(nodep->subDTypep());
} else {
int width = nodep->subDTypep()->width() * nodep->rangep()->elementsConst();
nodep->widthForce(width,width);
}
UINFO(4,"dtWidthed "<<nodep<<endl);
}
virtual void visit(AstBasicDType* nodep, AstNUser*) {
@@ -751,6 +805,28 @@ private:
pushDeletep(nodep); nodep=NULL;
//if (debug()) newp->dumpTree(cout," CastOut: ");
}
virtual void visit(AstCastSize* nodep, AstNUser* vup) {
if (!nodep->rhsp()->castConst()) nodep->v3fatalSrc("Unsupported: Non-const cast of size");
//if (debug()) nodep->dumpTree(cout," CastPre: ");
int width = nodep->rhsp()->castConst()->toSInt();
if (width < 1) { nodep->v3error("Size-changing cast to zero or negative size"); width=1; }
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
AstBasicDType* underDtp = nodep->lhsp()->dtypep()->castBasicDType();
if (!underDtp) {
nodep->v3error("Unsupported: Size-changing cast on non-basic data type");
underDtp = nodep->findLogicBoolDType()->castBasicDType();
}
AstNodeDType* newDtp = (underDtp->keyword().isFourstate()
? nodep->findLogicDType(width, width, underDtp->numeric())
: nodep->findBitDType(width, width, underDtp->numeric()));
nodep->dtypep(newDtp);
AstNode* underp = nodep->lhsp()->unlinkFrBack();
nodep->replaceWith(underp);
if (underp->width()!=width) {
fixWidthExtend(underp, newDtp);
}
pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstVar* nodep, AstNUser* vup) {
//if (debug()) nodep->dumpTree(cout," InitPre: ");
// Must have deterministic constant width
@@ -772,7 +848,7 @@ private:
nodep->dtypep(iterateEditDTypep(nodep, nodep->dtypep()));
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype determined for var");
if (nodep->isIO() && !(nodep->dtypeSkipRefp()->castBasicDType()
|| nodep->dtypeSkipRefp()->castArrayDType()
|| nodep->dtypeSkipRefp()->castNodeArrayDType()
|| nodep->dtypeSkipRefp()->castNodeClassDType())) {
nodep->v3error("Unsupported: Inputs and outputs must be simple data types");
}
@@ -784,8 +860,8 @@ private:
bool didchk = false;
bool implicitParam = nodep->isParam() && bdtypep && bdtypep->implicit();
if (implicitParam) {
int width=0;
if (nodep->valuep()) {
int width=0;
nodep->valuep()->iterateAndNext(*this,WidthVP(width,0,PRELIM).p());
UINFO(9,"implicitParamPRELIMIV "<<nodep->valuep()<<endl);
// Although nodep will get a different width for parameters just below,
@@ -807,7 +883,19 @@ private:
width = 32;
}
// Can't just inherit valuep()->dtypep() as mwidth might not equal width
nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(),issigned);
if (width==1) {
// one bit parameter is same as "parameter [0] foo", not "parameter logic foo"
// as you can extract "foo[0]" from a parameter but not a wire
nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(),
issigned?AstNumeric::SIGNED : AstNumeric::UNSIGNED);
nodep->dtypep(nodep->findLogicRangeDType
(VNumRange(0,0,false),
nodep->valuep()->widthMin(),
issigned?AstNumeric::SIGNED : AstNumeric::UNSIGNED));
} else {
nodep->dtypeChgWidthSigned(width, nodep->valuep()->widthMin(),
issigned?AstNumeric::SIGNED : AstNumeric::UNSIGNED);
}
didchk = true;
nodep->valuep()->iterateAndNext(*this,WidthVP(width,nodep->widthMin(),FINAL).p());
}
@@ -824,7 +912,9 @@ private:
if (nodep->valuep()) {
//if (debug()) nodep->dumpTree(cout," final: ");
if (!didchk) nodep->valuep()->iterateAndNext(*this,WidthVP(nodep->dtypep()->width(),0,BOTH).p());
widthCheck(nodep,"Initial value",nodep->valuep(),nodep->width(),nodep->widthMin());
if (!nodep->valuep()->castInitArray()) { // No dtype at present, perhaps TODO
widthCheck(nodep,"Initial value",nodep->valuep(),nodep->width(),nodep->widthMin());
}
}
UINFO(4,"varWidthed "<<nodep<<endl);
//if (debug()) nodep->dumpTree(cout," InitOut: ");
@@ -903,6 +993,7 @@ private:
virtual void visit(AstEnumItem* nodep, AstNUser* vup) {
UINFO(5," ENUMITEM "<<nodep<<endl);
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("ENUMITEM not under ENUM");
nodep->dtypep(vdtypep);
if (nodep->valuep()) { // else the value will be assigned sequentially
int width = vdtypep->width(); // Always from parent type
@@ -925,6 +1016,63 @@ private:
}
nodep->dtypeFrom(nodep->itemp());
}
virtual void visit(AstInitArray* nodep, AstNUser* vup) {
// Should be correct by construction, so we'll just loop through all types
nodep->iterateChildren(*this, vup);
}
virtual void visit(AstInside* nodep, AstNUser* vup) {
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) {
nextip = itemp->nextp(); // Prelim may cause the node to get replaced
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); itemp=NULL;
}
// Take width as maximum across all items
int width = nodep->exprp()->width();
int mwidth = nodep->exprp()->widthMin();
for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) {
width = max(width,itemp->width());
mwidth = max(mwidth,itemp->widthMin());
}
// Apply width
nodep->exprp()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
for (AstNode* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()) {
widthCheck(nodep,"Inside Item",itemp,width,mwidth);
}
widthCheck(nodep,"Inside expression",nodep->exprp(),width,mwidth);
nodep->dtypeSetLogicBool();
if (debug()>=9) nodep->dumpTree(cout,"-inside-in: ");
// Now rip out the inside and replace with simple math
AstNode* newp = NULL;
for (AstNode* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) {
nextip = itemp->nextp(); // Will be unlinking
AstNode* inewp;
if (AstInsideRange* irangep = itemp->castInsideRange()) {
inewp = new AstAnd(itemp->fileline(),
new AstGte(itemp->fileline(),
nodep->exprp()->cloneTree(true),
irangep->lhsp()->unlinkFrBack()),
new AstLte(itemp->fileline(),
nodep->exprp()->cloneTree(true),
irangep->rhsp()->unlinkFrBack()));
} else {
inewp = new AstEqWild(itemp->fileline(),
nodep->exprp()->cloneTree(true),
itemp->unlinkFrBack());
}
if (newp) newp = new AstOr(nodep->fileline(), newp, inewp);
else newp = inewp;
}
if (!newp) newp = new AstConst(nodep->fileline(), AstConst::LogicFalse());
if (debug()>=9) newp->dumpTree(cout,"-inside-out: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstInsideRange* nodep, AstNUser* vup) {
// Just do each side; AstInside will rip these nodes out later
nodep->lhsp()->iterateAndNext(*this,vup);
nodep->rhsp()->iterateAndNext(*this,vup);
nodep->dtypeFrom(nodep->lhsp());
}
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," NODECLASS "<<nodep<<endl);
@@ -1004,12 +1152,17 @@ private:
virtual void visit(AstPattern* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return;
UINFO(9,"PATTERN "<<nodep<<endl);
AstNodeDType* oldAssDTypep = m_assDTypep;
if (nodep->childDTypep()) nodep->dtypep(moveChildDTypeEdit(nodep)); // data_type '{ pattern }
if (!nodep->dtypep() && vup->c()->dtypep()) { // Get it from parent assignment/pin/etc
nodep->dtypep(vup->c()->dtypep());
}
AstNodeDType* vdtypep = nodep->dtypep();
if (!vdtypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath a supported construct: "<<nodep->backp()->prettyTypeName());
{
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern not underneath an assignment");
m_assDTypep = m_assDTypep->skipRefp();
UINFO(9," adtypep "<<m_assDTypep<<endl);
nodep->dtypep(m_assDTypep);
vdtypep = vdtypep->skipRefp();
nodep->dtypep(vdtypep);
UINFO(9," adtypep "<<vdtypep<<endl);
nodep->dtypep(vdtypep);
for (AstPatMember* patp = nodep->itemsp()->castPatMember(); patp; patp = patp->nextp()->castPatMember()) {
// Determine replication count, and replicate initial value as widths need to be individually determined
int times = visitPatMemberRep(patp);
@@ -1027,7 +1180,10 @@ private:
patp->unlinkFrBack();
}
}
if (AstNodeClassDType* classp = m_assDTypep->castNodeClassDType()) {
while (AstConstDType* classp = vdtypep->castConstDType()) {
vdtypep = classp->subDTypep()->skipRefp();
}
if (AstNodeClassDType* classp = vdtypep->castNodeClassDType()) {
// Due to "default" and tagged patterns, we need to determine
// which member each AstPatMember corresponds to before we can
// determine the dtypep for that PatMember's value, and then
@@ -1081,9 +1237,9 @@ private:
patp = it->second;
}
// Determine initial values
m_assDTypep = memp;
vdtypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(patp->width(),patp->width(),BOTH).p());
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
if (!newp) newp = patp->lhsp()->unlinkFrBack();
else {
@@ -1099,16 +1255,16 @@ private:
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
} else {
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<m_assDTypep->prettyTypeName());
nodep->v3error("Unsupported: Assignment pattern applies against non struct/union: "<<vdtypep->prettyTypeName());
}
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstPatMember* nodep, AstNUser* vup) {
if (!nodep->dtypep()) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
if (!m_assDTypep) nodep->v3error("Unsupported/Illegal: Assignment pattern member not underneath an assignment");
AstNodeDType* vdtypep = vup->c()->dtypep();
if (!vdtypep) nodep->v3fatalSrc("Pattern member type not assigned by AstPattern visitor");
nodep->dtypep(vdtypep);
nodep->lhsp()->dtypeFrom(nodep);
nodep->iterateChildren(*this,WidthVP(nodep->dtypep()->width(),nodep->dtypep()->width(),BOTH).p());
nodep->iterateChildren(*this,WidthVP(nodep->dtypep(),BOTH).p());
widthCheck(nodep,"LHS",nodep->lhsp(),nodep->width(),nodep->width());
}
int visitPatMemberRep(AstPatMember* nodep) {
@@ -1142,12 +1298,10 @@ private:
virtual void visit(AstNodeCase* nodep, AstNUser*) {
// TOP LEVEL NODE
AstNodeCase* lastCasep = m_casep;
m_casep = nodep;
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
for (AstCaseItem* nextip, *itemp = nodep->itemsp(); itemp; itemp=nextip) {
nextip = itemp->nextp()->castCaseItem(); // Prelim may cause the node to get replaced
if (!m_casep->castGenCase()) itemp->bodysp()->iterateAndNext(*this);
if (!nodep->castGenCase()) itemp->bodysp()->iterateAndNext(*this);
for (AstNode* nextcp, *condp = itemp->condsp(); condp; condp=nextcp) {
nextcp = condp->nextp(); // Prelim may cause the node to get replaced
condp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); condp=NULL;
@@ -1171,7 +1325,6 @@ private:
}
}
widthCheck(nodep,"Case expression",nodep->exprp(),width,mwidth);
m_casep = lastCasep;
}
virtual void visit(AstNodeFor* nodep, AstNUser*) {
// TOP LEVEL NODE
@@ -1208,13 +1361,13 @@ private:
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
// TOP LEVEL NODE
//if (debug()) nodep->dumpTree(cout," AssignPre: ");
AstNodeDType* oldAssDTypep = m_assDTypep;
{
//if (debug()) nodep->dumpTree(cout,"- assin: ");
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (!nodep->lhsp()->dtypep()) nodep->v3fatalSrc("How can LHS be untyped?");
if (!nodep->lhsp()->dtypep()->widthSized()) nodep->v3fatalSrc("How can LHS be unsized?");
m_assDTypep = nodep->lhsp()->dtypep();
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),ANYSIZE,0,PRELIM).p());
//if (debug()) nodep->dumpTree(cout,"- assign: ");
if (!nodep->lhsp()->isDouble() && nodep->rhsp()->isDouble()) {
spliceCvtS(nodep->rhsp(), false); // Round RHS
} else if (nodep->lhsp()->isDouble() && !nodep->rhsp()->isDouble()) {
@@ -1224,7 +1377,7 @@ private:
if (awidth==0) {
awidth = nodep->rhsp()->width(); // Parameters can propagate by unsized assignment
}
nodep->rhsp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(nodep->lhsp()->dtypep(),awidth,awidth,FINAL).p());
nodep->dtypeFrom(nodep->lhsp());
nodep->dtypeChgWidth(awidth,awidth); // We know the assign will truncate, so rather
// than using "width" and have the optimizer truncate the result, we do
@@ -1233,7 +1386,6 @@ private:
widthCheck(nodep,"Assign RHS",nodep->rhsp(),awidth,awidth);
//if (debug()) nodep->dumpTree(cout," AssignOut: ");
}
m_assDTypep = oldAssDTypep;
}
virtual void visit(AstSFormatF* nodep, AstNUser*) {
// Excludes NodeDisplay, see below
@@ -1345,8 +1497,8 @@ private:
virtual void visit(AstReadMem* nodep, AstNUser*) {
nodep->filenamep()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->memp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (!nodep->memp()->dtypep()->skipRefp()->castArrayDType()) {
nodep->memp()->v3error("Unsupported: $readmem into non-array");
if (!nodep->memp()->dtypep()->skipRefp()->castUnpackArrayDType()) {
nodep->memp()->v3error("Unsupported: $readmem into other than unpacked array");
}
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
@@ -1424,6 +1576,16 @@ private:
// otherwise would need some mess to force both sides to proper size
}
}
// TODO Simple dtype checking, should be a more general check
bool hiArray = nodep->exprp()->dtypep()->skipRefp()->castUnpackArrayDType();
bool loArray = nodep->modVarp()->dtypep()->skipRefp()->castUnpackArrayDType();
if (loArray != hiArray) {
nodep->v3error("Illegal port connection '"<<nodep->prettyName()<<"',"
<<" mismatch between port which is"<<(hiArray?"":" not")<<" an array,"
<<" and expression which is"<<(loArray?"":" not")<<" an array.");
UINFO(1," Related lo: "<<nodep->exprp()->dtypep()->skipRefp()<<endl);
UINFO(1," Related hi: "<<nodep->modVarp()->dtypep()->skipRefp()<<endl);
}
if (inputPin) {
// input pin is lhs, expr is rhs; resize expr to match
awidth = pinwidth;
@@ -1548,7 +1710,7 @@ private:
handle.relink(newp);
pinp = newp;
}
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
pinp->accept(*this,WidthVP(portp->dtypep(),PRELIM).p()); pinp=NULL;
} else if (accept_mode==1) {
// Change data types based on above accept completion
if (portp->isDouble()) {
@@ -1556,7 +1718,7 @@ private:
}
} else if (accept_mode==2) {
// Do PRELIM again, because above accept may have exited early due to node replacement
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
pinp->accept(*this,WidthVP(portp->dtypep(),BOTH).p());
if ((portp->isOutput() || portp->isInout())
&& pinp->width() != portp->width()) {
pinp->v3error("Unsupported: Function output argument '"<<portp->prettyName()<<"'"
@@ -1863,7 +2025,8 @@ private:
int width = max(vup->c()->width(), max(nodep->lhsp()->width(), nodep->rhsp()->width()));
int mwidth = max(vup->c()->widthMin(), max(nodep->lhsp()->widthMin(), nodep->rhsp()->widthMin()));
bool expSigned = (nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned());
nodep->dtypeChgWidthSigned(width,mwidth,expSigned);
nodep->dtypeChgWidthSigned(width,mwidth,
expSigned?AstNumeric::SIGNED : AstNumeric::UNSIGNED);
if (vup->c()->final()) {
// Final call, so make sure children check their sizes
nodep->lhsp()->iterateAndNext(*this,WidthVP(width,mwidth,FINAL).p());
@@ -2034,7 +2197,8 @@ private:
linker.relink(newp);
nodep=newp;
}
nodep->dtypeChgWidthSigned(expWidth,expWidth,expSigned);
nodep->dtypeChgWidthSigned(expWidth,expWidth,
expSigned?AstNumeric::SIGNED : AstNumeric::UNSIGNED);
UINFO(4," _new: "<<nodep<<endl);
}
@@ -2330,6 +2494,99 @@ private:
return nodep;
}
int dimensionValue(AstNodeDType* nodep, AstAttrType attrType, int dim) {
// Return the dimension value for the specified attribute and constant dimension
AstNodeDType* dtypep = nodep->skipRefp();
VNumRange declRange; // ranged() set false
for (int i = 1; i <= dim; ++i) {
//UINFO(9, " dim at "<<dim<<" "<<dtypep<<endl);
declRange = VNumRange(); // ranged() set false
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
declRange = adtypep->declRange();
if (i<dim) dtypep = adtypep->subDTypep()->skipRefp();
continue;
} else if (AstNodeClassDType* adtypep = dtypep->castNodeClassDType()) {
declRange = adtypep->declRange();
if (adtypep) {} // UNUSED
break; // Sub elements don't look like arrays and can't iterate into
} else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
if (adtypep->isRanged()) declRange = adtypep->declRange();
break;
}
break;
}
int val = 0;
if (attrType==AstAttrType::DIM_BITS) {
int bits = 1;
while (dtypep) {
//UINFO(9, " bits at "<<bits<<" "<<dtypep<<endl);
if (AstNodeArrayDType* adtypep = dtypep->castNodeArrayDType()) {
bits *= adtypep->declRange().elements();
dtypep = adtypep->subDTypep()->skipRefp();
continue;
} else if (AstNodeClassDType* adtypep = dtypep->castNodeClassDType()) {
bits *= adtypep->width();
break;
} else if (AstBasicDType* adtypep = dtypep->castBasicDType()) {
bits *= adtypep->width();
break;
}
break;
}
if (dim == 0) {
val = 0;
} else if (dim == 1 && !declRange.ranged() && bits==1) { // $bits should be sane for non-arrays
val = nodep->width();
} else {
val = bits;
}
} else if (attrType==AstAttrType::DIM_HIGH) {
val = !declRange.ranged() ? 0 : declRange.hi();
} else if (attrType==AstAttrType::DIM_LEFT) {
val = !declRange.ranged() ? 0 : declRange.left();
} else if (attrType==AstAttrType::DIM_LOW) {
val = !declRange.ranged() ? 0 : declRange.lo();
} else if (attrType==AstAttrType::DIM_RIGHT) {
val = !declRange.ranged() ? 0 : declRange.right();
} else if (attrType==AstAttrType::DIM_INCREMENT) {
val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1;
} else if (attrType==AstAttrType::DIM_SIZE) {
val = !declRange.ranged() ? 0 : declRange.elements();
} else {
nodep->v3fatalSrc("Missing DIM ATTR type case");
}
UINFO(9," $dimension "<<attrType.ascii()<<"("<<((void*)dtypep)<<","<<dim<<")="<<val<<endl);
return val;
}
AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType) {
// Return a variable table which has specified dimension properties for this variable
pair<uint32_t,uint32_t> dim = nodep->skipRefp()->dimensions(true);
uint32_t maxdim = dim.first+dim.second;
//
AstInitArray* initp = new AstInitArray (nodep->fileline(), NULL);
AstNodeDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
nodep->findSigned32DType(),
new AstRange(nodep->fileline(), maxdim, 0));
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
"__Vdimtable" + cvtToStr(m_dtTables++),
vardtypep);
varp->isConst(true);
varp->isStatic(true);
varp->valuep(initp);
// Add to root, as don't know module we are in, and aids later structure sharing
v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
// Element 0 is a non-index and has speced values
initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
dimensionValue(nodep, attrType, 0)));
for (unsigned i=1; i<maxdim+1; ++i) {
initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
dimensionValue(nodep, attrType, i)));
}
varp->iterate(*this); // May have already done $unit so must do this var
return varp;
}
//----------------------------------------------------------------------
// METHODS - special type detection
bool backRequiresUnsigned(AstNode* nodep) {
@@ -2337,6 +2594,15 @@ private:
// index is NOT wide enough, you do not sign extend, but always zero extend.
return (nodep->castArraySel() || nodep->castSel());
}
void checkConstantOrReplace(AstNode* nodep, const string& message) {
// See also V3WidthSel::checkConstantOrReplace
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
if (!nodep->castConst()) {
nodep->v3error(message);
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
pushDeletep(nodep); nodep=NULL;
}
}
public:
// CONSTUCTORS
@@ -2345,12 +2611,11 @@ public:
// // don't wish to trigger errors
m_paramsOnly = paramsOnly;
m_cellRangep = NULL;
m_casep = NULL;
m_funcp = NULL;
m_initialp = NULL;
m_attrp = NULL;
m_assDTypep = NULL;
m_doGenerate = doGenerate;
m_dtTables = 0;
}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
+171 -138
View File
@@ -51,11 +51,6 @@ private:
// complicated GenCase/GenFor/Cell/Function call logic that all depends
// on if widthing top-down or just for parameters.
#define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel
//
// NODE STATE
// isBelowSeled() used insead of userp, as we're out of
// non-conflicting users, and having a persistent variable means this
// code can be skipped during most later stage constification calls.
// METHODS
static int debug() {
@@ -65,6 +60,7 @@ private:
}
void checkConstantOrReplace(AstNode* nodep, const string& message) {
// See also V3Width::checkConstantOrReplace
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
if (!nodep->castConst()) {
nodep->v3error(message);
@@ -73,32 +69,53 @@ private:
}
}
AstNodeDType* dtypeForExtractp(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
// Perform error checks on the node
AstNode* errp;
AstNodeDType* bfdtypep = baseDTypeFrom(basefromp, errp/*ref*/);
//UINFO(9,"SCD\n"); if (debug()>=9) bfdtypep->dumpTree(cout,"-dtfexvar: ");
// This may be called on dotted variables before we've completed widthing of the dotted var.
AstNodeDType* ddtypep = bfdtypep;
ddtypep = ddtypep->dtypeDimensionp(dimension);
if (debug()>=9 &&ddtypep) ddtypep->dumpTree(cout,"-ddtypep: ");
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
return adtypep;
// RETURN TYPE
struct FromData {
AstNode* m_errp; // Node that was found, for error reporting if not known type
AstNodeDType* m_dtypep; // Data type for the 'from' slice
VNumRange m_fromRange; // Numeric range bounds for the 'from' slice
FromData(AstNode* errp, AstNodeDType* dtypep, VNumRange fromRange)
{ m_errp=errp; m_dtypep=dtypep; m_fromRange=fromRange; }
~FromData() {}
};
FromData fromDataForArray(AstNode* nodep, AstNode* basefromp, bool rangedSelect) {
// What is the data type and information for this SEL-ish's from()?
UINFO(9," fromData start ddtypep = "<<basefromp<<endl);
VNumRange fromRange; // constructs to isRanged(false)
while (basefromp) {
if (basefromp->castAttrOf()) {
basefromp = basefromp->castAttrOf()->fromp();
continue;
}
break;
}
if (!basefromp || !basefromp->dtypep()) nodep->v3fatalSrc("Select with no from dtype");
AstNodeDType* ddtypep = basefromp->dtypep()->skipRefp();
AstNode* errp = ddtypep;
UINFO(9," fromData.ddtypep = "<<ddtypep<<endl);
if (AstNodeArrayDType* adtypep = ddtypep->castNodeArrayDType()) {
fromRange = adtypep->declRange();
}
else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
return adtypep;
fromRange = adtypep->declRange();
}
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (!adtypep->isRanged()) {
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<errp->prettyName());
return NULL;
if (adtypep->isRanged()) {
if (adtypep->rangep()
&& (!adtypep->rangep()->msbp()->castConst()
|| !adtypep->rangep()->lsbp()->castConst()))
nodep->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
fromRange = adtypep->declRange();
} else {
nodep->v3error("Illegal bit or array select; type does not have a bit range, or bad dimension: type is "
<<errp->prettyName());
}
return adtypep;
}
else {
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<errp->prettyName());
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: type is "
<<errp->prettyName());
}
return NULL;
return FromData(errp,ddtypep,fromRange);
}
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
@@ -137,47 +154,22 @@ private:
return newp;
}
AstNodeDType* baseDTypeFrom(AstNode* basefromp, AstNode*& errpr) {
errpr = basefromp;
if (AstNodeVarRef* varrefp = basefromp->castNodeVarRef()) {
AstVar* varp = varrefp->varp(); if (!varp) { varrefp->v3fatalSrc("Signal not linked"); return NULL; }
errpr = varp;
AstNodeDType* bfdtypep = varp->subDTypep();
if (!bfdtypep) basefromp->v3fatalSrc("No datatype found for variable in select");
return bfdtypep;
} else if (AstMemberSel* selp = basefromp->castMemberSel()) {
errpr = selp;
AstNodeDType* bfdtypep = selp->dtypep();
if (!bfdtypep) basefromp->v3fatalSrc("No datatype found for variable in select");
return bfdtypep;
} else {
basefromp->v3fatalSrc("Bit/array selection of non-variable");
}
return NULL;
}
AstNode* newSubLsbOf(AstNode* underp, AstNode* basefromp) {
AstNode* newSubLsbOf(AstNode* underp, VNumRange fromRange) {
// Account for a variable's LSB in bit selections
// Will likely become SUB(underp, lsb_of_signal)
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
AstNode* errp;
AstNodeDType* bfdtypep = baseDTypeFrom(basefromp, errp/*ref*/);
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
if (!bfdtypep->basicp()->isRanged()) {
if (!fromRange.ranged()) {
// vector without range, or 0 lsb is ok, for example a INTEGER x; y = x[21:0];
return underp;
} else {
if (bfdtypep->basicp()->rangep()
&& (!bfdtypep->basicp()->rangep()->msbp()->castConst()
|| !bfdtypep->basicp()->rangep()->lsbp()->castConst()))
bfdtypep->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(bfdtypep)
if (bfdtypep->basicp()->littleEndian()) {
if (fromRange.littleEndian()) {
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
AstNode* newp = newSubNeg(bfdtypep->basicp()->msb(), underp);
AstNode* newp = newSubNeg(fromRange.hi(), underp);
return newp;
} else {
// reg [3:1] needs a SUB(under,1)
AstNode* newp = newSubNeg(underp, bfdtypep->basicp()->lsb());
AstNode* newp = newSubNeg(underp, fromRange.lo());
return newp;
}
}
@@ -186,118 +178,146 @@ private:
// VISITORS
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
virtual void visit(AstRange* nodep, AstNUser*) {
// Convert all range values to constants
UINFO(6,"RANGE "<<nodep<<endl);
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant");
checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant");
int msb = nodep->msbConst();
int lsb = nodep->lsbConst();
if (msb<lsb) {
// If it's an array, ok to have either ordering, we'll just correct
// So, see if we're sitting under a variable's arrayp.
AstNode* huntbackp = nodep;
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
if (huntbackp->backp()->castArrayDType()) {
} else {
// Little endian bits are legal, just remember to swap
// Warning is in V3Width to avoid false warnings when in "off" generate if's
nodep->littleEndian(!nodep->littleEndian());
}
// Internally we'll always have msb() be the greater number
// We only need to correct when doing [] AstSel extraction,
// and when tracing the vector.
nodep->msbp()->swapWith(nodep->lsbp());
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
// Select of a non-width specified part of an array, i.e. "array[2]"
// This select style has a lsb and msb (no user specified width)
UINFO(6,"SELBIT "<<nodep<<endl);
if (debug()>=9) nodep->backp()->dumpTree(cout,"-vsbin(-1): ");
if (debug()>=9) nodep->backp()->dumpTree(cout,"--SELBT0: ");
// lhsp/rhsp do not need to be constant
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, false);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack(); // bit we're extracting
if (debug()>=9) ddtypep->dumpTree(cout,"-ddtypep: ");
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
if (debug()>=9) nodep->dumpTree(cout,"--SELBT2: ");
FromData fromdata = fromDataForArray(nodep, fromp, false);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
UINFO(6," ddtypep "<<ddtypep<<endl);
if (AstUnpackArrayDType* adtypep = ddtypep->castUnpackArrayDType()) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstNode* subp = rhsp;
if (adtypep->lsb()!=0 || adtypep->msb()<0) {
subp = newSubNeg (subp, adtypep->lsb());
if (fromRange.lo()!=0 || fromRange.hi()<0) {
subp = newSubNeg (subp, fromRange.lo());
}
AstArraySel* newp = new AstArraySel (nodep->fileline(),
AstArraySel* newp = new AstArraySel (nodep->fileline(),
fromp, subp);
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (adtypep) {} // unused
else if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
// SELBIT(array, index) -> SEL(array, index*width-of-subindex, width-of-subindex)
AstNode* subp = rhsp;
if (fromRange.lo()!=0 || fromRange.hi()<0) {
subp = newSubNeg (subp, fromRange.lo());
}
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
adtypep->v3fatalSrc("Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
new AstMul(nodep->fileline(),
new AstConst(nodep->fileline(),AstConst::Unsized32(),elwidth),
newSubLsbOf(rhsp, fromRange)),
new AstConst (nodep->fileline(),AstConst::Unsized32(),elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
newp->dtypeFrom(adtypep->subDTypep()); // Need to strip off array reference
if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (ddtypep->castBasicDType()) {
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
newSubLsbOf(rhsp, fromRange),
// Unsized so width from user
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
if (adtypep) {} // unused
else if (ddtypep->castNodeClassDType()) { // It's packed, so a bit from the packed struct
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
newSubLsbOf(rhsp, fromRange),
// Unsized so width from user
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
if (debug()>=9) newp->dumpTree(cout,"--SELBTn: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension");
nodep->v3error("Illegal bit or array select; type already selected, or bad dimension: type is"
<<fromdata.m_errp->prettyName());
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
if (!rhsp->backp()) pushDeletep(rhsp); rhsp=NULL;
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
// Select of a range specified part of an array, i.e. "array[2:3]"
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
// This select style has a (msb or lsb) and width
UINFO(6,"SELEXTRACT "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX0: ");
//if (debug()>=9) nodep->dumpTree(cout,"--SELEX0: ");
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX3: ");
//if (debug()>=9) nodep->dumpTree(cout,"--SELEX3: ");
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
AstNode* errp;
AstNodeDType* bfdtypep = baseDTypeFrom(basefromp, errp/*ref*/);
vlsint32_t msb = msbp->castConst()->toSInt();
vlsint32_t lsb = lsbp->castConst()->toSInt();
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, msb!=lsb);
if (AstArrayDType* adtypep = ddtypep->castArrayDType()) {
if (adtypep) {}
if (msb!=lsb) {
FromData fromdata = fromDataForArray(nodep, fromp, false);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
if (ddtypep->castUnpackArrayDType()) {
// Slice extraction
if (fromRange.elements() == (msb-lsb+1)
&& fromRange.lo() == lsb) { // Extracting whole of original array
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
} else {
// TODO when unpacked arrays fully supported probably need new data type here
AstArraySel* newp = new AstArraySel (nodep->fileline(), fromp, lsbp);
newp->start(lsb);
newp->length((msb - lsb) + 1);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
} else {
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<errp->prettyName());
}
} else if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
if (adtypep) {} // Unused
if (bfdtypep->basicp()->littleEndian()) {
}
else if (AstPackArrayDType* adtypep = ddtypep->castPackArrayDType()) {
// SELEXTRACT(array, msb, lsb) -> SEL(array, lsb*width-of-subindex, width-of-subindex*(msb-lsb))
if (!fromRange.elements() || (adtypep->width() % fromRange.elements())!=0)
adtypep->v3fatalSrc("Array extraction with width miscomputed "
<<adtypep->width()<<"/"<<fromRange.elements());
int elwidth = adtypep->width() / fromRange.elements();
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
new AstConst(nodep->fileline(),AstConst::Unsized32(),lsb*elwidth),
new AstConst(nodep->fileline(),AstConst::Unsized32(),(msb-lsb+1)*elwidth));
newp->declRange(fromRange);
newp->declElWidth(elwidth);
if (fromRange.elements() == (msb-lsb+1) // Extracting whole of original array
&& fromRange.lo() == lsb) {
newp->dtypeFrom(adtypep);
} else {
// Need a slice data type, which is an array of the extracted type, but with (presumably) different size
AstNodeDType* vardtypep = new AstPackArrayDType(nodep->fileline(),
adtypep->subDTypep(), // Need to strip off array reference
new AstRange(nodep->fileline(), fromRange));
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
newp->dtypeFrom(vardtypep);
}
if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (ddtypep->castBasicDType()) {
if (fromRange.littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
}
@@ -309,13 +329,14 @@ private:
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
newSubLsbOf(lsbp, fromRange),
widthp);
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
//if (debug()>=9) newp->dumpTree(cout,"--SELEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
} else if (AstNodeClassDType* adtypep = ddtypep->castNodeClassDType()) {
if (adtypep) {} // Unused
}
else if (ddtypep->castNodeClassDType()) {
// Classes aren't little endian
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
@@ -325,14 +346,17 @@ private:
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
newSubLsbOf(lsbp, fromRange),
widthp);
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
//if (debug()>=9) newp->dumpTree(cout,"--SELEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal range select; variable already selected, or bad dimension");
nodep->v3error("Illegal range select; type already selected, or bad dimension: type is "
<<fromdata.m_errp->prettyName());
UINFO(1," Related ddtype: "<<ddtypep<<endl);
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
@@ -343,65 +367,73 @@ private:
}
void replaceSelPlusMinus(AstNodePreSel* nodep) {
// Select of a range specified with +: or -:, i.e. "array[2+:3], [2-:3]"
// This select style has a lsb and width
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
// Below 2 lines may change nodep->widthp()
if (debug()>=9) nodep->dumpTree(cout,"--SELPM0: ");
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
if (debug()>=9) nodep->dumpTree(cout,"--SELPM3: ");
// Now replace it with an AstSel
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
int width = widthp->castConst()->toSInt();
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
AstNodeDType* ddtypep = dtypeForExtractp(nodep, basefromp, dimension, width!=1);
if (AstBasicDType* adtypep = ddtypep->castBasicDType()) {
FromData fromdata = fromDataForArray(nodep, fromp, width!=1);
AstNodeDType* ddtypep = fromdata.m_dtypep;
VNumRange fromRange = fromdata.m_fromRange;
if (ddtypep->castBasicDType()
|| (ddtypep->castNodeClassDType()
&& ddtypep->castNodeClassDType()->packed())) {
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (adtypep->littleEndian()) {
if (fromRange.littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg((adtypep->msb()-width+1), rhsp),
newSubNeg((fromRange.hi()-width+1), rhsp),
widthp);
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
newSubNeg(rhsp, fromRange.lo()),
widthp);
}
} else if (nodep->castSelMinus()) {
if (adtypep->littleEndian()) {
if (fromRange.littleEndian()) {
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(adtypep->msb(), rhsp),
newSubNeg(fromRange.hi(), rhsp),
widthp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(rhsp, adtypep->lsb()+(width-1)),
newSubNeg(rhsp, fromRange.lo()+(width-1)),
widthp);
}
} else {
nodep->v3fatalSrc("Bad Case");
}
newp->declRange(fromRange);
UINFO(6," new "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
// delete whataver we didn't use in reconstruction
if (!fromp->backp()) pushDeletep(fromp); fromp=NULL;
if (!rhsp->backp()) pushDeletep(rhsp); rhsp=NULL;
if (!widthp->backp()) pushDeletep(widthp); widthp=NULL;
}
else { // NULL=bad extract, or unknown node type
nodep->v3error("Illegal +: or -: select; variable already selected, or bad dimension");
nodep->v3error("Illegal +: or -: select; type already selected, or bad dimension: type is "
<<fromdata.m_errp->prettyTypeName());
// How to recover? We'll strip a dimension.
nodep->replaceWith(fromp); pushDeletep(nodep); nodep=NULL;
}
// delete whataver we didn't use in reconstruction
if (!fromp->backp()) pushDeletep(fromp); fromp=NULL;
if (!rhsp->backp()) pushDeletep(rhsp); rhsp=NULL;
if (!widthp->backp()) pushDeletep(widthp); widthp=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);
@@ -415,6 +447,7 @@ private:
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
// See notes above; we never iterate
nodep->v3fatalSrc("Shouldn't iterate in V3WidthSel");
}
public:
+40 -22
View File
@@ -32,7 +32,7 @@
extern void yyerror(const char*);
extern void yyerrorf(const char* format, ...);
#define STATE_VERILOG_RECENT S09 // State name for most recent Verilog Version
#define STATE_VERILOG_RECENT S12 // State name for most recent Verilog Version
#define PARSEP V3ParseImp::parsep()
#define SYMP PARSEP->symp()
@@ -135,7 +135,7 @@ void yyerrorf(const char* format, ...) {
%a 15000
%o 25000
%s V95 V01 V05 S05 S09
%s V95 V01 V05 S05 S09 S12
%s STRING ATTRMODE TABLE
%s VA5 SA9 PSL VLT
%s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
@@ -171,7 +171,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Verilog 1995 */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
{ws} { } /* otherwise ignore white-space */
{crnl} { NEXTLINE(); } /* Count line numbers */
/* Extensions to Verilog set, some specified by PSL */
@@ -344,7 +344,7 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2001 */
<V01,V05,VA5,S05,S09,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
/* System Tasks */
"$signed" { FL; return yD_SIGNED; }
"$unsigned" { FL; return yD_UNSIGNED; }
@@ -375,29 +375,38 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2005 */
<V05,S05,S09,SA9,PSL>{
<V05,S05,S09,S12,SA9,PSL>{
/* Keywords */
"uwire" { FL; return yWIRE; }
}
/* System Verilog 2005 */
<S05,S09,PSL>{
<S05,S09,S12,PSL>{
/* System Tasks */
"$bits" { FL; return yD_BITS; }
"$clog2" { FL; return yD_CLOG2; }
"$countones" { FL; return yD_COUNTONES; }
"$dimensions" { FL; return yD_DIMENSIONS; }
"$error" { FL; return yD_ERROR; }
"$fatal" { FL; return yD_FATAL; }
"$high" { FL; return yD_HIGH; }
"$increment" { FL; return yD_INCREMENT; }
"$info" { FL; return yD_INFO; }
"$isunknown" { FL; return yD_ISUNKNOWN; }
"$left" { FL; return yD_LEFT; }
"$low" { FL; return yD_LOW; }
"$onehot" { FL; return yD_ONEHOT; }
"$onehot0" { FL; return yD_ONEHOT0; }
"$right" { FL; return yD_RIGHT; }
"$size" { FL; return yD_SIZE; }
"$unpacked_dimensions" { FL; return yD_UNPACKED_DIMENSIONS; }
"$warning" { FL; return yD_WARNING; }
/* SV2005 Keywords */
"$unit" { FL; return yD_UNIT; } /* Yes, a keyword, not task */
"always_comb" { FL; return yALWAYS; }
"always_ff" { FL; return yALWAYS; }
"always_latch" { FL; return yALWAYS; }
"bind" { FL; return yBIND; }
"bit" { FL; return yBIT; }
"break" { FL; return yBREAK; }
"byte" { FL; return yBYTE; }
@@ -415,6 +424,7 @@ word [a-zA-Z0-9_]+
"final" { FL; return yFINAL; }
"iff" { FL; return yIFF; }
"import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; }
"int" { FL; return yINT; }
"logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; }
@@ -440,7 +450,6 @@ word [a-zA-Z0-9_]+
/* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
"$root" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"alias" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"bind" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"binsof" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"class" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -461,7 +470,6 @@ word [a-zA-Z0-9_]+
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"inside" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -490,7 +498,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog 2005 ONLY not PSL; different rules for PSL as specified below */
<S05,S09>{
<S05,S09,S12>{
/* Keywords */
"assert" { FL; return yASSERT; }
"const" { FL; return yCONST__LEX; }
@@ -505,7 +513,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog 2009 */
<S09,PSL>{
<S09,S12,PSL>{
/* Keywords */
"global" { FL; return yGLOBAL__LEX; }
"unique0" { FL; return yUNIQUE0; }
@@ -533,8 +541,17 @@ word [a-zA-Z0-9_]+
"weak" { yyerrorf("Unsupported: SystemVerilog 2009 reserved word not implemented: %s",yytext); }
}
/* System Verilog 2012 */
<S12,PSL>{
/* Keywords */
"implements" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"interconnect" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"nettype" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"soft" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
}
/* Default PLI rule */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { string str (yytext,yyleng);
yylval.strp = PARSEP->newString(AstNode::encodeName(str));
// Lookup unencoded name including the $, to avoid hitting normal signals
@@ -641,7 +658,7 @@ word [a-zA-Z0-9_]+
/* PSL */
/*Entry into PSL; mode change */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"psl" { yy_push_state(PSL); FL; return yPSL; }
}
@@ -730,7 +747,7 @@ word [a-zA-Z0-9_]+
/* Meta comments */
/* Converted from //{cmt}verilator ...{cmt} by preprocessor */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"/*verilator"{ws}*"*/" {} /* Ignore empty comments, may be `endif // verilator */
"/*verilator clock_enable*/" { FL; return yVL_CLOCK_ENABLE; }
"/*verilator coverage_block_off*/" { FL; return yVL_COVERAGE_BLOCK_OFF; }
@@ -765,11 +782,11 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Single character operator thingies */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"{" { FL; return yytext[0]; }
"}" { FL; return yytext[0]; }
}
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"!" { FL; return yytext[0]; }
"#" { FL; return yytext[0]; }
"$" { FL; return yytext[0]; }
@@ -801,7 +818,7 @@ word [a-zA-Z0-9_]+
/* Operators and multi-character symbols */
/* Verilog 1995 Operators */
<V95,V01,V05,VA5,S05,S09,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"&&" { FL; return yP_ANDAND; }
"||" { FL; return yP_OROR; }
"<=" { FL; return yP_LTE; }
@@ -823,7 +840,7 @@ word [a-zA-Z0-9_]+
}
/* Verilog 2001 Operators */
<V01,V05,VA5,S05,S09,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
"<<<" { FL; return yP_SLEFT; }
">>>" { FL; return yP_SSRIGHT; }
"**" { FL; return yP_POW; }
@@ -833,7 +850,7 @@ word [a-zA-Z0-9_]+
}
/* SystemVerilog Operators */
<S05,S09>{
<S05,S09,S12>{
"'" { FL; return yP_TICK; }
"'{" { FL; return yP_TICKBRA; }
"==?" { FL; return yP_WILDEQUAL; }
@@ -882,7 +899,7 @@ word [a-zA-Z0-9_]+
}
/* Identifiers and numbers */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
{escid} { FL; yylval.strp = PARSEP->newString
(AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash
return yaID__LEX;
@@ -958,7 +975,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Attributes */
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,VA5,S05,S09,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*), but (* attr_spec
}
@@ -975,7 +992,7 @@ word [a-zA-Z0-9_]+
/* Preprocessor */
/* Common for all SYSC header states */
/* OPTIMIZE: we return one per line, make it one for the entire block */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
"`accelerate" { } // Verilog-XL compatibility
"`autoexpand_vectornets" { } // Verilog-XL compatibility
"`celldefine" { PARSEP->inCellDefine(true); }
@@ -1019,6 +1036,7 @@ word [a-zA-Z0-9_]+
"`begin_keywords"[ \t]*\"VAMS[-0-9.]*\" { yy_push_state(VA5); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2005\" { yy_push_state(S05); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2009\" { yy_push_state(S09); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800-2012\" { yy_push_state(S12); PARSEP->pushBeginKeywords(YY_START); }
"`begin_keywords"[ \t]*\"1800+VAMS\" { yy_push_state(SA9); PARSEP->pushBeginKeywords(YY_START); }
"`end_keywords" { yy_pop_state(); if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); }
@@ -1050,7 +1068,7 @@ word [a-zA-Z0-9_]+
/************************************************************************/
/* Default rules - leave last */
<V95,V01,V05,VA5,S05,S09,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
"`"[a-zA-Z_0-9]+ { FL; yyerrorf("Define or directive not defined: %s",yytext); }
"//"[^\n]* { } /* throw away single line comments */
. { FL; return yytext[0]; } /* return single char ops. */
+131 -52
View File
@@ -63,7 +63,6 @@ public:
AstPin* m_instParamp; // Parameters for instantiations
AstNodeModule* m_modp; // Module
int m_modTypeImpNum; // Implicit type number, incremented each module
int m_uniqueAttr; // Bitmask of unique/priority keywords
// CONSTRUCTORS
V3ParseGrammar() {
@@ -112,11 +111,8 @@ public:
// Find one made earlier?
AstPackage* pkgp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName())->nodep()->castPackage();
if (!pkgp) {
pkgp = new AstPackage(fl, AstPackage::dollarUnitName());
pkgp->inLibrary(true); // packages are always libraries; don't want to make them a "top"
pkgp->modTrace(false); // may reconsider later
pkgp = PARSEP->rootp()->dollarUnitPkgAddp();
GRAMMARP->m_modp = pkgp; GRAMMARP->m_modTypeImpNum = 0;
PARSEP->rootp()->addModulep(pkgp);
SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global
}
return pkgp;
@@ -282,6 +278,7 @@ class AstSenTree;
%token<fl> yASSIGN "assign"
%token<fl> yAUTOMATIC "automatic"
%token<fl> yBEGIN "begin"
%token<fl> yBIND "bind"
%token<fl> yBIT "bit"
%token<fl> yBREAK "break"
%token<fl> yBUF "buf"
@@ -334,6 +331,7 @@ class AstSenTree;
%token<fl> yINITIAL "initial"
%token<fl> yINOUT "inout"
%token<fl> yINPUT "input"
%token<fl> yINSIDE "inside"
%token<fl> yINT "int"
%token<fl> yINTEGER "integer"
%token<fl> yLOCALPARAM "localparam"
@@ -416,6 +414,7 @@ class AstSenTree;
%token<fl> yD_CEIL "$ceil"
%token<fl> yD_CLOG2 "$clog2"
%token<fl> yD_COUNTONES "$countones"
%token<fl> yD_DIMENSIONS "$dimensions"
%token<fl> yD_DISPLAY "$display"
%token<fl> yD_ERROR "$error"
%token<fl> yD_EXP "$exp"
@@ -431,11 +430,15 @@ class AstSenTree;
%token<fl> yD_FOPEN "$fopen"
%token<fl> yD_FSCANF "$fscanf"
%token<fl> yD_FWRITE "$fwrite"
%token<fl> yD_HIGH "$high"
%token<fl> yD_INCREMENT "$increment"
%token<fl> yD_INFO "$info"
%token<fl> yD_ISUNKNOWN "$isunknown"
%token<fl> yD_ITOR "$itor"
%token<fl> yD_LEFT "$left"
%token<fl> yD_LN "$ln"
%token<fl> yD_LOG10 "$log10"
%token<fl> yD_LOW "$low"
%token<fl> yD_ONEHOT "$onehot"
%token<fl> yD_ONEHOT0 "$onehot0"
%token<fl> yD_POW "$pow"
@@ -444,9 +447,11 @@ class AstSenTree;
%token<fl> yD_READMEMH "$readmemh"
%token<fl> yD_REALTIME "$realtime"
%token<fl> yD_REALTOBITS "$realtobits"
%token<fl> yD_RIGHT "$right"
%token<fl> yD_RTOI "$rtoi"
%token<fl> yD_SFORMAT "$sformat"
%token<fl> yD_SIGNED "$signed"
%token<fl> yD_SIZE "$size"
%token<fl> yD_SQRT "$sqrt"
%token<fl> yD_SSCANF "$sscanf"
%token<fl> yD_STIME "$stime"
@@ -456,6 +461,7 @@ class AstSenTree;
%token<fl> yD_TESTPLUSARGS "$test$plusargs"
%token<fl> yD_TIME "$time"
%token<fl> yD_UNIT "$unit"
%token<fl> yD_UNPACKED_DIMENSIONS "$unpacked_dimensions"
%token<fl> yD_UNSIGNED "$unsigned"
%token<fl> yD_VALUEPLUSARGS "$value$plusargs"
%token<fl> yD_WARNING "$warning"
@@ -551,7 +557,7 @@ class AstSenTree;
// PSL op precedence
%right yP_MINUSGT yP_LOGIFF
%right yP_ORMINUSGT yP_OREQGT
%left<fl> prPSLCLK
%left<fl> prPSLCLK
// Verilog op precedence
%right '?' ':'
@@ -561,7 +567,7 @@ class AstSenTree;
%left '^' yP_XNOR
%left '&' yP_NAND
%left yP_EQUAL yP_NOTEQUAL yP_CASEEQUAL yP_CASENOTEQUAL yP_WILDEQUAL yP_WILDNOTEQUAL
%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE
%left '>' '<' yP_GTE yP_LTE yP_LTE__IGNORE yINSIDE
%left yP_SLEFT yP_SRIGHT yP_SSRIGHT
%left '+' '-'
%left '*' '/' '%'
@@ -645,7 +651,7 @@ description: // ==IEEE: description
| program_declaration { }
| package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
//UNSUP bind_directive { }
| bind_directive { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
// unsupported // IEEE: config_declaration
// // Verilator only
| vltItem { }
@@ -887,7 +893,7 @@ port<nodep>: // ==IEEE: port
| portDirNetE yVAR implicit_typeE portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
| portDirNetE signingE rangeList portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,false)); $$->addNextNull(VARDONEP($$,$5,$6)); }
{ $$=$4; VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2), $3,true)); $$->addNextNull(VARDONEP($$,$5,$6)); }
| portDirNetE /*implicit*/ portSig variable_dimensionListE sigAttrListE
{ $$=$2; /*VARDTYPE-same*/ $$->addNextNull(VARDONEP($$,$3,$4)); }
//
@@ -1036,13 +1042,30 @@ net_declaration<nodep>: // IEEE: net_declaration - excluding implict
;
net_declarationFront: // IEEE: beginning of net_declaration
net_declRESET net_type strengthSpecE signingE delayrange { VARDTYPE($5); $5->basicp()->setSignedState($4); }
net_declRESET net_type strengthSpecE net_scalaredE net_dataType { VARDTYPE($5); }
;
net_declRESET:
/* empty */ { VARRESET_NONLIST(UNKNOWN); }
;
net_scalaredE:
/* empty */ { }
//UNSUP: ySCALARED/yVECTORED ignored
| ySCALARED { }
| yVECTORED { }
;
net_dataType<dtypep>:
// // If there's a SV data type there shouldn't be a delay on this wire
// // Otherwise #(...) can't be determined to be a delay or parameters
// // Submit this as a footnote to the committee
var_data_type { $$ = $1; }
| signingE rangeList delayE { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC, $1),$2,true); } // not implicit
| signing { $$ = new AstBasicDType($<fl>1, LOGIC, $1); } // not implicit
| /*implicit*/ delayE { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
;
net_type: // ==IEEE: net_type
ySUPPLY0 { VARDECL(SUPPLY0); }
| ySUPPLY1 { VARDECL(SUPPLY1); }
@@ -1097,7 +1120,7 @@ port_declaration<nodep>: // ==IEEE: port_declaration
list_of_variable_decl_assignments { $$ = $6; }
| port_directionReset port_declNetE yVAR implicit_typeE { VARDTYPE($4); }
list_of_variable_decl_assignments { $$ = $6; }
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4,false)); }
| port_directionReset port_declNetE signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($4->fileline(), LOGIC_IMPLICIT, $3),$4,true)); }
list_of_variable_decl_assignments { $$ = $6; }
| port_directionReset port_declNetE signing { VARDTYPE(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $3)); }
list_of_variable_decl_assignments { $$ = $5; }
@@ -1197,7 +1220,7 @@ data_typeBasic<dtypep>: // IEEE: part of data_type
data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc references
data_typeBasic { $$ = $1; }
| struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
GRAMMARP->m_modp,VFlagChildDType(),$1),$2,false); }
GRAMMARP->m_modp,VFlagChildDType(),$1),$2,true); }
| enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
GRAMMARP->m_modp,VFlagChildDType(),$1); }
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
@@ -1211,11 +1234,17 @@ data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc referenc
// // IEEE: ps_covergroup: see data_type above
;
data_type_or_void<dtypep>: // ==IEEE: data_type_or_void
data_type { $$=$1; }
data_type_or_void<dtypep>: // ==IEEE: data_type_or_void
data_type { $$ = $1; }
//UNSUP yVOID { UNSUP } // No yTAGGED structures
;
var_data_type<dtypep>: // ==IEEE: var_data_type
data_type { $$ = $1; }
| yVAR data_type { $$ = $2; }
| yVAR implicit_typeE { $$ = $2; }
;
struct_unionDecl<classp>: // IEEE: part of data_type
// // packedSigningE is NOP for unpacked
ySTRUCT packedSigningE '{' { $<classp>$ = new AstStructDType($1, $2); SYMP->pushNew($<classp>$); }
@@ -1362,14 +1391,15 @@ enum_base_typeE<dtypep>: // IEEE: enum_base_type
/* empty */ { $$ = new AstBasicDType(CRELINE(),AstBasicDTypeKwd::INT); }
// // Not in spec, but obviously "enum [1:0]" should work
// // implicit_type expanded, without empty
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
// // Note enum base types are always packed data types
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
//
| integer_atom_type signingE { $1->setSignedState($2); $$ = $1; }
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,false); }
| integer_vector_type signingE rangeListE { $1->setSignedState($2); $$ = GRAMMARP->addRange($1,$3,true); }
// // below can be idAny or yaID__aTYPE
// // IEEE requires a type, though no shift conflict if idAny
| idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, false); }
| idAny rangeListE { $$ = GRAMMARP->createArray(new AstRefDType($<fl>1, *$1), $2, true); }
;
enum_nameList<nodep>:
@@ -1419,12 +1449,12 @@ data_declarationVarFront: // IEEE: part of data_declaration
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
/**/ yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE($3); }
| /**/ yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT)); }
| /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,false)); }
| /**/ yVAR lifetimeE signingE rangeList { /*VARRESET-in-ddVar*/ VARDTYPE(GRAMMARP->addRange(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $3), $4,true)); }
//
// // implicit_type expanded into /*empty*/ or "signingE rangeList"
| yCONST__ETC yVAR lifetimeE data_type { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), $4)); }
| yCONST__ETC yVAR lifetimeE { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), new AstBasicDType($<fl>2, LOGIC_IMPLICIT))); }
| yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,false))); }
| yCONST__ETC yVAR lifetimeE signingE rangeList { VARRESET_NONLIST(VAR); VARDTYPE(new AstConstDType($<fl>1, VFlagChildDType(), GRAMMARP->addRange(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $4), $5,true))); }
//
// // Expanded: "constE lifetimeE data_type"
| /**/ data_type { VARRESET_NONLIST(VAR); VARDTYPE($1); }
@@ -1436,7 +1466,7 @@ data_declarationVarFront: // IEEE: part of data_declaration
implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
// // Also expanded in data_declaration
/* empty */ { $$ = NULL; }
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,false); }
| signingE rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1),$2,true); }
| signing { $$ = new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1); }
;
@@ -1511,7 +1541,7 @@ module_common_item<nodep>: // ==IEEE: module_common_item
// // + module_instantiation from module_or_generate_item
| etcInst { $$ = $1; }
| concurrent_assertion_item { $$ = $1; }
//UNSUP bind_directive { $$ = $1; }
| bind_directive { $$ = $1; }
| continuous_assign { $$ = $1; }
// // IEEE: net_alias
//UNSUP yALIAS variable_lvalue aliasEqList ';' { UNSUP }
@@ -1548,6 +1578,31 @@ module_or_generate_item_declaration<nodep>: // ==IEEE: module_or_generate_item_d
//UNSUP yDEFAULT yCLOCKING idAny/*new-clocking_identifier*/ ';' { $$ = $1; }
;
bind_directive<nodep>: // ==IEEE: bind_directive + bind_target_scope
// // ';' - Note IEEE grammar is wrong, includes extra ';' - it's already in module_instantiation
// // We merged the rules - id may be a bind_target_instance or module_identifier or interface_identifier
yBIND bind_target_instance bind_instantiation { $$ = new AstBind($<fl>1,*$2,$3); }
| yBIND bind_target_instance ':' bind_target_instance_list bind_instantiation { $$=NULL; $1->v3error("Unsupported: Bind with instance list"); }
;
bind_target_instance_list: // ==IEEE: bind_target_instance_list
bind_target_instance { }
| bind_target_instance_list ',' bind_target_instance { }
;
bind_target_instance<strp>: // ==IEEE: bind_target_instance
//UNSUP hierarchical_identifierBit { }
idAny { $$ = $1; }
;
bind_instantiation<nodep>: // ==IEEE: bind_instantiation
// // IEEE: program_instantiation
// // IEEE: + module_instantiation
// // IEEE: + interface_instantiation
// // Need to get an AstBind instead of AstCell, so have special rules
instDecl { $$ = $1; }
;
//************************************************
// Generates
//
@@ -1768,11 +1823,6 @@ rangeList<rangep>: // IEEE: {packed_dimension}
| rangeList anyrange { $$ = $1; $1->addNext($2); }
;
wirerangeE<dtypep>:
/* empty */ { $$ = new AstBasicDType(CRELINE(), LOGIC); } // not implicit
| rangeList { $$ = GRAMMARP->addRange(new AstBasicDType($1->fileline(), LOGIC),$1,false); } // not implicit
;
// IEEE: select
// Merged into more general idArray
@@ -1795,13 +1845,6 @@ packed_dimension<rangep>: // ==IEEE: packed_dimension
//UNSUP '[' ']' { UNSUP }
;
delayrange<dtypep>:
wirerangeE delayE { $$ = $1; }
| ySCALARED wirerangeE delayE { $$ = $2; }
| yVECTORED wirerangeE delayE { $$ = $2; }
//UNSUP: ySCALARED/yVECTORED ignored
;
//************************************************
// Parameters
@@ -2141,6 +2184,7 @@ statementVerilatorPragmas<nodep>:
foperator_assignment<nodep>: // IEEE: operator_assignment (for first part of expression)
fexprLvalue '=' delayE expr { $$ = new AstAssign($2,$1,$4); }
| fexprLvalue '=' yD_FOPEN '(' expr ')' { $$ = NULL; $3->v3error("Unsupported: $fopen with multichannel descriptor. Add ,\"w\" as second argument to open a file descriptor."); }
| fexprLvalue '=' yD_FOPEN '(' expr ',' expr ')' { $$ = new AstFOpen($3,$1,$5,$7); }
//
//UNSUP ~f~exprLvalue '=' delay_or_event_controlE expr { UNSUP }
@@ -2202,6 +2246,20 @@ case_itemList<caseitemp>: // IEEE: { case_item + ... }
| case_itemList yDEFAULT ':' stmtBlock { $$ = $1;$1->addNext(new AstCaseItem($3,NULL,$4)); }
;
open_range_list<nodep>: // ==IEEE: open_range_list + open_value_range
open_value_range { $$ = $1; }
| open_range_list ',' open_value_range { $$ = $1;$1->addNext($3); }
;
open_value_range<nodep>: // ==IEEE: open_value_range
value_range { $$ = $1; }
;
value_range<nodep>: // ==IEEE: value_range
expr { $$ = $1; }
| '[' expr ':' expr ']' { $$ = new AstInsideRange($3,$2,$4); }
;
caseCondList<nodep>: // IEEE: part of case_item
expr { $$ = $1; }
| caseCondList ',' expr { $$ = $1;$1->addNext($3); }
@@ -2256,7 +2314,7 @@ patternKey<nodep>: // IEEE: merge structure_pattern_key, array_pattern_key, ass
| yaID__ETC { $$ = new AstText($<fl>1,*$1); }
;
assignment_pattern<nodep>: // ==IEEE: assignment_pattern
assignment_pattern<patternp>: // ==IEEE: assignment_pattern
// This doesn't match the text of the spec. I think a : is missing, or example code needed
// yP_TICKBRA constExpr exprList '}' { $$="'{"+$2+" "+$3"}"; }
// // "'{ const_expression }" is same as patternList with one entry
@@ -2385,39 +2443,55 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yaD_DPI parenE { $$ = new AstFuncRef($<fl>1,*$1,NULL); }
| yaD_DPI '(' exprList ')' { $$ = new AstFuncRef($2,*$1,$3); }
//
| yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); }
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
| yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); }
| yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); }
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); }
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::EXPR_BITS,$3); }
| yD_BITS '(' data_type ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
| yD_BITS '(' data_type ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3); }
| yD_BITS '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_BITS,$3,$5); }
| yD_BITSTOREAL '(' expr ')' { $$ = new AstBitsToRealD($1,$3); }
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
| yD_CEIL '(' expr ')' { $$ = new AstCeilD($1,$3); }
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
| yD_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_DIMENSIONS,$3); }
| yD_EXP '(' expr ')' { $$ = new AstExpD($1,$3); }
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_FLOOR '(' expr ')' { $$ = new AstFloorD($1,$3); }
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_HIGH '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,NULL); }
| yD_HIGH '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_HIGH,$3,$5); }
| yD_INCREMENT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,NULL); }
| yD_INCREMENT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_INCREMENT,$3,$5); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ITOR '(' expr ')' { $$ = new AstIToRD($1,$3); }
| yD_LEFT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,NULL); }
| yD_LEFT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LEFT,$3,$5); }
| yD_LN '(' expr ')' { $$ = new AstLogD($1,$3); }
| yD_LOG10 '(' expr ')' { $$ = new AstLog10D($1,$3); }
| yD_LOW '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,NULL); }
| yD_LOW '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_LOW,$3,$5); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
| yD_POW '(' expr ',' expr ')' { $$ = new AstPowD($1,$3,$5); }
| yD_RANDOM '(' expr ')' { $1->v3error("Unsupported: Seeding $random doesn't map to C++, use $c(\"srand\")"); }
| yD_RANDOM parenE { $$ = new AstRand($1); }
| yD_REALTIME parenE { $$ = new AstTimeD($1); }
| yD_REALTOBITS '(' expr ')' { $$ = new AstRealToBits($1,$3); }
| yD_RIGHT '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,NULL); }
| yD_RIGHT '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_RIGHT,$3,$5); }
| yD_RTOI '(' expr ')' { $$ = new AstRToIS($1,$3); }
//| yD_SFORMATF '(' str commaEListE ')' { $$ = new AstSFormatF($1,*$3,false,$4); } // Have AST, just need testing and debug
| yD_SIGNED '(' expr ')' { $$ = new AstSigned($1,$3); }
| yD_SIZE '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,NULL); }
| yD_SIZE '(' expr ',' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_SIZE,$3,$5); }
| yD_SQRT '(' expr ')' { $$ = new AstSqrtD($1,$3); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_STIME parenE { $$ = new AstSel($1,new AstTime($1),0,32); }
| yD_TIME parenE { $$ = new AstTime($1); }
| yD_SYSTEM '(' expr ')' { $$ = new AstSystemF($1,$3); }
| yD_TESTPLUSARGS '(' str ')' { $$ = new AstTestPlusArgs($1,*$3); }
| yD_TIME parenE { $$ = new AstTime($1); }
| yD_UNPACKED_DIMENSIONS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::DIM_UNPK_DIMENSIONS,$3); }
| yD_UNSIGNED '(' expr ')' { $$ = new AstUnsigned($1,$3); }
| yD_VALUEPLUSARGS '(' str ',' expr ')' { $$ = new AstValuePlusArgs($1,*$3,$5); }
;
@@ -2480,7 +2554,7 @@ funcId<ftaskp>: // IEEE: function_data_type_or_implicit + part of function_bod
SYMP->pushNewUnder($$, NULL); }
| signingE rangeList tfIdScoped
{ $$ = new AstFunc ($<fl>3,*$<strp>3,NULL,
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,false));
GRAMMARP->addRange(new AstBasicDType($<fl>3, LOGIC_IMPLICIT, $1), $2,true));
SYMP->pushNewUnder($$, NULL); }
| signing tfIdScoped
{ $$ = new AstFunc ($<fl>2,*$<strp>2,NULL,
@@ -2550,14 +2624,14 @@ tf_port_item<nodep>: // ==IEEE: tf_port_item
tf_port_itemFront: // IEEE: part of tf_port_item, which has the data type
data_type { VARDTYPE($1); }
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, false)); }
| signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($2->fileline(), LOGIC_IMPLICIT, $1), $2, true)); }
| signing { VARDTYPE(new AstBasicDType($<fl>1, LOGIC_IMPLICIT, $1)); }
| yVAR data_type { VARDTYPE($2); }
| yVAR implicit_typeE { VARDTYPE($2); }
//
| tf_port_itemDir /*implicit*/ { VARDTYPE(NULL); /*default_nettype-see spec*/ }
| tf_port_itemDir data_type { VARDTYPE($2); }
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,false)); }
| tf_port_itemDir signingE rangeList { VARDTYPE(GRAMMARP->addRange(new AstBasicDType($3->fileline(), LOGIC_IMPLICIT, $2),$3,true)); }
| tf_port_itemDir signing { VARDTYPE(new AstBasicDType($<fl>2, LOGIC_IMPLICIT, $2)); }
| tf_port_itemDir yVAR data_type { VARDTYPE($3); }
| tf_port_itemDir yVAR implicit_typeE { VARDTYPE($3); }
@@ -2698,7 +2772,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
| ~l~expr '?' ~r~expr ':' ~r~expr { $$ = new AstCond($2,$1,$3,$5); }
//
// // IEEE: inside_expression
//UNSUP ~l~expr yINSIDE '{' open_range_list '}' { UNSUP }
| ~l~expr yINSIDE '{' open_range_list '}' { $$ = new AstInside($2,$1,$4); }
//
// // IEEE: tagged_union_expression
//UNSUP yTAGGED id/*member*/ %prec prTAGGED { UNSUP }
@@ -2751,6 +2825,7 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
// // Spec only allows primary with addition of a type reference
// // We'll be more general, and later assert LHS was a type.
//UNSUP ~l~expr yP_TICK '(' expr ')' { UNSUP }
| yaINTNUM yP_TICK '(' expr ')' { $$ = new AstCastSize($2,$4,new AstConst($1->fileline(),*$1)); }
//
// // IEEE: assignment_pattern_expression
// // IEEE: streaming_concatenation
@@ -2802,7 +2877,7 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
// // We allow more here than the spec requires
//UNSUP ~l~exprScope assignment_pattern { UNSUP }
//UNSUP data_type assignment_pattern { UNSUP }
| data_type assignment_pattern { $$ = $2; $2->childDTypep($1); }
| assignment_pattern { $$ = $1; }
//
//UNSUP streaming_concatenation { UNSUP }
@@ -3433,7 +3508,11 @@ AstNodeDType* V3ParseGrammar::createArray(AstNodeDType* basep, AstRange* rangep,
while (rangep) {
AstRange* prevp = rangep->backp()->castRange();
if (prevp) rangep->unlinkFrBack();
arrayp = new AstArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep, isPacked);
if (isPacked) {
arrayp = new AstPackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
} else {
arrayp = new AstUnpackArrayDType(rangep->fileline(), VFlagChildDType(), arrayp, rangep);
}
rangep = prevp;
}
}
+1
View File
@@ -365,6 +365,7 @@ sub new {
'v3' => 0,
verilator_flags => ["-cc",
"-Mdir $self->{obj_dir}",
"-OD", # As currently disabled unless -O3
"--debug-check"],
verilator_flags2 => [],
verilator_make_gcc => 1,
+1 -1
View File
@@ -14,9 +14,9 @@ use Cwd qw(chdir);
my @args = @ARGV;
chdir("$FindBin::Bin/..");
$ENV{PWD} = Cwd::getcwd(); # Else chdir leaves the .. which confuses later commands
@args = map { s!.*test_regress/!!; $_; } @args;
print "cd $ENV{PWD} && $FindBin::Bin/bootstrap.pl ",join(' ',@args),"\n";
exec("./driver.pl", @args);
die;
+1 -1
View File
@@ -13,7 +13,7 @@
// please note it here, otherwise:**
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
// without warranty, 2013 by ____YOUR_NAME_HERE____.
module t (/*AUTOARG*/
// Inputs
@@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug448");
compile (
);
+121 -93
View File
@@ -10,22 +10,40 @@ module t (/*AUTOARG*/
input clk;
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
// parameters for array sizes
localparam WA = 4;
localparam WB = 6;
localparam WC = 8;
// 2D packed arrays
logic [WA-1:0] [WB-1:0] [WC-1:0] array_bg; // big endian array
logic [WA+1:2] [WB+1:2] [WC+1:2] array_bg; // big endian array
/* verilator lint_off LITENDIAN */
logic [0:WA-1] [0:WB-1] [0:WC-1] array_lt; // little endian array
logic [2:WA+1] [2:WB+1] [2:WC+1] array_lt; // little endian array
/* verilator lint_on LITENDIAN */
logic [1:0] array_unpk [3:2][1:0];
integer cnt = 0;
integer slc = 0; // slice type
integer dim = 0; // dimension
integer wdt = 0; // width
initial begin
`checkh($dimensions (array_unpk), 3);
`ifndef VCS
`checkh($unpacked_dimensions (array_unpk), 2); // IEEE 2009
`endif
`checkh($bits (array_unpk), 2*2*2);
`checkh($low (array_unpk), 2);
`checkh($high (array_unpk), 3);
`checkh($left (array_unpk), 3);
`checkh($right(array_unpk), 2);
`checkh($increment(array_unpk), 1);
`checkh($size (array_unpk), 2);
end
// event counter
always @ (posedge clk) begin
cnt <= cnt + 1;
@@ -38,104 +56,114 @@ module t (/*AUTOARG*/
$finish;
end
integer slc_next;
// calculation of dimention sizes
always @ (posedge clk)
begin
// slicing tipe counter
always @ (posedge clk) begin
// slicing type counter
case (cnt[3:2])
2'd0 : begin slc <= 0; end // full array
2'd1 : begin slc <= 1; end // half array
2'd2 : begin slc <= 2; end // single array element
default: begin slc <= 0; end
2'd0 : begin slc_next = 0; end // full array
2'd1 : begin slc_next = 1; end // single array element
2'd2 : begin slc_next = 2; end // half array
default: begin slc_next = 0; end
endcase
// dimmension counter
slc <= slc_next;
// dimension counter
case (cnt[1:0])
2'd0 : begin dim <= 1; wdt = (slc==1) ? WA/2 : (slc==2) ? 1 : WA; end
2'd1 : begin dim <= 2; wdt = WB; end
2'd2 : begin dim <= 3; wdt = WC; end
default: begin dim <= 0; wdt = 0; end
2'd0 : begin dim <= 1; wdt <= (slc_next==1) ? WA/2 : (slc_next==2) ? WA/2 : WA; end
2'd1 : begin dim <= 2; wdt <= WB; end
2'd2 : begin dim <= 3; wdt <= WC; end
default: begin dim <= 0; wdt <= 0; end
endcase
end
always @ (posedge clk)
if (cnt[30:4]==1) begin
// big endian
if (cnt[3:2]==0) begin
// full array
if ($dimensions (array_bg) != 3) $stop;
if ($bits (array_bg) != WA*WB*WC) $stop;
if ((dim>=1)&&(dim<=3)) begin
if ($left (array_bg, dim) != wdt-1) $stop;
if ($right (array_bg, dim) != 0 ) $stop;
if ($low (array_bg, dim) != 0 ) $stop;
if ($high (array_bg, dim) != wdt-1) $stop;
if ($increment (array_bg, dim) != 1 ) $stop;
if ($size (array_bg, dim) != wdt ) $stop;
end
end else if (cnt[3:2]==1) begin
// half array
if ($dimensions (array_bg[WA/2-1:0]) != 3) $stop;
if ($bits (array_bg[WA/2-1:0]) != WA/2*WB*WC) $stop;
if ((dim>=1)&&(dim<=3)) begin
if ($left (array_bg[WA/2-1:0], dim) != wdt-1) $stop;
if ($right (array_bg[WA/2-1:0], dim) != 0 ) $stop;
if ($low (array_bg[WA/2-1:0], dim) != 0 ) $stop;
if ($high (array_bg[WA/2-1:0], dim) != wdt-1) $stop;
if ($increment (array_bg[WA/2-1:0], dim) != 1 ) $stop;
if ($size (array_bg[WA/2-1:0], dim) != wdt ) $stop;
end
end else if (cnt[3:2]==2) begin
// single array element
if ($dimensions (array_bg[0]) != 2) $stop;
if ($bits (array_bg[0]) != WB*WC) $stop;
if ((dim>=2)&&(dim<=3)) begin
if ($left (array_bg[0], dim-1) != wdt-1) $stop;
if ($right (array_bg[0], dim-1) != 0 ) $stop;
if ($low (array_bg[0], dim-1) != 0 ) $stop;
if ($high (array_bg[0], dim-1) != wdt-1) $stop;
if ($increment (array_bg[0], dim-1) != 1 ) $stop;
if ($size (array_bg[0], dim-1) != wdt ) $stop;
end
end
end else if (cnt[30:4]==2) begin
// little endian
if (cnt[3:2]==0) begin
// full array
if ($dimensions (array_lt) != 3) $stop;
if ($bits (array_lt) != WA*WB*WC) $stop;
if ((dim>=1)&&(dim<=3)) begin
if ($left (array_lt, dim) != 0 ) $stop;
if ($right (array_lt, dim) != wdt-1) $stop;
if ($low (array_lt, dim) != 0 ) $stop;
if ($high (array_lt, dim) != wdt-1) $stop;
if ($increment (array_lt, dim) != -1 ) $stop;
if ($size (array_lt, dim) != wdt ) $stop;
end
end else if (cnt[3:2]==1) begin
// half array
if ($dimensions (array_lt[0:WA/2-1]) != 3) $stop;
if ($bits (array_lt[0:WA/2-1]) != WA/2*WB*WC) $stop;
if ((dim>=1)&&(dim<=3)) begin
if ($left (array_lt[0:WA/2-1], dim) != 0 ) $stop;
if ($right (array_lt[0:WA/2-1], dim) != wdt-1) $stop;
if ($low (array_lt[0:WA/2-1], dim) != 0 ) $stop;
if ($high (array_lt[0:WA/2-1], dim) != wdt-1) $stop;
if ($increment (array_lt[0:WA/2-1], dim) != -1 ) $stop;
if ($size (array_lt[0:WA/2-1], dim) != wdt ) $stop;
end
end else if (cnt[3:2]==2) begin
// single array element
if ($dimensions (array_lt[0]) != 2) $stop;
if ($bits (array_lt[0]) != WB*WC) $stop;
if ((dim>=2)&&(dim<=3)) begin
if ($left (array_lt[0], dim-1) != 0 ) $stop;
if ($right (array_lt[0], dim-1) != wdt-1) $stop;
if ($low (array_lt[0], dim-1) != 0 ) $stop;
if ($high (array_lt[0], dim-1) != wdt-1) $stop;
if ($increment (array_lt[0], dim-1) != -1 ) $stop;
if ($size (array_lt[0], dim-1) != wdt ) $stop;
end
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("cnt[30:4]=%0d slc=%0d dim=%0d wdt=%0d\n", cnt[30:4], slc, dim, wdt);
`endif
if (cnt[30:4]==1) begin
// big endian
if (slc==0) begin
// full array
`checkh($dimensions (array_bg), 3);
`checkh($bits (array_bg), WA*WB*WC);
if ((dim>=1)&&(dim<=3)) begin
`checkh($left (array_bg, dim), wdt+1);
`checkh($right (array_bg, dim), 2 );
`checkh($low (array_bg, dim), 2 );
`checkh($high (array_bg, dim), wdt+1);
`checkh($increment (array_bg, dim), 1 );
`checkh($size (array_bg, dim), wdt );
end
end else if (slc==1) begin
// single array element
`checkh($dimensions (array_bg[2]), 2);
`checkh($bits (array_bg[2]), WB*WC);
if ((dim>=2)&&(dim<=3)) begin
`checkh($left (array_bg[2], dim-1), wdt+1);
`checkh($right (array_bg[2], dim-1), 2 );
`checkh($low (array_bg[2], dim-1), 2 );
`checkh($high (array_bg[2], dim-1), wdt+1);
`checkh($increment (array_bg[2], dim-1), 1 );
`checkh($size (array_bg[2], dim-1), wdt );
end
`ifndef VERILATOR // Unsupported slices don't maintain size correctly
end else if (slc==2) begin
// half array
`checkh($dimensions (array_bg[WA/2+1:2]), 3);
`checkh($bits (array_bg[WA/2+1:2]), WA/2*WB*WC);
if ((dim>=1)&&(dim<=3)) begin
`checkh($left (array_bg[WA/2+1:2], dim), wdt+1);
`checkh($right (array_bg[WA/2+1:2], dim), 2 );
`checkh($low (array_bg[WA/2+1:2], dim), 2 );
`checkh($high (array_bg[WA/2+1:2], dim), wdt+1);
`checkh($increment (array_bg[WA/2+1:2], dim), 1 );
`checkh($size (array_bg[WA/2+1:2], dim), wdt);
end
`endif
end
end else if (cnt[30:4]==2) begin
// little endian
if (slc==0) begin
// full array
`checkh($dimensions (array_lt), 3);
`checkh($bits (array_lt), WA*WB*WC);
if ((dim>=1)&&(dim<=3)) begin
`checkh($left (array_lt, dim), 2 );
`checkh($right (array_lt, dim), wdt+1);
`checkh($low (array_lt, dim), 2 );
`checkh($high (array_lt, dim), wdt+1);
`checkh($increment (array_lt, dim), -1 );
`checkh($size (array_lt, dim), wdt );
end
end else if (slc==1) begin
// single array element
`checkh($dimensions (array_lt[2]), 2);
`checkh($bits (array_lt[2]), WB*WC);
if ((dim>=2)&&(dim<=3)) begin
`checkh($left (array_lt[2], dim-1), 2 );
`checkh($right (array_lt[2], dim-1), wdt+1);
`checkh($low (array_lt[2], dim-1), 2 );
`checkh($high (array_lt[2], dim-1), wdt+1);
`checkh($increment (array_lt[2], dim-1), -1 );
`checkh($size (array_lt[2], dim-1), wdt );
end
`ifndef VERILATOR // Unsupported slices don't maintain size correctly
end else if (slc==2) begin
// half array
`checkh($dimensions (array_lt[2:WA/2+1]), 3);
`checkh($bits (array_lt[2:WA/2+1]), WA/2*WB*WC);
if ((dim>=1)&&(dim<=3)) begin
`checkh($left (array_lt[2:WA/2+1], dim), 2 );
`checkh($right (array_lt[2:WA/2+1], dim), wdt+1);
`checkh($low (array_lt[2:WA/2+1], dim), 2 );
`checkh($high (array_lt[2:WA/2+1], dim), wdt+1);
`checkh($increment (array_lt[2:WA/2+1], dim), -1 );
`checkh($size (array_lt[2:WA/2+1], dim), wdt );
end
`endif
end
end
end
endmodule
-2
View File
@@ -7,8 +7,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug448");
compile (
);
+4 -4
View File
@@ -39,7 +39,9 @@ module array_test
input clk;
// verilator lint_off LITENDIAN
reg [7:0] a [LEFT:RIGHT];
// verilator lint_on LITENDIAN
integer l;
integer r;
@@ -54,10 +56,8 @@ module array_test
$write ("$left (a) = %d, $right (a) = %d, $size (a) = %d\n", l, r, s);
`endif
if ((l == LEFT) && (r == RIGHT) && (s == (RIGHT - LEFT + 1))) begin
$write("*-* All Finished *-*\n");
end
if ((l != LEFT) || (r != RIGHT) || (s != (RIGHT - LEFT + 1))) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+3 -5
View File
@@ -7,14 +7,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} and $Self->unsupported("Verilator unsupported, bind");
compile (
);
);
execute (
check_finished=>1,
);
check_finished=>1,
);
ok(1);
1;
+25 -5
View File
@@ -3,7 +3,14 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module t;
bit a_finished;
bit b_finished;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
wire [31:0] o;
wire si = 1'b0;
@@ -18,6 +25,13 @@ module t;
// Inputs
.si (si));
always @ (posedge clk) begin
if (!a_finished) $stop;
if (!b_finished) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module InstModule (
@@ -28,10 +42,7 @@ module InstModule (
endmodule
program Prog (input si);
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
initial a_finished = 1'b1;
endprogram
module ExampInst (o,i);
@@ -55,3 +66,12 @@ module ExampInst (o,i);
endmodule
// Check bind at top level
bind InstModule Prog2 instProg2
(/*AUTOBIND*/
.si (si));
// Check program declared after bind
program Prog2 (input si);
initial b_finished = 1'b1;
endprogram
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+92
View File
@@ -0,0 +1,92 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Ed Lander.
// verilator lint_off WIDTH
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [7:0] p1;
reg [7:0] p2;
reg [7:0] p3;
initial begin
p1 = 8'h01;
p2 = 8'h02;
p3 = 8'h03;
end
parameter int param1 = 8'h11;
parameter int param2 = 8'h12;
parameter int param3 = 8'h13;
targetmod i_targetmod (/*AUTOINST*/
// Inputs
.clk (clk));
//Binding i_targetmod to mycheck --instantiates i_mycheck inside i_targetmod
//param1 not over-riden (as mycheck) (=> 0x31)
//param2 explicitly bound to targetmod value (=> 0x22)
//param3 explicitly bound to top value (=> 0x13)
//p1 implictly bound (.*), takes value from targetmod (=> 0x04)
//p2 explictly bound to targetmod (=> 0x05)
//p3 explictly bound to top (=> 0x03)
// Alternative unsupported form is i_targetmod
bind targetmod mycheck
#(
.param2(param2),
.param3(param3)
)
i_mycheck (.p2(p2), .p3(p3), .*);
endmodule
module targetmod (input clk);
reg [7:0] p1;
reg [7:0] p2;
reg [7:0] p3;
parameter int param1 = 8'h21;
parameter int param2 = 8'h22;
parameter int param3 = 8'h23;
initial begin
p1 = 8'h04;
p2 = 8'h05;
p3 = 8'h06;
end
endmodule
module mycheck (/*AUTOARG*/
// Inputs
clk, p1, p2, p3
);
input clk;
input [7:0] p1;
input [7:0] p2;
input [7:0] p3;
parameter int param1 = 8'h31;
parameter int param2 = 8'h32;
parameter int param3 = 8'h33;
always @ (posedge clk) begin
`checkh(param1,8'h31);
`checkh(param2,8'h22);
`checkh(param3,8'h23);
`checkh(p1,8'h04);
`checkh(p2,8'h05);
`checkh(p3,8'h06);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+2 -3
View File
@@ -11,9 +11,8 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_bitsel_const_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: b
.*
%Error: Exiting due to.*',
'%Error: t/t_bitsel_const_bad.v:\d+: Illegal bit or array select; type does not have a bit range, or bad dimension: type is logic
.*%Error: Exiting due to.*',
);
ok(1);
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+32
View File
@@ -0,0 +1,32 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// A test case for struct signal bit selection.
//
// This test is to check that bit selection of multi-dimensional signal inside
// of a struct works.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Jie Xu.
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [1:0][15:0] channel;
logic others;
} buss_t;
buss_t b;
reg [7:0] a;
initial begin
b = {16'h8765,16'h4321,1'b1};
a = b.channel[0][8+:8];
if (a != 8'h43) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+44
View File
@@ -0,0 +1,44 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Wilson Snyder.
module t (/*AUTOARG*/);
typedef struct packed {
logic [3:2] a;
logic [5:4][3:2] b;
} ab_t;
typedef ab_t [7:6] c_t; // array of structs
typedef struct packed {
c_t [17:16] d;
} e_t;
`define checkb(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='b%x exp='b%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
initial begin
e_t e;
`checkh($bits(ab_t),6);
`checkh($bits(c_t),12);
`checkh($bits(e_t),24);
`checkh($bits(e), 24);
`checkh($bits(e.d[17]),12);
`checkh($bits(e.d[16][6]),6);
`checkh($bits(e.d[16][6].b[5]),2);
`checkh($bits(e.d[16][6].b[5][2]), 1);
//
e = 24'b101101010111010110101010;
`checkb(e, 24'b101101010111010110101010);
e.d[17] = 12'b111110011011;
`checkb(e, 24'b111110011011010110101010);
e.d[16][6] = 6'b010101;
`checkb(e, 24'b111110011011010110010101);
e.d[16][6].b[5] = 2'b10;
`checkb(e, 24'b111110011011010110011001);
e.d[16][6].b[5][2] = 1'b1;
//
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+42
View File
@@ -0,0 +1,42 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// A test case for struct signal bit selection.
//
// This test is to check that bit selection of multi-dimensional signal inside
// of a packed struct works. Currently +: and -: blow up with packed structs.
//
// This file ONLY is placed into the Public Domain, for any use, without
// warranty, 2013 by Jie Xu.
module t(/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [15:0] channel;
logic [15:0] others;
} buss_t;
buss_t b;
reg [7:0] a;
reg [7:0] c;
reg [7:0] d;
initial begin
b = {16'h8765,16'h4321};
a = b[19:12]; // This works
c = b[8+:8]; // This fails
d = b[11-:8]; // This fails
if ((a == 8'h54) && (c == 8'h43) && (d == 8'h32)) begin
$write("*-* All Finished *-*\n");
$finish;
end
else begin
$stop;
end
end
endmodule
+3
View File
@@ -10,11 +10,14 @@ module t;
mc_t o;
logic [15:0] allones = 16'hffff;
initial begin
if (4'shf > 4'sh0) $stop;
if (signed'(4'hf) > 4'sh0) $stop;
if (4'hf < 4'h0) $stop;
if (unsigned'(4'shf) < 4'h0) $stop;
if (4'(allones) !== 4'hf) $stop;
o = tocast_t'(4'b1);
if (o != 4'b1) $stop;
-1
View File
@@ -17,7 +17,6 @@ compile (
%Warning-CDCRSTLOGIC: See details in obj_dir/t_cdc_async_bad/Vt_cdc_async_bad__cdc.txt
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6a_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst6b_bad_n
%Warning-CDCRSTLOGIC: t/t_cdc_async_bad.v:\d+: Logic in path that feeds async reset, via signal: v.rst3_bad_n
%Error: Exiting due to.*',
);
+5 -2
View File
@@ -21,9 +21,8 @@ double sc_time_stamp () {
VM_PREFIX* topp = NULL;
void clockit(int clk1, int clk0) {
#ifdef T_CLK_2IN_VEC
topp->clks = clk1<<1 | clk0;
#else
#ifndef T_CLK_2IN_VEC
topp->c1 = clk1;
topp->c0 = clk0;
#endif
@@ -38,6 +37,7 @@ int main (int argc, char *argv[]) {
topp = new VM_PREFIX;
topp->check = 0;
clockit(0,0);
main_time+=10;
Verilated::debug(0);
@@ -49,6 +49,9 @@ int main (int argc, char *argv[]) {
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 0);
clockit(0, 0);
}
topp->check = 1;
clockit(0,0);
+7 -9
View File
@@ -7,18 +7,16 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["$Self->{t_dir}/$Self->{name}.cpp"],
verilator_flags2 => ["--exe"],
);
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe","$Self->{t_dir}/$Self->{name}.cpp"],
vcs_flags2 => ['-assert'],
);
execute (
check_finished=>1,
);
check_finished=>1,
);
ok(1);
1;
+111 -19
View File
@@ -3,19 +3,75 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
module t (
`ifdef T_CLK_2IN_VEC
input [1:0] clks,
`ifndef VERILATOR
module t;
/*AUTOREGINPUT*/
// Beginning of automatic reg inputs (for undeclared instantiated-module inputs)
reg c0; // To t2 of t2.v
reg c1; // To t2 of t2.v
reg check; // To t2 of t2.v
reg [1:0] clks; // To t2 of t2.v
// End of automatics
t2 t2 (/*AUTOINST*/
// Inputs
.clks (clks[1:0]),
.c0 (c0),
.c1 (c1),
.check (check));
task clockit (input v1, v0);
c1 = v1;
c0 = v0;
clks[1] = v1;
clks[0] = v0;
`ifdef TEST_VERBOSE $write("[%0t] c1=%x c0=%x\n", $time,v0,v1); `endif
#1;
endtask
initial begin
check = '0;
c0 = '0;
c1 = '0;
clks = '0;
#1
t2.clear();
#10;
for (int i=0; i<2; i++) begin
clockit(0, 0);
clockit(0, 0);
clockit(0, 1);
clockit(1, 1);
clockit(0, 0);
clockit(1, 1);
clockit(1, 0);
clockit(0, 0);
clockit(1, 0);
clockit(0, 1);
clockit(0, 0);
end
check = 1;
clockit(0, 0);
end
endmodule
`endif
`ifdef VERILATOR
`define t2 t
`else
`define t2 t2
`endif
module `t2 (
input [1:0] clks,
input c0,
input c1,
`endif
input check
);
`ifdef T_CLK_2IN_VEC
wire c0 = clks[0];
wire c1 = clks[1];
wire clk0 = clks[0];
wire clk1 = clks[1];
`else
wire clk0 = c0;
wire clk1 = c1;
`endif
integer p0 = 0;
@@ -24,46 +80,82 @@ module t (
integer n0 = 0;
integer n1 = 0;
integer n01 = 0;
integer vp = 0;
integer vn = 0;
integer vpn = 0;
task clear;
`ifdef TEST_VERBOSE $display("[%0t] clear\n",$time); `endif
p0 = 0;
p1 = 0;
p01 = 0;
n0 = 0;
n1 = 0;
n01 = 0;
vp = 0;
vn = 0;
vpn = 0;
endtask
`define display_counts(text) begin \
$write("[%0t] ",$time); \
`ifdef T_CLK_2IN_VEC $write(" 2v "); `endif \
$write(text); \
$write(": %0d %0d %0d %0d %0d %0d\n", p0, p1, p01, n0, n1, n01); \
$write(": %0d %0d %0d %0d %0d %0d %0d %0d %0d\n", p0, p1, p01, n0, n1, n01, vp, vn, vpn); \
end
always @ (posedge c0) begin
always @ (posedge clk0) begin
p0 = p0 + 1; // Want blocking, so don't miss clock counts
`ifdef TEST_VERBOSE `display_counts("posedge 0"); `endif
end
always @ (posedge c1) begin
always @ (posedge clk1) begin
p1 = p1 + 1;
`ifdef TEST_VERBOSE `display_counts("posedge 1"); `endif
end
always @ (posedge c0 or posedge c1) begin
always @ (posedge clk0 or posedge clk1) begin
p01 = p01 + 1;
`ifdef TEST_VERBOSE `display_counts("posedge *"); `endif
end
always @ (negedge c0) begin
always @ (negedge clk0) begin
n0 = n0 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge 0"); `endif
end
always @ (negedge c1) begin
always @ (negedge clk1) begin
n1 = n1 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge 1"); `endif
end
always @ (negedge c0 or negedge c1) begin
always @ (negedge clk0 or negedge clk1) begin
n01 = n01 + 1;
`ifdef TEST_VERBOSE `display_counts("negedge *"); `endif
end
`ifndef VERILATOR
always @ (posedge clks) begin
vp = vp + 1;
`ifdef TEST_VERBOSE `display_counts("pos vec"); `endif
end
always @ (negedge clks) begin
vn = vn + 1;
`ifdef TEST_VERBOSE `display_counts("neg vec"); `endif
end
always @ (posedge clks or negedge clks) begin
vpn = vpn + 1;
`ifdef TEST_VERBOSE `display_counts("or vec"); `endif
end
`endif
always @ (posedge check) begin
if (p0!=4) $stop;
if (p1!=4) $stop;
if (p01!=6) $stop;
if (n0!=4) $stop;
if (n1!=4) $stop;
if (n01!=6) $stop;
if (p0!=6) $stop;
if (p1!=6) $stop;
if (p01!=10) $stop;
if (n0!=6) $stop;
if (n1!=6) $stop;
if (n01!=10) $stop;
`ifndef VERILATOR
if (vp!=6) $stop;
if (vn!=6) $stop;
if (vpn!=12) $stop;
`endif
$write("*-* All Finished *-*\n");
end
+2 -4
View File
@@ -9,13 +9,11 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
top_filename("t/t_clk_2in.v");
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
v_flags2 => ["+define+T_CLK_2IN_VEC=1 $Self->{t_dir}/t_clk_2in.cpp"],
verilator_flags2 => ["--exe"],
v_flags2 => ["+define+T_CLK_2IN_VEC=1"],
verilator_flags2 => ["--exe $Self->{t_dir}/t_clk_2in.cpp"],
);
execute (
+1 -1
View File
@@ -18,7 +18,7 @@ execute (
# Read the input .v file and do any CHECK_COVER requests
inline_checks();
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 24)
file_grep ($Self->{stats}, qr/Coverage, Toggle points joined\s+(\d+)/i, 25)
if $Self->{vlt};
ok(1);
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["--stats"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 4);
}
ok(1);
1;
+61
View File
@@ -0,0 +1,61 @@
// DESCRIPTION: Verilator: Dedupe optimization test.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// Contributed 2012 by Varun Koyyalagunta, Centaur Technology.
module t(res,d,clk,en);
output res;
input d,en,clk;
wire q0,q1,q2,q3;
flop_gated_latch f0(q0,d,clk,en);
flop_gated_latch f1(q1,d,clk,en);
flop_gated_flop f2(q2,d,clk,en);
flop_gated_flop f3(q3,d,clk,en);
assign res = (q0 + q1) * (q2 - q3);
endmodule
module flop_gated_latch(q,d,clk,en);
input d, clk, en;
output q;
wire gated_clock;
clock_gate_latch clock_gate(gated_clock, clk, en);
always @(posedge gated_clock) begin
q <= d;
end
endmodule
module flop_gated_flop(q,d,clk,en);
input d, clk, en;
output q;
wire gated_clock;
clock_gate_flop clock_gate(gated_clock, clk, en);
always @(posedge gated_clock) begin
q <= d;
end
endmodule
module clock_gate_latch (gated_clk, clk, clken);
output gated_clk;
input clk, clken;
reg clken_latched /*verilator clock_enable*/;
assign gated_clk = clk & clken_latched ;
wire clkb = ~clk;
always @(clkb or clken)
if(clkb) clken_latched = clken;
endmodule
module clock_gate_flop (gated_clk, clk, clken);
output gated_clk;
input clk, clken;
reg clken_r /*verilator clock_enable*/;
assign gated_clk = clk & clken_r ;
always @(negedge clk)
clken_r <= clken;
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["--stats"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate sigs deduped\s+(\d+)/i, 6);
}
ok(1);
1;
+123
View File
@@ -0,0 +1,123 @@
// DESCRIPTION: Verilator: Dedupe optimization test.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty.
// Contributed 2012 by Varun Koyyalagunta, Centaur Technology.
//
// Test consists of the follow logic tree, which has many obvious
// places for dedupe:
/*
output
+
--------------/ \--------------
/ \
+ +
----/ \----- ----/ \----
/ + / +
+ / \ + / \
-/ \- a b -/ \- a b
/ \ / \
+ + + +
/ \ / \ / \ / \
a b c d a b c d
*/
module t(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left,right;
add add(sum,left,right,clk);
l l(left,a,b,c,d,clk);
r r(right,a,b,c,d,clk);
endmodule
module l(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
ll ll(left,a,b,c,d,clk);
lr lr(right,a,b,c,d,clk);
endmodule
module ll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
lll lll(left,a,b,c,d,clk);
llr llr(right,a,b,c,d,clk);
endmodule
module lll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module llr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,c,d,clk);
endmodule
module lr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module r(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
rl rl(left,a,b,c,d,clk);
rr rr(right,a,b,c,d,clk);
endmodule
module rr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add add(sum,a,b,clk);
endmodule
module rl(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
wire left, right;
add add(sum,left,right,clk);
rll rll(left,a,b,c,d,clk);
rlr rlr(right,a,b,c,d,clk);
endmodule
module rll(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add2 add(sum,a,b,clk);
endmodule
module rlr(sum,a,b,c,d,clk);
output sum;
input a,b,c,d,clk;
add2 add(sum,c,d,clk);
endmodule
module add(sum,x,y,clk);
output sum;
input x,y,clk;
reg t1,t2;
always @(posedge clk) begin
sum <= x + y;
end
endmodule
module add2(sum,x,y,clk);
output sum;
input x,y,clk;
reg t1,t2;
always @(posedge clk) begin
sum <= x + y;
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["-Wno-UNOPTFLAT"]
);
execute (
check_finished=>1,
);
ok(1);
1;
+41
View File
@@ -0,0 +1,41 @@
// DESCRIPTION: Verilator: Simple test of unoptflat
//
// Trigger the DETECTARRAY error.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Jeremy Bennett.
localparam ID_MSB = 1;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [ID_MSB:0] id;
} context_t;
context_t tsb;
assign tsb.id = {tsb.id[0], clk};
initial begin
tsb.id = 0;
end
always @(posedge clk or negedge clk) begin
`ifdef TEST_VERBOSE
$write("tsb.id = %x\n", tsb.id);
`endif
if (tsb.id[1] != 0) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["-Wno-UNOPTFLAT"]
);
execute (
check_finished=>1,
);
ok(1);
1;
+43
View File
@@ -0,0 +1,43 @@
// DESCRIPTION: Verilator: Simple test of unoptflat
//
// This should trigger the DETECTARRAY error like t_detectarray_1.v, but in
// fact it casuses a broken link error. The only difference is that the struct
// is defined using a constant rather than a localparam.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2013 by Jeremy Bennett.
localparam ID_MSB = 1;
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
typedef struct packed {
logic [1:0] id;
} context_t;
context_t tsb;
assign tsb.id = {tsb.id[0], clk};
initial begin
tsb.id = 0;
end
always @(posedge clk or negedge clk) begin
`ifdef TEST_VERBOSE
$write("tsb.id = %x\n", tsb.id);
`endif
if (tsb.id[1] != 0) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+4 -1
View File
@@ -54,9 +54,12 @@ sub printfll {
my %names;
foreach my $line (split /\n/, $grep) {
next if $line !~ /%[a-z0-9]*ll/;
next if $line !~ /\blong\S+long\b/; # Assume a cast
print "$line\n";
if ($line =~ /^([^:]+)/) {
$names{$1} = 1;
print "$line\n";
} else {
$names{UNKNOWN} = 1;
}
}
if (keys %names) {

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