Compare commits

...
70 Commits
Author SHA1 Message Date
Wilson Snyder b46f656d17 Version bump. 2014-05-11 16:51:56 -04:00
Wilson Snyder 58fd602bbd Fix flex warning 2014-05-11 09:36:39 -04:00
Wilson Snyder 9cc95704cd Tests: Add t_inst_dff parameter width change test. 2014-05-11 09:18:04 -04:00
Wilson Snyder 5f5a3dbb0a Tests: More width testing. 2014-05-10 21:51:21 -04:00
Wilson Snyder f8f53df4ec Fix X/Z extension with WIDTH param mismatch, bug764. 2014-05-10 21:38:36 -04:00
Wilson Snyder 56b85cc63c Suppress WIDTH warnings on 'x = 1<<a' 2014-05-10 17:19:57 -04:00
Wilson Snyder 90aca97e66 Internals: Flip sense of warnOn. No functional change intended. 2014-05-10 17:12:04 -04:00
Wilson Snyder 6ce2a52c5f Fix shift-right optmiization, bug763. 2014-05-10 16:38:20 -04:00
Wilson Snyder 1f56312132 Fix -Wno-UNOPTFLAT change detection with 64-bits, bug762. 2014-05-10 12:40:35 -04:00
Wilson Snyder 3aa290cddb Add error on power > 64-bits, bug761. 2014-05-10 08:24:51 -04:00
Wilson Snyder 1d1eb4fedb Testcase for bug756. 2014-05-10 08:20:10 -04:00
Wilson Snyder 266ff41386 For --cdc, don't show data types in dump file. 2014-05-10 07:50:04 -04:00
Wilson Snyder 02331e5536 Fix begin_keywords 1800+VAMS, msg1211. 2014-05-08 07:15:44 -04:00
Wilson Snyder 621c51589a Fix shift by x, bug760. 2014-05-04 08:50:44 -04:00
Wilson Snyder 4a58e859a4 Fix concats with no argments mis-sign extending, bug759. 2014-05-03 20:20:15 -04:00
Wilson Snyder 48d393d8f5 Tests: test_verilated must match signs on == sides. 2014-05-03 20:11:38 -04:00
Wilson Snyder 321552d998 Fix wide modulus uninit var 2014-05-03 20:09:45 -04:00
Wilson Snyder a985a1f9f5 Fix >>> sign extension based on expression, bug754. 2014-05-03 09:25:12 -04:00
Wilson Snyder d532a36739 Fix change detection error on unions, bug758. 2014-05-02 08:14:23 -04:00
Wilson Snyder b631b5927b Fix shift width extension, broke recent commit, bug754. 2014-04-30 22:47:01 -04:00
Wilson Snyder adb39ceb98 Internals: cppcheck clean and add cppcheck_filtered 2014-04-29 22:59:38 -04:00
Wilson Snyder 84b91b19ca Commentary 2014-04-29 22:02:48 -04:00
Wilson Snyder aaea68d3d6 Rewrite V3Width for better spec adherence when -Wno-WIDTH. 2014-04-29 22:01:50 -04:00
Wilson Snyder 2accba2e71 Update WIDTH warning message formats to match future commit. 2014-04-29 21:11:57 -04:00
Wilson Snyder 8f4f4eb5ae Fix coredump on undriven vector[-1]. 2014-04-29 21:09:44 -04:00
Wilson Snyder c5aabb3c6e Tests: Move most old test_v tests into test_regress. 2014-04-29 19:47:26 -04:00
Wilson Snyder 60c2d136e1 Internals: V3Width renames. Fix CASEEQ signing. 2014-04-26 16:52:09 -04:00
Wilson Snyder cae6ec16ba Commentary 2014-04-26 13:59:50 -04:00
Wilson Snyder 30601c77d4 tests: Add driver --unsupported 2014-04-22 20:50:22 -04:00
Wilson Snyder b0f4cf3c9c Support {} in always sensitivity lists, bug745. 2014-04-21 19:39:28 -04:00
Wilson Snyder c41dfcf6ad Fix assertions broken from bug725, bug743. 2014-04-16 22:33:25 -04:00
Wilson Snyder 2e10555f03 Fix tracing of packed arrays without --trace-structs, bug742. 2014-04-15 20:20:45 -04:00
Wilson Snyder 6b2ee0fcf3 Fix reporting struct members as reserved words, bug741. 2014-04-15 19:35:44 -04:00
Wilson Snyder 0dbdbffba7 Fix double I/O port warnings. 2014-04-15 18:50:04 -04:00
Wilson Snyder 9c5dd8d767 Fix RHEL5.6 compile warnings. 2014-04-15 18:18:36 -04:00
Glen Gibb fff0ebb5f3 Internals: Add AstReplicate dtype init.
Signed-off-by: Wilson Snyder <[email protected]>
2014-04-10 17:54:52 -04:00
Glen Gibb d34275150c Support streaming operators, bug649.
Signed-off-by: Wilson Snyder <[email protected]>
2014-04-09 20:29:35 -04:00
Wilson Snyder d04eb977c2 Fix mis-extending red xor/xand operators. 2014-04-09 07:58:46 -04:00
Wilson Snyder fb4928b2f5 Fix power calculation; setAllOnes should not set hidden state bits in V3Number. 2014-04-08 20:28:16 -04:00
Wilson Snyder 5c39420d91 Re-fix bug729 due to bug733; other internal sign extension cleanups too. 2014-04-07 21:34:00 -04:00
Wilson Snyder 14fcfd8a40 Fix signed extension problem with -Wno-WIDTH, bug729. 2014-04-05 15:52:05 -04:00
Wilson Snyder ff19dd94f9 Fix power operator calculation, bug730. 2014-04-05 15:44:49 -04:00
Wilson Snyder b6913ff9b3 With high c-splits, even split blank functions. 2014-04-05 12:41:00 -04:00
Wilson Snyder 4573fd3069 Tests: Fix unsupported items. 2014-04-03 22:03:03 -04:00
Wilson Snyder 6cf6d9f7e1 Fix modport function import not-found error. 2014-04-03 21:53:39 -04:00
Wilson Snyder 28e35a64ea Support parameter arrays, bug683. 2014-04-01 23:16:16 -04:00
Wilson Snyder 091818483a Order initial statements based on variables used. Merge from bug683 branch. 2014-04-01 22:01:25 -04:00
Wilson Snyder 3b43556c41 Internals: Remove dead NEW_ORDERING code. 2014-03-31 20:29:35 -04:00
Wilson Snyder ed39c66715 Internals: Make const iterator to fix missed-edits on dump. Merge from bug683 branch. 2014-03-31 20:24:05 -04:00
Wilson Snyder 446b0e4e5e Support '{} assignment pattern on arrays, bug355. 2014-03-30 20:41:20 -04:00
Wilson Snyder 6e3e8318d0 Internals: Add dtype to InitArray; misc Slice cleanups. From bug355 branch. 2014-03-30 20:28:51 -04:00
Wilson Snyder 17b8b660f0 Internals: Fix assignment pattern replication. From bug355 branch. 2014-03-30 10:20:12 -04:00
Wilson Snyder 40bceea68a Fix missing coverage line on else-if, bug727. 2014-03-29 11:04:13 -04:00
Holger Waechtler b655c17c09 Fix Mac OS-X test issues.
Signed-off-by: Wilson Snyder <[email protected]>
2014-03-29 08:30:08 -04:00
Wilson Snyder a3813f94fc Add PINCONNECTEMPTY warning. 2014-03-27 21:36:52 -04:00
Wilson Snyder c70540a825 Fix Mac OS-X include compile issue. 2014-03-27 21:07:59 -04:00
Holger Waechtler 9caffe330b Fix Mac OS-X test issues.
Signed-off-by: Wilson Snyder <[email protected]>
2014-03-24 20:19:43 -04:00
Wilson Snyder 8d8c5da812 Add assertions on 'unique if', bug725. 2014-03-16 21:38:29 -04:00
Wilson Snyder 55bb766c15 Fix escaped newline in assertion failures. 2014-03-16 20:57:15 -04:00
Wilson Snyder c18df68ead Fix C++-2011 warnings. 2014-03-15 14:50:03 -04:00
Wilson Snyder 3996e94c39 Fix Bison 4.0 warnings. From Verilog-Perl. 2014-03-15 14:23:19 -04:00
Wilson Snyder 1bdf017f9e PSL is no longer supported, please use System Verilog assertions. 2014-03-14 21:14:24 -04:00
Wilson Snyder 93790c1dc6 Fix tracing of package variables and real arrays. 2014-03-14 20:36:47 -04:00
Wilson Snyder ba8c11b25d Fix scope creating extra vars for package variables. See next trace commit for test. 2014-03-14 20:24:21 -04:00
Wilson Snyder ca57edfa0b Fix assignment temporaries not using real types. 2014-03-14 20:22:06 -04:00
Wilson Snyder ccb6545c32 tests: Fix bogus set of output. 2014-03-14 20:19:56 -04:00
Wilson Snyder d146dbc9d7 Commentary. 2014-03-14 20:13:41 -04:00
Glen Gibb b4eaaccc88 Documentation fixes, bug723.
Signed-off-by: Wilson Snyder <[email protected]>
2014-03-14 07:17:03 -04:00
Wilson Snyder c9ed9e74f2 Add --no-trace-params. 2014-03-13 20:08:43 -04:00
Wilson Snyder 587c7c70f5 devel release 2014-03-11 19:52:28 -04:00
162 changed files with 5710 additions and 2279 deletions
+57 -7
View File
@@ -3,6 +3,56 @@ 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.860 2014-05-11
** PSL is no longer supported, please use System Verilog assertions.
** Support '{} assignment pattern on arrays, bug355.
** Support streaming operators, bug649. [Glen Gibb]
** Fix expression problems with -Wno-WIDTH, bug729, bug736, bug737, bug759.
Where WIDTH warnings were ignored this might result in different
warning messages and results, though it should better match the spec.
[Clifford Wolf]
*** Add --no-trace-params.
*** Add assertions on 'unique if', bug725. [Jeff Bush]
*** Add PINCONNECTEMPTY warning. [Holger Waechtler]
*** Support parameter arrays, bug683. [Jeremy Bennett]
*** Fix begin_keywords "1800+VAMS", msg1211.
**** Documentation fixes, bug723. [Glen Gibb]
**** Support {} in always sensitivity lists, bug745. [Igor Lesik]
**** Fix tracing of package variables and real arrays.
**** Fix tracing of packed arrays without --trace-structs, bug742. [Jie Xu]
**** Fix missing coverage line on else-if, bug727. [Sharad Bagri]
**** Fix modport function import not-found error.
**** Fix power operator calculation, bug730, bug735. [Clifford Wolf]
**** Fix reporting struct members as reserved words, bug741. [Chris Randall]
**** Fix change detection error on unions, bug758. [Jie Xu]
**** Fix -Wno-UNOPTFLAT change detection with 64-bits, bug762. [Clifford Wolf]
**** Fix shift-right optimization, bug763. [Clifford Wolf]
**** Fix Mac OS-X test issues. [Holger Waechtler]
**** Fix C++-2011 warnings.
* Verilator 3.856 2014-03-11
*** Support case inside, bug708. [Jan Egil Ruud]
@@ -117,17 +167,17 @@ indicates the contributor was also the author of the fix; Thanks!
* Verilator 3.847 2013-05-11
*** Add ALWCOMBORDER warning. [KC Buckenmaier]
*** Add --pins-sc-uint and --pins-sc-biguint, bug638. [Alex Hornung]
**** Support "signal[vec]++".
**** Fix simulation error when inputs and MULTIDRIVEN, bug634. [Ted Campbell]
**** Fix module resolution with __, bug631. [Jason McMullan]
**** Fix packed array non-zero right index select crash, bug642. [Krzysztof Jankowski]
**** Fix nested union crash, bug643. [Krzysztof Jankowski]
@@ -443,7 +493,7 @@ indicates the contributor was also the author of the fix; Thanks!
*** Support $fopen and I/O with integer instead of `verilator_file_descriptor.
*** Support coverage in -cc and -sc output modes. [John Li]
Note this requires SystemPerl 1.338 or newer.
Note this requires SystemPerl 1.338 or newer.
**** Fix vpi_register_cb using bad s_cb_data, bug370. [by Thomas Watts]
+3 -2
View File
@@ -120,7 +120,8 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
include/.*ignore \
include/vltstd/*.[chv]* \
.*attributes */.*attributes */*/.*attributes \
src/.*ignore src/*.in src/*.cpp src/*.[chly] src/astgen src/bisonpre src/*fix \
src/.*ignore src/*.in src/*.cpp src/*.[chly] \
src/astgen src/bisonpre src/*fix src/cppcheck_filtered \
src/.gdbinit \
src/*.pl src/*.pod \
test_*/.*ignore test_*/Makefile* test_*/*.cpp \
@@ -400,7 +401,7 @@ endif
endif
# Use --xml flag to see the cppcheck code to use for suppression
CPPCHECK = cppcheck
CPPCHECK = src/cppcheck_filtered
CPPCHECK_FLAGS = --enable=all --inline-suppr --suppress=unusedScopedObject --suppress=cstyleCast
CPPCHECK_FLAGS += --xml
CPPCHECK_CPP = $(wildcard $(srcdir)/include/*.cpp $(srcdir)/src/*.cpp)
+3
View File
@@ -31,11 +31,13 @@ Configure/Make/Install
* Distribute with flex/bison already expanded?
Flex library not needed. Probably too difficult to be worth it.
* Integrate SystemPerl coverage
see the SystemPerl git branch coverage_only
(Note in /usr/include there are no upper cased include files.)
Coverage.pm -- Need all functionality, but in C?
Coverage/Item.pm -- Need all functionality, but in C?
Coverage/ItemKey.pm -- Need all functionality, but in C?
sp_preproc -- Some steps in here need to be moved to generated C
-- -- note uses Verilog::Getopt
src/Sp.cpp -- n/a
src/SpCommon.h -- mostly overlaps verilatedos.h
src/SpCoverage.cpp/h -- All needed
@@ -53,6 +55,7 @@ Testing:
* New random program generator
* Better graph viewer with search and zoom
* Port and test against opencores.org code
* // verilator debug in code so can see only tree affecting those nodes
Usability:
* Detect and pre-remove most UNOPTFLATs (4.000)
+35 -64
View File
@@ -209,7 +209,7 @@ Verilator - Convert Verilog code to C++/SystemC
=head1 DESCRIPTION
Verilator converts synthesizable (not behavioral) Verilog code, plus some
Synthesis, SystemVerilog and a small subset of Verilog AMS and Sugar/PSL
Synthesis, SystemVerilog and a small subset of Verilog AMS
assertions, into C++, SystemC or SystemPerl code. It is not a complete
simulator, just a compiler.
@@ -259,7 +259,7 @@ descriptions in the next sections for more information.
--coverage Enable all coverage
--coverage-line Enable line coverage
--coverage-toggle Enable toggle coverage
--coverage-user Enable PSL/SVL user coverage
--coverage-user Enable SVL user coverage
--coverage-underscore Enable coverage of _signals
-D<var>[=<value>] Set preprocessor define
--debug Enable debugging
@@ -311,7 +311,6 @@ descriptions in the next sections for more information.
--prefix <topname> Name of top level class
--profile-cfuncs Name functions for profiling
--private Debugging; see docs
--psl Enable PSL parsing
--public Debugging; see docs
--report-unoptflat Extra diagnostics for UNOPTFLAT
--savable Enable model save-restore
@@ -325,6 +324,7 @@ descriptions in the next sections for more information.
--trace-depth <levels> Depth of tracing
--trace-max-array <depth> Maximum bit width for tracing
--trace-max-width <width> Maximum array depth for tracing
--trace-params Enable tracing parameters
--trace-structs Enable tracing structure names
--trace-underscore Enable tracing of _signals
-U<var> Undefine preprocessor define
@@ -409,8 +409,7 @@ C<+1364-1995ext+> etc. specify both the syntax I<and> semantics to be used.
=item --assert
Enable all assertions, includes enabling the --psl flag. (If psl is not
desired, but other assertions are, use --assert --nopsl.)
Enable all assertions.
See also --x-assign and --x-initial-edge; setting "--x-assign unique"
and/or "--x-initial-edge" may be desirable.
@@ -562,14 +561,13 @@ signals are not covered. See also --trace-underscore.
=item --coverage-user
Enables user inserted functional coverage. Currently, all functional
coverage points are specified using PSL which must be separately enabled
with --psl.
coverage points are specified using SVA which must be separately enabled
with --assert.
For example, the following PSL statement will add a coverage point, with
For example, the following statement will add a coverage point, with
the comment "DefaultClock":
// psl default clock = posedge clk;
// psl cover {cyc==9} report "DefaultClock,expect=1";
DefaultClock: cover property (@(posedge clk) cyc==3);
=item -DI<var>=I<value>
@@ -630,7 +628,7 @@ large and not desired.
=item --dump-treei <level>
Rarely needed. Enable writing .tree debug files with a specific dumping
level, 0 disbles dumps and is equivelent to "--no-dump-tree". Level 9
level, 0 disbles dumps and is equivalent to "--no-dump-tree". Level 9
enables dumping of every stage.
=item -E
@@ -902,12 +900,6 @@ statements.
Opposite of --public. Is the default; this option exists for backwards
compatibility.
=item --psl
Enable PSL parsing. Without this switch, PSL meta-comments are ignored.
See the --assert flag to enable all assertions, and --coverage-user to
enable functional coverage.
=item --public
This is only for historical debug use. Using it may result in
@@ -929,7 +921,7 @@ 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.
analyzing 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
@@ -1022,6 +1014,10 @@ Rarely needed. Specify the maximum bit width of a signal that may be
traced. Defaults to 256, as tracing large vectors may greatly slow traced
simulations.
=item --no-trace-params
Disable tracing of parameters.
=item --trace-structs
Enable tracing to show the name of packed structure, union, and packed
@@ -1099,8 +1095,9 @@ Disable the specified warning message.
Disable all lint related warning messages, and all style warnings. This is
equivalent to "-Wno-ALWCOMBORDER -Wno-CASEINCOMPLETE -Wno-CASEOVERLAP
-Wno-CASEX -Wno-CASEWITHX -Wno-CMPCONST -Wno-ENDLABEL -Wno-IMPLICIT
-Wno-LITENDIAN -Wno-PINMISSING -Wno-SYNCASYNCNET -Wno-UNDRIVEN
-Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown for Wno-style.
-Wno-LITENDIAN -Wno-PINCONNECTEMPTY -Wno-PINMISSING -Wno-SYNCASYNCNET
-Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED -Wno-WIDTH" plus the list shown for
Wno-style.
It is strongly recommended you cleanup your code rather than using this
option, it is only intended to be use when running test-cases of code
@@ -1110,8 +1107,8 @@ received from third parties.
Disable all code style related warning messages (note by default they are
already disabled). This is equivalent to "-Wno-DECLFILENAME -Wno-DEFPARAM
-Wno-INCABSPATH -Wno-PINNOCONNECT -Wno-SYNCASYNCNET -Wno-UNDRIVEN
-Wno-UNUSED -Wno-VARHIDDEN".
-Wno-INCABSPATH -Wno-PINCONNECTEMPTY -Wno-PINNOCONNECT -Wno-SYNCASYNCNET
-Wno-UNDRIVEN -Wno-UNUSED -Wno-VARHIDDEN".
=item -Wno-fatal
@@ -1190,7 +1187,7 @@ so the above C<always> block would not trigger.
While it is not good practice, there are some designs that rely on X
E<rarr> 0 triggering a C<negedge>, particularly in reset sequences. Using
--x-initial-edge with Verilator will replicate this behaviour. It will also
--x-initial-edge with Verilator will replicate this behavior. It will also
ensure that X E<rarr> 1 triggers a C<posedge>.
B<Note.> Some users have reported that using this option can affect
@@ -1975,7 +1972,7 @@ please file a bug if a feature you need is missing.
Verilator implements a very small subset of Verilog AMS (Verilog Analog and
Mixed-Signal Extensions) with the subset corresponding to those VMS
keywords with near equivelents in the Verilog 2005 or SystemVerilog 2009
keywords with near equivalents in the Verilog 2005 or SystemVerilog 2009
languages.
AMS parsing is enabled with "--language VAMS" or "--language 1800+VAMS".
@@ -1983,34 +1980,6 @@ AMS parsing is enabled with "--language VAMS" or "--language 1800+VAMS".
At present Verilator implements ceil, exp, floor, ln, log, pow, sqrt,
string, and wreal.
=head2 Sugar/PSL Support
Most future work is being directed towards improving SystemVerilog
assertions instead of PSL. If you are using these PSL features, please
contact the author as they may be depreciated in future versions.
With the --assert switch, Verilator enables support of the Property
Specification Language (PSL), specifically the simple PSL subset without
time-branching primitives. Verilator currently only converts PSL
assertions to simple "if (...) error" statements, and coverage statements
to increment the line counters described in the coverage section.
Verilator implements these keywords: assert, assume (same as assert),
default (for clocking), countones, cover, isunknown, onehot, onehot0,
report, and true.
Verilator implements these operators: -> (logical if).
Verilator does not support SEREs yet. All assertion and coverage
statements must be simple expressions that complete in one cycle. PSL
vmode/vprop/vunits are not supported. PSL statements must be in the module
they reference, at the module level where you would put an
initial... statement.
Verilator only supports (posedge CLK) or (negedge CLK), where CLK is the
name of a one bit signal. You may not use arbitrary expressions as
assertion clocks.
=head2 Synthesis Directive Assertion Support
With the --assert switch, Verilator reads any "//synopsys full_case" or
@@ -2023,9 +1992,8 @@ appropriate code to detect failing cases at runtime and print an "Assertion
failed" error message.
Verilator likewise also asserts any "unique" or "priority" SystemVerilog
keywords on case statements. However, "unique if" and "priority if" are
currently simply ignored.
keywords on case statement, as well as "unique" on if statements.
However, "priority if" is currently simply ignored.
=head1 LANGUAGE EXTENSIONS
@@ -2051,13 +2019,6 @@ supported by Verilator since 2006!)
This will report an error when encountered, like C++'s #error.
=item _(I<expr>)
A underline followed by an expression in parenthesis returns a Verilog
expression. This is different from normal parenthesis in special contexts,
such as PSL expressions, and can be used to embed bit concatenation ({})
inside of PSL statements.
=item $c(I<string>, ...);
The string will be embedded directly in the output C++ code at the point
@@ -2471,7 +2432,7 @@ reset works. (Note this is what the hardware will really do.) In
practice, just setting all variables to one at startup finds most problems.
B<Note.> --x-assign applies to variables explicitly initialized or assigned to
X. Unititialized clocks are initialized to zero, while all other state holding
X. Uninitialized clocks are initialized to zero, while all other state holding
variables are initialized to a random value.
Event driven simulators will generally trigger an edge on a transition from X
@@ -3049,11 +3010,21 @@ not really needed. The best solution is to insure that each module is in a
unique file by the same name. Otherwise, make sure all library files are
read in as libraries with -v, instead of automatically with -y.
=item PINCONNECTEMPTY
Warns that a cell instantiation has a pin which is connected to
.pin_name(), e.g. not another signal, but with an explicit mention of the
pin. It may be desirable to disable PINCONNECTEMPTY, as this indicates
intention to have a no-connect.
Disabled by default as this is a code style warning; it will simulate
correctly.
=item PINMISSING
Warns that a module has a pin which is not mentioned in a cell
instantiation. If a pin is not missing it should still be specified on the
cell declaration with a empty connection,using "(.pin_name())".
cell declaration with a empty connection, using "(.pin_name())".
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
+1 -1
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.856 2014-03-11])
AC_INIT([Verilator],[3.860 2014-05-11])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
+2 -1
View File
@@ -207,7 +207,8 @@ WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, boo
vluint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
// Zero for ease of debugging and to save having to zero for shifts
for (int i=0; i<words; i++) { un[i]=vn[i]=0; }
// Note +1 as loop will use extra word
for (int i=0; i<words+1; i++) { un[i]=vn[i]=0; }
// Algorithm requires divisor MSB to be set
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
+148 -3
View File
@@ -1163,7 +1163,10 @@ static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDa
}
}
#define VL_POW_QQI(obits,lbits,rbits,lhs,rhs) VL_POW_QQQ(obits,lbits,rbits,lhs,rhs)
static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (VL_UNLIKELY(lhs==0)) return 0;
IData power = lhs;
IData out = 1;
@@ -1173,10 +1176,8 @@ static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
}
return out;
}
#define VL_POW_QQI(obits,lbits,rbits,lhs,rhs) VL_POW_QQQ(obits,lbits,rbits,lhs,rhs)
static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (VL_UNLIKELY(lhs==0)) return 0;
QData power = lhs;
QData out = VL_ULL(1);
@@ -1187,6 +1188,36 @@ static inline QData VL_POW_QQQ(int, int, int rbits, QData lhs, QData rhs) {
return out;
}
#define VL_POWSS_QQI(obits,lbits,rbits,lhs,rhs,lsign,rsign) VL_POWSS_QQQ(obits,lbits,rbits,lhs,rhs,lsign,rsign)
static inline IData VL_POWSS_III(int obits, int, int rbits, IData lhs, IData rhs, bool lsign, bool rsign) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (rsign && VL_SIGN_I(rbits, rhs)) {
if (lhs==0) return 0; // "X"
else if (lhs==1) return 1;
else if (lsign && lhs==VL_MASK_I(obits)) { //-1
if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1
else return 1; // -1^even=1
}
return 0;
}
return VL_POW_III(obits, obits, rbits, lhs, rhs);
}
static inline QData VL_POWSS_QQQ(int obits, int, int rbits, QData lhs, QData rhs, bool lsign, bool rsign) {
if (VL_UNLIKELY(rhs==0)) return 1;
if (rsign && VL_SIGN_I(rbits, rhs)) {
if (lhs==0) return 0; // "X"
else if (lhs==1) return 1;
else if (lsign && lhs==VL_MASK_I(obits)) { //-1
if (rhs & 1) return VL_MASK_I(obits); // -1^odd=-1
else return 1; // -1^even=1
}
return 0;
}
return VL_POW_QQQ(obits, obits, rbits, lhs, rhs);
}
//===================================================================
// Concat/replication
@@ -1327,6 +1358,120 @@ static inline WDataOutP VL_REPLICATE_WWI(int obits, int lbits, int, WDataOutP ow
return(owp);
}
// Left stream operator. Output will always be clean. LHS and RHS must be clean.
// Special "fast" versions for slice sizes that are a power of 2. These use
// shifts and masks to execute faster than the slower for-loop approach where a
// subset of bits is copied in during each iteration.
static inline IData VL_STREAML_FAST_III(int, int lbits, int, IData ld, IData rd_log2) {
// Pre-shift bits in most-significant slice:
//
// If lbits is not a multiple of the slice size (i.e., lbits % rd != 0),
// then we end up with a "gap" in our reversed result. For example, if we
// have a 5-bit Verlilog signal (lbits=5) in an 8-bit C data type:
//
// ld = ---43210
//
// (where numbers are the Verilog signal bit numbers and '-' is an unused bit).
// Executing the switch statement below with a slice size of two (rd=2,
// rd_log2=1) produces:
//
// ret = 1032-400
//
// Pre-shifting the bits in the most-significant slice allows us to avoid
// this gap in the shuffled data:
//
// ld_adjusted = --4-3210
// ret = 10324---
IData ret = ld;
if (rd_log2) {
vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2); // max multiple of rd <= lbits
vluint32_t lbitsRem = lbits - lbitsFloor; // number of bits in most-sig slice (MSS)
IData msbMask = VL_MASK_I(lbitsRem) << lbitsFloor; // mask to sel only bits in MSS
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_UL(1) << rd_log2) - lbitsRem));
}
switch (rd_log2) {
case 0:
ret = ((ret >> 1) & VL_UL(0x55555555)) | ((ret & VL_UL(0x55555555)) << 1); // FALLTHRU
case 1:
ret = ((ret >> 2) & VL_UL(0x33333333)) | ((ret & VL_UL(0x33333333)) << 2); // FALLTHRU
case 2:
ret = ((ret >> 4) & VL_UL(0x0f0f0f0f)) | ((ret & VL_UL(0x0f0f0f0f)) << 4); // FALLTHRU
case 3:
ret = ((ret >> 8) & VL_UL(0x00ff00ff)) | ((ret & VL_UL(0x00ff00ff)) << 8); // FALLTHRU
case 4:
ret = ((ret >> 16) | (ret << 16));
}
return ret >> (VL_WORDSIZE - lbits);
}
static inline QData VL_STREAML_FAST_QQI(int, int lbits, int, QData ld, IData rd_log2) {
// Pre-shift bits in most-significant slice (see comment in VL_STREAML_FAST_III)
QData ret = ld;
if (rd_log2) {
vluint32_t lbitsFloor = lbits & ~VL_MASK_I(rd_log2);
vluint32_t lbitsRem = lbits - lbitsFloor;
QData msbMask = VL_MASK_Q(lbitsRem) << lbitsFloor;
ret = (ret & ~msbMask) | ((ret & msbMask) << ((VL_ULL(1) << rd_log2) - lbitsRem));
}
switch (rd_log2) {
case 0:
ret = ((ret >> 1) & VL_ULL(0x5555555555555555)) | ((ret & VL_ULL(0x5555555555555555)) << 1); // FALLTHRU
case 1:
ret = ((ret >> 2) & VL_ULL(0x3333333333333333)) | ((ret & VL_ULL(0x3333333333333333)) << 2); // FALLTHRU
case 2:
ret = ((ret >> 4) & VL_ULL(0x0f0f0f0f0f0f0f0f)) | ((ret & VL_ULL(0x0f0f0f0f0f0f0f0f)) << 4); // FALLTHRU
case 3:
ret = ((ret >> 8) & VL_ULL(0x00ff00ff00ff00ff)) | ((ret & VL_ULL(0x00ff00ff00ff00ff)) << 8); // FALLTHRU
case 4:
ret = ((ret >> 16) & VL_ULL(0x0000ffff0000ffff)) | ((ret & VL_ULL(0x0000ffff0000ffff)) << 16); // FALLTHRU
case 5:
ret = ((ret >> 32) | (ret << 32));
}
return ret >> (VL_QUADSIZE - lbits);
}
// Regular "slow" streaming operators
static inline IData VL_STREAML_III(int, int lbits, int, IData ld, IData rd) {
IData ret = 0;
// Slice size should never exceed the lhs width
IData mask = VL_MASK_I(rd);
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
ret |= ((ld >> istart) & mask) << ostart;
}
return ret;
}
static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) {
QData ret = 0;
// Slice size should never exceed the lhs width
QData mask = VL_MASK_Q(rd);
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
ret |= ((ld >> istart) & mask) << ostart;
}
return ret;
}
static inline WDataOutP VL_STREAML_WWI(int, int lbits, int, WDataOutP owp, WDataInP lwp, IData rd) {
VL_ZERO_RESET_W(lbits, owp);
// Slice size should never exceed the lhs width
int ssize = ((int)rd < lbits) ? ((int)rd) : lbits;
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
for (int sbit=0; sbit<ssize && sbit<lbits-istart; sbit++) {
// Extract a single bit from lwp and shift it to the correct
// location for owp.
WData bit= ((lwp[VL_BITWORD_I(istart+sbit)] >> VL_BITBIT_I(istart+sbit)) & 1) << VL_BITBIT_I(ostart+sbit);
owp[VL_BITWORD_I(ostart+sbit)] |= bit;
}
}
return owp;
}
// Because concats are common and wide, it's valuable to always have a clean output.
// Thus we specify inputs must be clean, so we don't need to clean the output.
// Note the bit shifts are always constants, so the adds in these constify out.
+3 -2
View File
@@ -283,7 +283,7 @@ public:
virtual ~VerilatedVpioMemoryWordIter() {}
static inline VerilatedVpioMemoryWordIter* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWordIter*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiIterator; }
void iterationInc() { if (!(m_done = m_iteration == m_varp->array().left())) m_iteration+=m_direction; }
void iterationInc() { if (!(m_done = (m_iteration == m_varp->array().left()))) m_iteration+=m_direction; }
virtual vpiHandle dovpi_scan() {
vpiHandle result;
if (m_done) return 0;
@@ -408,7 +408,7 @@ public:
}
}
}
for (set<VerilatedVpioVar*>::iterator it=update.begin(); it!=update.end(); it++ ) {
for (set<VerilatedVpioVar*>::iterator it=update.begin(); it!=update.end(); ++it) {
memcpy((*it)->prevDatap(), (*it)->varDatap(), (*it)->entSize());
}
}
@@ -454,6 +454,7 @@ class VerilatedVpiError {
public:
VerilatedVpiError() : m_flag(false) {
m_buff[0] = '\0';
m_errorInfo.product = (PLI_BYTE8*)Verilated::productName();
}
~VerilatedVpiError() {}
+10
View File
@@ -95,6 +95,16 @@
// This is not necessarily the same as #UL, depending on what the IData typedef is.
#define VL_UL(c) ((IData)(c##UL)) ///< Add appropriate suffix to 32-bit constant
//=========================================================================
// C++-2011
#if __cplusplus >= 201103L || defined(__GXX_EXPERIMENTAL_CXX0X__)
# define VL_HAS_UNIQUE_PTR
# define VL_UNIQUE_PTR unique_ptr
#else
# define VL_UNIQUE_PTR auto_ptr
#endif
//=========================================================================
// Warning disabled
+1 -1
View File
@@ -29,7 +29,7 @@ typedef signed __int8 int8_t;
#include <stdint.h>
#elif defined(__APPLE__)
#include <stdint.h>
#elif defined(__linux)
#elif defined(__linux) || (defined(__APPLE__) && defined(__MACH__))
#include <inttypes.h>
#else
#include <sys/types.h>
+1 -1
View File
@@ -37,7 +37,7 @@ typedef signed __int32 int32_t;
typedef signed __int8 int8_t;
#elif defined(__MINGW32__)
#include <stdint.h>
#elif defined(__linux)
#elif defined(__linux) || (defined(__APPLE__) && defined(__MACH__))
#include <inttypes.h>
#else
#include <sys/types.h>
+47 -16
View File
@@ -40,7 +40,7 @@ Verilator then performs many additional edits and optimizations on the
hierarchical design. This includes coverage, assertions, X elimination,
inlining, constant propagation, and dead code elimination.
References in the design are then psudo-flattened. Each module's variables
References in the design are then pseudo-flattened. Each module's variables
and functions get "Scope" references. A scope reference is an occurrence of
that un-flattened variable in the flattened hierarchy. A module that occurs
only once in the hierarchy will have a single scope and single VarScope for
@@ -49,7 +49,7 @@ occurrence, and two VarScopes for each variable. This allows optimizations
to proceed across the flattened design, while still preserving the
hierarchy.
Additional edits and optimizations proceed on the psudo-flat design. These
Additional edits and optimizations proceed on the pseudo-flat design. These
include module references, function inlining, loop unrolling, variable
lifetime analysis, lookup table creation, always splitting, and logic gate
simplifications (pushing inverters, etc).
@@ -80,8 +80,8 @@ classes).
Each C<AstNode> has pointers to up to four children, accessed by the
C<op1p> through C<op4p> methods. These methods are then abstracted in a
specific Ast* node class to a more specific name. For example with the
C<AstIf> node (for C<if> statements), C<ifsp> calls C<op1p> to give the
pointer to the AST for the "then" block, while C<elsesp> calls C<op2p> to
C<AstIf> node (for C<if> statements), C<ifsp> calls C<op2p> to give the
pointer to the AST for the "then" block, while C<elsesp> calls C<op3p> to
give the pointer to the AST for the "else" block, or NULL if there is not
one.
@@ -97,7 +97,7 @@ are at the top of the tree.
By convention, each function/method uses the variable C<nodep> as a pointer
to the C<AstNode> currently being processed.
=item C<AstNVistor>
=item C<AstNVisitor>
The passes are implemented by AST visitor classes (see L</Visitor
Functions>). These are implemented by subclasses of the abstract class,
@@ -119,7 +119,7 @@ C<fanout>, C<color> and C<rank>, which may be used in algorithms for ordering
the graph. A generic C<user>/C<userp> member variable is also provided.
Virtual methods are provided to specify the name, color, shape and style to be
used in dot output. Typically users provided derived classes from
used in dot output. Typically users provide derived classes from
C<V3GraphVertex> which will reimplement these methods.
Iterators are provided to access in and out edges. Typically these are used in
@@ -219,7 +219,7 @@ and optimization passes. This allows separation of the pass algorithm from
the AST on which it operates. Wikipedia provides an introduction to the
concept at L<http://en.wikipedia.org/wiki/Visitor_pattern>.
As noted above, all visitors are derived classes of C<AstNvisitor>. All
As noted above, all visitors are derived classes of C<AstNVisitor>. All
derived classes of C<AstNode> implement the C<accept> method, which takes
as argument a reference to an instance or a C<AstNVisitor> derived class
and applies the visit method of the C<AstNVisitor> to the invoking AstNode
@@ -262,7 +262,7 @@ exiting the lower for will lose the upper for's setting.
User attributes. Each C<AstNode> (B<Note.> The AST node, not the visitor)
has five user attributes, which may be accessed as an integer using the
C<user1()> through C<user5()> methods, or as a pointer (of type
C<AstNuser>) using the C<user1p()> through C<user5p()> methods (a common
C<AstNUser>) using the C<user1p()> through C<user5p()> methods (a common
technique lifted from graph traversal packages).
A visitor first clears the one it wants to use by calling
@@ -290,7 +290,7 @@ module.
Parameters can be passed between the visitors in close to the "normal"
function caller to callee way. This is the second C<vup> parameter of type
C<AstNuser> that is ignored on most of the visitor functions. V3Width does
C<AstNUser> that is ignored on most of the visitor functions. V3Width does
this, but it proved more messy than the above and is deprecated. (V3Width
was nearly the first module written. Someday this scheme may be removed,
as it slows the program down to have to pass vup everywhere.)
@@ -301,10 +301,10 @@ as it slows the program down to have to pass vup everywhere.)
C<AstNode> provides a set of iterators to facilitate walking over the
tree. Each takes two arguments, a visitor, C<v>, of type C<AstNVisitor> and
an optional pointer user data, C<vup>, of type C<AstNuser*>. The second is
an optional pointer user data, C<vup>, of type C<AstNUser*>. The second is
one of the ways to pass parameters to visitors described in L</Visitor
Functions>, but its use is no deprecated and should be used for new visitor
classes.
Functions>, but its use is now deprecated and should I<not> be used for new
visitor classes.
=over 4
@@ -341,6 +341,37 @@ C<op4p> in turn.
=back
=head3 Caution on Using Iterators When Child Changes
Visitors often replace one node with another node; V3Width and V3Const are
major examples. A visitor which is the parent of such a replacement needs
to be aware that calling iteration may cause the children to change. For
example:
// nodep->lhsp() is 0x1234000
nodep->lhsp()->iterateAndNext(...); // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400
nodep->lhsp()->iterateAndNext(...);
Will work fine, as even if the first iterate causes a new node to take the
place of the lhsp(), that edit will update nodep->lhsp() and the second
call will correctly see the change. Alternatively:
lp = nodep->lhsp();
// nodep->lhsp() is 0x1234000, lp is 0x1234000
lp->iterateAndNext(...); **lhsp=NULL;** // and under covers nodep->lhsp() changes
// nodep->lhsp() is 0x5678400, lp is 0x1234000
lp->iterateAndNext(...);
This will cause bugs or a core dump, as lp is a dangling pointer. Thus it
is advisable to set lhsp=NULL shown in the *'s above to make sure these
dangles are avoided. Another alternative used in special cases mostly in
V3Width is to use acceptSubtreeReturnEdits, which operates on a single node
and returns the new pointer if any. Note acceptSubtreeReturnEdits does not
follow nextp() links.
lp = lp->acceptSubtreeReturnEdits()
=head2 Identifying derived classes
A common requirement is to identify the specific C<AstNode> class we are
@@ -372,7 +403,7 @@ Verilator primary manual.
It is important to add tests for failures as well as success (for example to
check that an error message is correctly triggered).
Tests that fail should by convenition have the suffix C<_bad> in their name,
Tests that fail should by convention have the suffix C<_bad> in their name,
and include C<fails =E<gt> 1> in either their C<compile> or C<execute> step as
appropriate.
@@ -388,7 +419,7 @@ For convenience, a summary of the most commonly used features is provided
here. All drivers require a call to C<compile> subroutine to compile the
test. For run-time tests, this is followed by a call to the C<execute>
subroutine. Both of these functions can optionally be provided with a hash
table as argument specifying additonal options.
table as argument specifying additional options.
The test driver assumes by default that the source Verilog file name
matches the PERL driver name. So a test whose driver is C<t/t_mytest.pl>
@@ -608,8 +639,8 @@ Shows the value of the node's user1p...user5p, if non-NULL.
Many nodes have an explicit data type. "@dt=0x..." indicates the address
of the data type (AstNodeDType) this node uses.
If a data type is present and is numberic, it then prints the width of the
item. This field is a squence of flag characters and width data as follows:
If a data type is present and is numeric, it then prints the width of the
item. This field is a sequence of flag characters and width data as follows:
C<s> if the node is signed.
+1 -1
View File
@@ -8,7 +8,7 @@ use strict;
#======================================================================
# main
eval `modulecmd perl add synopsys-vcs`;
eval `modulecmd perl add synopsys-vcs_mx`;
exec('vcs',@ARGV);
#######################################################################
-2
View File
@@ -326,12 +326,10 @@ private:
bool sequent = m_itemSequent;
if (!combo && !sequent) combo=true; // If no list, Verilog 2000: always @ (*)
#ifndef NEW_ORDERING
if (combo && sequent) {
nodep->v3error("Unsupported: Mixed edge (pos/negedge) and activity (no edge) sensitive activity list");
sequent = false;
}
#endif
AstActive* wantactivep = NULL;
if (combo && !sequent) {
+77 -15
View File
@@ -56,7 +56,7 @@ private:
+":"+cvtToStr(nodep->fileline()->lineno())
+": Assertion failed in %m"
+((message != "")?": ":"")+message
+"\\n");
+"\n");
}
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
nodep->displayType(AstDisplayType::DT_WRITE);
@@ -73,25 +73,31 @@ private:
AstNode* newIfAssertOn(AstNode* nodep) {
// Add a internal if to check assertions are on.
// Don't make this a AND term, as it's unlikely to need to test this.
return new AstIf (nodep->fileline(),
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn()
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
nodep, NULL);
AstNode* newp
= new AstIf (nodep->fileline(),
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
(v3Global.opt.assertOn()
? (AstNode*)(new AstCMath(nodep->fileline(), "Verilated::assertOn()", 1))
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
nodep, NULL);
newp->user1(true); // Don't assert/cover this if
return newp;
}
AstNode* newIfCoverageOn(AstNode* nodep) {
// Add a internal if to check coverage is on
// Don't make this a AND term, as it's unlikely to need to test this.
return new AstIf (nodep->fileline(),
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
(v3Global.opt.coverage()
? (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicTrue()))
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
nodep, NULL);
AstNode* newp
= new AstIf (nodep->fileline(),
// If assertions are off, have constant propagation rip them out later
// This allows syntax errors and such to be detected normally.
(v3Global.opt.coverage()
? (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicTrue()))
: (AstNode*)(new AstConst(nodep->fileline(), AstConst::LogicFalse()))),
nodep, NULL);
newp->user1(true); // Don't assert/cover this if
return newp;
}
AstNode* newFireAssert(AstNode* nodep, const string& message) {
@@ -174,6 +180,62 @@ private:
// Bye
pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstIf* nodep, AstNUser*) {
if (nodep->user1SetOnce()) return;
if (nodep->uniquePragma() || nodep->unique0Pragma()) {
AstNodeIf* ifp = nodep;
AstNode* propp = NULL;
bool hasDefaultElse = false;
do {
// If this statement ends with 'else if', then nextIf will point to the
// nextIf statement. Otherwise it will be null.
AstNodeIf* nextifp = dynamic_cast<AstNodeIf*>(ifp->elsesp());
ifp->condp()->iterateAndNext(*this);
// Recurse into the true case.
ifp->ifsp()->iterateAndNext(*this);
// If the last else is not an else if, recurse into that too.
if (ifp->elsesp() && !nextifp) {
ifp->elsesp()->iterateAndNext(*this);
}
// Build a bitmask of the true predicates
AstNode* predp = ifp->condp()->cloneTree(false);
if (propp) {
propp = new AstConcat(nodep->fileline(), predp, propp);
} else {
propp = predp;
}
// Record if this ends with an 'else' that does not have an if
if (ifp->elsesp() && !nextifp) {
hasDefaultElse = true;
}
ifp = nextifp;
} while (ifp);
AstNode *newifp = nodep->cloneTree(false);
bool allow_none = nodep->unique0Pragma();
// Note: if this ends with an 'else', then we don't need to validate that one of the
// predicates evaluates to true.
AstNode* ohot = ((allow_none || hasDefaultElse)
? (new AstOneHot0(nodep->fileline(), propp))->castNode()
: (new AstOneHot (nodep->fileline(), propp))->castNode());
AstIf* checkifp = new AstIf (nodep->fileline(),
new AstLogNot (nodep->fileline(), ohot),
newFireAssert(nodep, "'unique if' statement violated"),
newifp);
checkifp->branchPred(AstBranchPred::BP_UNLIKELY);
nodep->replaceWith(checkifp);
pushDeletep(nodep);
} else {
nodep->iterateChildren(*this);
}
}
// VISITORS //========== Case assertions
virtual void visit(AstCase* nodep, AstNUser*) {
+25 -5
View File
@@ -239,6 +239,9 @@ inline void AstNode::debugTreeChange(const char* prefix, int lineno, bool next)
//if (debug()) cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<": "<<(void*)this<<" <e"<<AstNode::s_editCntGbl<<">"<<endl;
//if (debug()) {
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
// // Commenting out the section below may crash, as the tree state
// // between edits is not always consistent for printing
// cout<<"-treeChange: V3Ast.cpp:"<<lineno<<" Tree Change for "<<prefix<<endl;
// v3Global.rootp()->dumpTree(cout,"-treeChange: ");
// if (next||1) this->dumpTreeAndNext(cout, prefix);
// else this->dumpTree(cout, prefix);
@@ -561,7 +564,7 @@ void AstNode::relink(AstNRelinker* linkerp) {
if (linkerp->m_iterpp) {
// If we're iterating over a next() link, we need to follow links off the
// NEW node. Thus we pass iteration information via a pointer in the node.
// This adds a unfortunate 4 bytes to every AstNode, but is faster than passing
// This adds a unfortunate hot 8 bytes to every AstNode, but is faster than passing
// across every function.
// If anyone has a cleaner way, I'd be grateful.
*(linkerp->m_iterpp) = newp;
@@ -750,6 +753,20 @@ void AstNode::iterateChildren(AstNVisitor& v, AstNUser* vup) {
if (m_op4p) m_op4p->iterateAndNext(v, vup);
}
void AstNode::iterateChildrenConst(AstNVisitor& v, AstNUser* vup) {
// This is a very hot function
if (!this) return;
ASTNODE_PREFETCH(m_op1p);
ASTNODE_PREFETCH(m_op2p);
ASTNODE_PREFETCH(m_op3p);
ASTNODE_PREFETCH(m_op4p);
// if () not needed since iterateAndNext accepts null this, but faster with it.
if (m_op1p) m_op1p->iterateAndNextConst(v, vup);
if (m_op2p) m_op2p->iterateAndNextConst(v, vup);
if (m_op3p) m_op3p->iterateAndNextConst(v, vup);
if (m_op4p) m_op4p->iterateAndNextConst(v, vup);
}
void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
// This is a very hot function
// IMPORTANT: If you replace a node that's the target of this iterator,
@@ -764,16 +781,18 @@ 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);
// Desirable check, but many places where multiple iterations are OK
//if (VL_UNLIKELY(niterp->m_iterpp)) niterp->v3fatalSrc("IterateAndNext under iterateAndNext may miss edits");
// cppcheck-suppress nullPointer
niterp->m_iterpp = &niterp;
niterp->accept(v, vup);
// accept may do a replaceNode and change niterp on us...
//if (niterp != nodep) UINFO(1,"iterateAndNext edited "<<(void*)nodep<<" now into "<<(void*)niterp<<endl); // niterp maybe NULL, so need cast
if (!niterp) return;
if (!niterp) return; // Perhaps node deleted inside accept
niterp->m_iterpp = NULL;
if (VL_UNLIKELY(niterp!=nodep)) { // Edited it
if (VL_UNLIKELY(niterp!=nodep)) { // Edited node inside accept
nodep = niterp;
} else { // Same node, just loop
} else { // Unchanged node, just continue loop
nodep = niterp->m_nextp;
}
}
@@ -799,11 +818,12 @@ void AstNode::iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup) {
this->op4p()->iterateListBackwards(v,vup);
}
void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) {
void AstNode::iterateAndNextConst(AstNVisitor& v, AstNUser* vup) {
// Keep following the current list even if edits change it
if (!this) return;
for (AstNode* nodep=this; nodep; ) {
AstNode* nnextp = nodep->m_nextp;
ASTNODE_PREFETCH(nnextp);
nodep->accept(v, vup);
nodep = nnextp;
}
+20 -2
View File
@@ -92,6 +92,8 @@ public:
else if (signst==signedst_SIGNED) m_e=SIGNED;
else m_e=NOSIGN;
}
static inline AstNumeric fromBool (bool isSigned) { // Factory method
return isSigned ? AstNumeric(SIGNED) : AstNumeric(UNSIGNED); }
explicit inline AstNumeric (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
inline bool isSigned() const { return m_e==SIGNED; }
@@ -606,13 +608,16 @@ struct VNumRange {
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 leftToRightInc() const { return littleEndian()?1:-1; }
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_lo==0 && m_hi>=1 && !m_littleEndian)); }
void dump(ostream& str) const { if (ranged()) str<<"["<<left()<<":"<<right()<<"]"; else str<<"[norg]"; }
};
inline ostream& operator<<(ostream& os, VNumRange rhs) { rhs.dump(os); return os; }
//######################################################################
@@ -1014,7 +1019,8 @@ public:
static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation
static string vcdName(const string& namein); // Name for printing out to vcd files
string prettyName() const { return prettyName(name()); }
string prettyTypeName() const; // "VARREF name" for error messages
string prettyTypeName() const; // "VARREF" for error messages
virtual string prettyOperatorName() const { return "operator "+prettyTypeName(); }
FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline=fl; }
bool width1() const;
@@ -1185,9 +1191,11 @@ public:
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
void iterate(AstNVisitor& v, AstNUser* vup=NULL) { this->accept(v,vup); } // Does this; excludes following this->next
void iterateAndNext(AstNVisitor& v, AstNUser* vup=NULL);
void iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup=NULL);
void iterateAndNextConst(AstNVisitor& v, AstNUser* vup=NULL);
void iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup=NULL) { iterateAndNextConst(v, vup); }
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
void iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
void iterateChildrenConst(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
AstNode* acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup=NULL); // Return edited nodep; see comments in V3Ast.cpp
// CONVERSION
@@ -1671,6 +1679,16 @@ struct AstNodeSel : public AstNodeBiop {
virtual bool hasDType() const { return true; }
};
struct AstNodeStream : public AstNodeBiop {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
AstNodeStream(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp->dtypep()) {
dtypeSetLogicSized(lhsp->dtypep()->width(), lhsp->dtypep()->width(), AstNumeric::UNSIGNED);
}
}
ASTNODE_BASE_FUNCS(NodeStream)
};
//######################################################################
// Tasks/functions common handling
+33
View File
@@ -0,0 +1,33 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//*************************************************************************
// DESCRIPTION: Verilator: Ast node structure
//
// Code available from: http://www.veripool.org/verilator
//
//*************************************************************************
//
// Copyright 2003-2014 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.
//
//*************************************************************************
#ifndef _V3ASTCONSTONLY_H_
#define _V3ASTCONSTONLY_H_ 1
// Include only in visitors that do not not edit nodes, so should use constant iterators
#define iterateAndNext error_use_iterateAndNextConst
#define iterateChildren error_use_iterateChildrenConst
#define addNext error_no_addNext_in_ConstOnlyVisitor
#define replaceWith error_no_replaceWith_in_ConstOnlyVisitor
#define deleteTree error_no_deleteTree_in_ConstOnlyVisitor
#define unlinkFrBack error_no_unlinkFrBack_in_ConstOnlyVisitor
#endif // Guard
+5 -5
View File
@@ -200,7 +200,7 @@ string AstVar::verilogKwd() const {
}
}
string AstVar::vlArgType(bool named, bool forReturn) const {
string AstVar::vlArgType(bool named, bool forReturn, bool forFunc) const {
if (forReturn) named=false;
if (forReturn) v3fatalSrc("verilator internal data is never passed as return, but as first argument");
string arg;
@@ -233,7 +233,7 @@ string AstVar::vlArgType(bool named, bool forReturn) const {
arg += " (& "+name();
arg += ")["+cvtToStr(widthWords())+"]";
} else {
if (isOutput() || (strtype && isInput())) arg += "&";
if (forFunc && (isOutput() || (strtype && isInput()))) arg += "&";
if (named) arg += " "+name();
}
return arg;
@@ -835,11 +835,11 @@ void AstNodeDType::dumpSmall(ostream& str) {
void AstNodeArrayDType::dumpSmall(ostream& str) {
this->AstNodeDType::dumpSmall(str);
if (castPackArrayDType()) str<<"p"; else str<<"u";
str<<"["<<declRange().left()<<":"<<declRange().right()<<"]";
str<<" "<<declRange();
}
void AstNodeArrayDType::dump(ostream& str) {
this->AstNodeDType::dump(str);
str<<" ["<<declRange().left()<<":"<<declRange().right()<<"]";
str<<" "<<declRange();
}
void AstNodeModule::dump(ostream& str) {
this->AstNode::dump(str);
@@ -855,7 +855,7 @@ void AstPackageImport::dump(ostream& str) {
void AstSel::dump(ostream& str) {
this->AstNode::dump(str);
if (declRange().ranged()) {
str<<" decl["<<declRange().left()<<":"<<declRange().right()<<"]";
str<<" decl"<<declRange()<<"]";
if (declElWidth()!=1) str<<"/"<<declElWidth();
}
}
+85 -18
View File
@@ -965,7 +965,7 @@ public:
string scType() const; // Return SysC type: bool, uint32_t, uint64_t, sc_bv
string cPubArgType(bool named, bool forReturn) const; // Return C /*public*/ type for argument: bool, uint32_t, uint64_t, etc.
string dpiArgType(bool named, bool forReturn) const; // Return DPI-C type for argument
string vlArgType(bool named, bool forReturn) const; // Return Verilator internal type for argument: CData, SData, IData, WData
string vlArgType(bool named, bool forReturn, bool forFunc) const; // Return Verilator internal type for argument: CData, SData, IData, WData
string vlEnumType() const; // Return VerilatorVarType: VLVT_UINT32, etc
string vlEnumDir() const; // Return VerilatorVarDir: VLVD_INOUT, etc
void combineType(AstVarType type);
@@ -977,7 +977,6 @@ public:
void valuep(AstNode* nodep) { setOp3p(nodep); } // It's valuep, not constp, as may be more complicated than an AstConst
void addAttrsp(AstNode* nodep) { addNOp4p(nodep); }
AstNode* attrsp() const { return op4p()->castNode(); } // op4 = Attributes during early parse
bool hasSimpleInit() const { return (op3p() && !op3p()->castInitArray()); }
void childDTypep(AstNodeDType* nodep) { setOp1p(nodep); }
AstNodeDType* subDTypep() const { return dtypep() ? dtypep() : childDTypep(); }
void attrClockEn(bool flag) { m_attrClockEn = flag; }
@@ -1004,6 +1003,8 @@ public:
void trace(bool flag) { m_trace=flag; }
// METHODS
virtual void name(const string& name) { m_name = name; }
virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input"
: isOutput() ? "output" : varType().ascii()); }
bool isInput() const { return m_input; }
bool isOutput() const { return m_output; }
bool isInOnly() const { return m_input && !m_output; }
@@ -1295,6 +1296,9 @@ public:
virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); return NULL; }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; }
virtual string prettyOperatorName() const { return modVarp()
? (modVarp()->directionName()+" port connection '"+modVarp()->prettyName()+"'")
: "port connection"; }
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
int pinNum() const { return m_pinNum; }
void exprp(AstNode* nodep) { addOp1p(nodep); }
@@ -2237,6 +2241,7 @@ struct AstFClose : public AstNodeStmt {
};
struct AstFOpen : public AstNodeStmt {
// Although a system function in IEEE, here a statement which sets the file pointer (MCD)
AstFOpen(FileLine* fileline, AstNode* filep, AstNode* filenamep, AstNode* modep)
: AstNodeStmt (fileline) {
setOp1p(filep);
@@ -2758,15 +2763,20 @@ struct AstInsideRange : public AstNodeMath {
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.
// The first value on the initsp() list is for the lo() index of the array.
// Parents: ASTVAR::init()
// Children: CONSTs...
AstInitArray(FileLine* fl, AstNode* initsp)
AstInitArray(FileLine* fl, AstNodeArrayDType* newDTypep, AstNode* initsp)
: AstNode(fl) {
dtypep(newDTypep);
addNOp1p(initsp);
}
ASTNODE_NODE_FUNCS(InitArray, INITARRAY)
AstNode* initsp() const { return op1p()->castNode(); } // op1 = Initial value expressions
void addInitsp(AstNode* newp) { addOp1p(newp); }
virtual bool hasDType() const { return true; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
};
struct AstPragma : public AstNode {
@@ -4032,7 +4042,7 @@ struct AstPow : public AstNodeBiop {
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; }
};
struct AstPowD : public AstNodeBiop {
AstPowD(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
@@ -4044,20 +4054,46 @@ struct AstPowD : public AstNodeBiop {
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return instrCountDoubleDiv(); }
virtual int instrCount() const { return instrCountDoubleDiv()*5; }
virtual bool doubleFlavor() const { return true; }
};
struct AstPowS : public AstNodeBiop {
AstPowS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
struct AstPowSU : public AstNodeBiop {
AstPowSU(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
dtypeFrom(lhsp); }
ASTNODE_NODE_FUNCS(PowS, POWS)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowS(lhs,rhs); }
ASTNODE_NODE_FUNCS(PowSU, POWSU)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSU(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f** %r)"; }
virtual string emitC() { return "VL_POWS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,0)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*instrCountMul(); }
virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; }
virtual bool signedFlavor() const { return true; }
};
struct AstPowSS : public AstNodeBiop {
AstPowSS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
dtypeFrom(lhsp); }
ASTNODE_NODE_FUNCS(PowSS, POWSS)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowSS(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f** %r)"; }
virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 1,1)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; }
virtual bool signedFlavor() const { return true; }
};
struct AstPowUS : public AstNodeBiop {
AstPowUS(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
dtypeFrom(lhsp); }
ASTNODE_NODE_FUNCS(PowUS, POWUS)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opPowUS(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %f** %r)"; }
virtual string emitC() { return "VL_POWSS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri, 0,1)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*instrCountMul()*10; }
virtual bool signedFlavor() const { return true; }
};
struct AstEqCase : public AstNodeBiCom {
@@ -4128,14 +4164,21 @@ struct AstConcat : public AstNodeBiop {
virtual int instrCount() const { return widthInstrs()*2; }
};
struct AstReplicate : public AstNodeBiop {
// Also used as a "Uniop" flavor of Concat, e.g. "{a}"
// Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp()
AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (AstConst* constp=rhsp->castConst()) {
dtypeSetLogicSized(lhsp->width()*constp->toUInt(), lhsp->width()*constp->toUInt(), AstNumeric::UNSIGNED);
private:
void init() {
if (lhsp()) {
if (AstConst* constp=rhsp()->castConst()) {
dtypeSetLogicSized(lhsp()->width()*constp->toUInt(), lhsp()->width()*constp->toUInt(), AstNumeric::UNSIGNED);
}
}
}
public:
AstReplicate(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeBiop(fl, lhsp, rhsp) { init(); }
AstReplicate(FileLine* fl, AstNode* lhsp, uint32_t repCount)
: AstNodeBiop(fl, lhsp, new AstConst(fl, repCount)) {}
: AstNodeBiop(fl, lhsp, new AstConst(fl, repCount)) { init(); }
ASTNODE_NODE_FUNCS(Replicate, REPLICATE)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opRepl(lhs,rhs); }
virtual string emitVerilog() { return "%f{%r{%k%l}}"; }
@@ -4145,6 +4188,30 @@ struct AstReplicate : public AstNodeBiop {
virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*2; }
};
struct AstStreamL : public AstNodeStream {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
AstStreamL(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStream(fl, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(StreamL, STREAML)
virtual string emitVerilog() { return "%f{ << %r %k{%l} }"; }
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opStreamL(lhs,rhs); }
virtual string emitC() { return "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
virtual bool cleanOut() {return true;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*2; }
};
struct AstStreamR : public AstNodeStream {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
AstStreamR(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeStream(fl, lhsp, rhsp) {}
ASTNODE_NODE_FUNCS(StreamR, STREAMR)
virtual string emitVerilog() { return "%f{ >> %r %k{%l} }"; }
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opAssign(lhs); }
virtual string emitC() { return isWide() ? "VL_ASSIGN_W(%nw, %P, %li)" : "%li"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return false;}
virtual int instrCount() const { return widthInstrs()*2; }
};
struct AstBufIf1 : public AstNodeBiop {
// lhs is enable, rhs is data to drive
// Note unlike the Verilog bufif1() UDP, this allows any width; each lhsp bit enables respective rhsp bit
@@ -4201,15 +4268,15 @@ private:
bool m_default;
public:
AstPatMember(FileLine* fl, AstNode* lhsp, AstNode* keyp, AstNode* repp) : AstNodeMath(fl) {
setOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; }
addOp1p(lhsp), setNOp2p(keyp), setNOp3p(repp); m_default = false; }
ASTNODE_NODE_FUNCS(PatMember, PATMEMBER)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { V3ERROR_NA; }
virtual string emitVerilog() { return lhsp()?"%f{%r{%k%l}}":"%l"; }
virtual string emitVerilog() { return lhssp()?"%f{%r{%k%l}}":"%l"; }
virtual string emitC() { V3ERROR_NA; return "";}
virtual string emitSimpleOperator() { V3ERROR_NA; return "";}
virtual bool cleanOut() {V3ERROR_NA; return "";}
virtual int instrCount() const { return widthInstrs()*2; }
AstNode* lhsp() const { return op1p(); } // op1 = expression to assign or another AstPattern
AstNode* lhssp() const { return op1p(); } // op1 = expression to assign or another AstPattern (list if replicated)
AstNode* keyp() const { return op2p(); } // op2 = assignment key (Const, id Text)
AstNode* repp() const { return op3p(); } // op3 = replication count, or NULL for count 1
bool isDefault() const { return m_default; }
+2 -2
View File
@@ -94,9 +94,9 @@ private:
public:
// CONSTUCTORS
BranchVisitor(AstNetlist* rootp) {
BranchVisitor(AstNetlist* nodep) {
reset();
rootp->iterateChildren(*this);
nodep->iterateChildren(*this);
}
virtual ~BranchVisitor() {}
};
+12 -8
View File
@@ -37,6 +37,9 @@
#include "V3Broken.h"
#include "V3Ast.h"
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
#include "V3AstConstOnly.h"
//######################################################################
class BrokenTable : public AstNVisitor {
@@ -47,11 +50,11 @@ private:
typedef map<const AstNode*,int> NodeMap;
static NodeMap s_nodes; // Set of all nodes that exist
// BITMASK
static const int FLAG_ALLOCATED = 0x01; // new() and not delete()ed
static const int FLAG_IN_TREE = 0x02; // Is in netlist tree
static const int FLAG_LINKABLE = 0x04; // Is in netlist tree, can be linked to
static const int FLAG_LEAKED = 0x08; // Known to have been leaked
static const int FLAG_UNDER_NOW = 0x10; // Is in tree as parent of current node
enum { FLAG_ALLOCATED = 0x01 }; // new() and not delete()ed
enum { FLAG_IN_TREE = 0x02 }; // Is in netlist tree
enum { FLAG_LINKABLE = 0x04 }; // Is in netlist tree, can be linked to
enum { FLAG_LEAKED = 0x08 }; // Known to have been leaked
enum { FLAG_UNDER_NOW = 0x10 }; // Is in tree as parent of current node
public:
// METHODS
static void deleted(const AstNode* nodep) {
@@ -71,7 +74,8 @@ public:
((AstNode*)(nodep))->v3fatalSrc("Newing AstNode object that is already allocated\n");
}
if (iter == s_nodes.end()) {
s_nodes.insert(make_pair(nodep,FLAG_ALLOCATED));
int flags = FLAG_ALLOCATED; // This int needed to appease GCC 4.1.2
s_nodes.insert(make_pair(nodep,flags));
}
}
static void setUnder(const AstNode* nodep, bool flag) {
@@ -185,7 +189,7 @@ private:
// VISITORS
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::addInTree(nodep, nodep->maybePointedTo());
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
}
public:
// CONSTUCTORS
@@ -228,7 +232,7 @@ private:
nodep->v3fatalSrc("Width != WidthMin");
}
}
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
BrokenTable::setUnder(nodep,false);
}
public:
+1
View File
@@ -712,6 +712,7 @@ private:
virtual void visit(AstInitial* nodep, AstNUser*) { }
virtual void visit(AstTraceInc* nodep, AstNUser*) { }
virtual void visit(AstCoverToggle* nodep, AstNUser*) { }
virtual void visit(AstNodeDType* nodep, AstNUser*) { }
//--------------------
// Default
+4 -7
View File
@@ -81,22 +81,19 @@ private:
}
void genChangeDet(AstVarScope* vscp) {
#ifdef NEW_ORDERING
vscp->v3fatalSrc("Not applicable\n");
#endif
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstStructDType *structp = varp->dtypeSkipRefp()->castStructDType();
AstNodeClassDType *classp = varp->dtypeSkipRefp()->castNodeClassDType();
bool isArray = arrayp;
bool isStruct = structp && structp->packedUnsup();
bool isClass = classp && classp->packedUnsup();
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(elements));
} else if (!isArray && !isStruct
} else if (!isArray && !isClass
&& !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());
@@ -147,7 +144,7 @@ private:
if (!scopep) nodep->v3fatalSrc("No scope found on top level, perhaps you have no statements?\n");
m_scopetopp = scopep;
// Create change detection function
m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "IData");
m_chgFuncp = new AstCFunc(nodep->fileline(), "_change_request", scopep, "QData");
m_chgFuncp->argTypes(EmitCBaseVisitor::symClassVar());
m_chgFuncp->symProlog(true);
m_chgFuncp->declPrivate(true);
+10 -135
View File
@@ -320,28 +320,6 @@ private:
}
nodep->deleteTree(); nodep = NULL;
}
void moveInitial(AstActive* nodep) {
// Change to CFunc
AstNode* stmtsp = nodep->stmtsp();
if (stmtsp) {
if (!m_scopep) nodep->v3fatalSrc("Initial Active not under scope\n");
AstCFunc* funcp = new AstCFunc(nodep->fileline(), "_initial__"+m_scopep->nameDotless(),
m_scopep);
funcp->argTypes(EmitCBaseVisitor::symClassVar());
funcp->symProlog(true);
funcp->slow(true);
stmtsp->unlinkFrBackWithNext();
funcp->addStmtsp(stmtsp);
nodep->replaceWith(funcp);
// Add top level call to it
AstCCall* callp = new AstCCall(nodep->fileline(), funcp);
callp->argTypes("vlSymsp");
m_initFuncp->addStmtsp(callp);
} else {
nodep->unlinkFrBack();
}
nodep->deleteTree(); nodep=NULL;
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
nodep->iterateChildren(*this);
// Link to global function
@@ -365,13 +343,14 @@ private:
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
else m_settleFuncp->addStmtsp(stmtsp); // else add to top level function
}
void addToInitial(AstNode* stmtsp) {
if (m_untilp) m_untilp->addBodysp(stmtsp); // In a until loop, add to body
else m_initFuncp->addStmtsp(stmtsp); // else add to top level function
}
virtual void visit(AstActive* nodep, AstNUser*) {
// Careful if adding variables here, ACTIVES can be under other ACTIVES
// Need to save and restore any member state in AstUntilStable block
if (nodep->hasInitial()) {
moveInitial(nodep);
}
else if (!m_topScopep || !nodep->stmtsp()) {
if (!m_topScopep || !nodep->stmtsp()) {
// Not at the top or empty block...
// Only empty blocks should be leftover on the non-top. Killem.
if (nodep->stmtsp()) nodep->v3fatalSrc("Non-empty lower active");
@@ -381,6 +360,7 @@ private:
AstNode* stmtsp = nodep->stmtsp()->unlinkFrBackWithNext();
if (nodep->hasClocked()) {
// Remember the latest sensitivity so we can compare it next time
if (nodep->hasInitial()) nodep->v3fatalSrc("Initial block should not have clock sensitivity");
if (m_lastSenp && nodep->sensesp()->sameTree(m_lastSenp)) {
UINFO(4," sameSenseTree\n");
} else {
@@ -392,6 +372,10 @@ private:
}
// Move statements to if
m_lastIfp->addIfsp(stmtsp);
} else if (nodep->hasInitial()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function
addToInitial(stmtsp);
} else if (nodep->hasSettle()) {
// Don't need to: clearLastSen();, as we're adding it to different cfunc
// Move statements to function
@@ -406,115 +390,6 @@ private:
}
}
#ifdef NEW_ORDERING
virtual void visit(AstUntilStable* nodep, AstNUser*) {
// Process any sub ACTIVE statements first
UINFO(4," UNTILSTABLE "<<nodep<<endl);
{
// Keep vars if in middle of other stable
AstUntilStable* lastUntilp = m_untilp;
AstSenTree* lastSenp = m_lastSenp;
AstIf* lastIfp = m_lastIfp;
m_untilp = nodep;
m_lastSenp = NULL;
m_lastIfp = NULL;
nodep->iterateChildren(*this);
m_untilp = lastUntilp;
m_lastSenp = lastSenp;
m_lastIfp = lastIfp;
}
// Set "unstable" to 100. (non-stabilization count)
// int __VclockLoop = 0
// IData __Vchange = 1
// while (__Vchange) {
// Save old values of each until stable variable
// Evaluate the body
// __Vchange = {change_detect} contribution
// if (++__VclockLoop > 100) converge_error
if (debug()>4) nodep->dumpTree(cout, " UntilSt-old: ");
FileLine* fl = nodep->fileline();
if (nodep->bodysp()) fl = nodep->bodysp()->fileline(); // Point to applicable code...
m_stableNum++;
AstNode* origBodysp = nodep->bodysp(); if (origBodysp) origBodysp->unlinkFrBackWithNext();
AstVarScope* changeVarp = getCreateLocalVar(fl, "__Vchange"+cvtToStr(m_stableNum), NULL, 32);
AstVarScope* countVarp = getCreateLocalVar(fl, "__VloopCount"+cvtToStr(m_stableNum), NULL, 32);
AstWhile* untilp = new AstWhile(fl, new AstVarRef(fl, changeVarp, false), NULL);
AstNode* preUntilp = new AstComment(fl, "Change loop "+cvtToStr(m_stableNum));
preUntilp->addNext(new AstAssign(fl, new AstVarRef(fl, changeVarp, true),
new AstConst(fl, 1)));
preUntilp->addNext(new AstAssign(fl, new AstVarRef(fl, countVarp, true),
new AstConst(fl, 0)));
// Add stable variables & preinits
AstNode* setChglastp = NULL;
for (AstVarRef* varrefp = nodep->stablesp(); varrefp; varrefp=varrefp->nextp()->castVarRef()) {
AstVarScope* cmpvscp = getCreateLocalVar(varrefp->varp()->fileline(),
"__Vchglast"+cvtToStr(m_stableNum)+"__"+varrefp->name(),
varrefp->varp(), 0);
varrefp->varScopep()->user2p(cmpvscp);
setChglastp = setChglastp->addNext(
new AstAssign(fl, new AstVarRef(fl, cmpvscp, true),
new AstVarRef(fl, varrefp->varScopep(), false)));
}
if (!setChglastp) nodep->v3fatalSrc("UntilStable without any variables");
untilp->addBodysp(setChglastp);
untilp->addBodysp(new AstComment(fl, "Change Loop body begin"));
if (origBodysp) untilp->addBodysp(origBodysp);
untilp->addBodysp(new AstComment(fl, "Change Loop body end"));
// Add stable checks
// The order of the variables doesn't matter, but it's more expensive to test
// wide variables, and more so 64 bit wide ones. Someday it might be faster to
// set the changed variable in a "distributed" fashion over the code, IE,
// logic... logic.... a=....; Changed |= (a ^ old_a); more logic... Changed |=...
// But then, one hopes users don't have much unoptimized logic
AstNode* changeExprp = NULL;
int doublecount = 0;
for (int wide=0; wide<3; wide++) { // Adding backwards; wide, quad, then normal
for (AstVarRef* varrefp = nodep->stablesp(); varrefp; varrefp=varrefp->nextp()->castVarRef()) {
if (wide== ( varrefp->isQuad()?0:(varrefp->isWide() ? 1:2))) {
AstVarScope* cmpvscp = (AstVarScope*)(varrefp->varScopep()->user2p());
if (!cmpvscp) varrefp->v3fatalSrc("should have created above");
AstChangeXor* changep
= new AstChangeXor (fl,
new AstVarRef(fl, varrefp->varScopep(), false),
new AstVarRef(fl, cmpvscp, false));
if (!changeExprp) changeExprp = changep;
else if (doublecount++ > DOUBLE_OR_RATE) {
doublecount = 0;
changeExprp = new AstLogOr (fl, changep, changeExprp);
} else {
changeExprp = new AstOr (fl, changep, changeExprp);
}
}
}
}
if (!changeExprp) nodep->v3fatalSrc("UntilStable without any variables");
changeExprp = new AstAssign(fl, new AstVarRef(fl, changeVarp, true),
changeExprp);
untilp->addBodysp(changeExprp);
//
// Final body
AstNode* ifstmtp = new AstAssign(fl, new AstVarRef(fl, countVarp, true),
new AstAdd(fl, new AstConst(fl, 1),
new AstVarRef(fl, countVarp, false)));
ifstmtp->addNext(new AstIf(fl,
new AstLt (fl, new AstConst(fl, 100),
new AstVarRef(fl, countVarp, false)),
(new AstDisplay (fl, AstDisplayType::DT_DISPLAY,
"%%Error: Verilated model didn't converge", NULL, NULL))
->addNext(new AstStop (fl)),
NULL));
untilp->addBodysp(new AstIf(fl, new AstNeq(fl, new AstConst(fl, 0),
new AstVarRef(fl, changeVarp, false)),
ifstmtp, NULL));
//
// Replace it
preUntilp->addNext(untilp);
if (debug()>4) preUntilp->dumpTreeAndNext(cout, " UntilSt-new: ");
nodep->replaceWith(preUntilp); nodep->deleteTree(); nodep=NULL;
}
#endif
//--------------------
// Default: Just iterate
virtual void visit(AstNode* nodep, AstNUser*) {
+136 -20
View File
@@ -106,7 +106,8 @@ private:
bool m_doShort; // Remove expressions that short circuit
bool m_doV; // Verilog, not C++ conversion
bool m_doGenerate; // Postpone width checking inside generate
AstNodeModule* m_modp; // Current module
AstNodeModule* m_modp; // Current module
AstArraySel* m_selp; // Current select
AstNode* m_scopep; // Current scope
AstAttrOf* m_attrp; // Current attribute
@@ -233,16 +234,19 @@ private:
}
bool operandHugeShiftL(AstNodeBiop* nodep) {
return (nodep->rhsp()->castConst()
&& !nodep->rhsp()->castConst()->num().isFourState()
&& nodep->rhsp()->castConst()->toUInt() >= (uint32_t)(nodep->width())
&& isTPure(nodep->lhsp()));
}
bool operandHugeShiftR(AstNodeBiop* nodep) {
return (nodep->rhsp()->castConst()
&& !nodep->rhsp()->castConst()->num().isFourState()
&& nodep->rhsp()->castConst()->toUInt() >= (uint32_t)(nodep->lhsp()->width())
&& isTPure(nodep->lhsp()));
}
bool operandIsTwo(AstNode* nodep) {
return (nodep->castConst()
&& !nodep->castConst()->num().isFourState()
&& nodep->width() <= VL_QUADSIZE
&& nodep->castConst()->toUQuad()==2);
}
@@ -724,9 +728,15 @@ private:
AstNode* ap = lhsp->lhsp()->unlinkFrBack();
AstNode* shift1p = lhsp->rhsp()->unlinkFrBack();
AstNode* shift2p = nodep->rhsp()->unlinkFrBack();
// Shift1p and shift2p may have different sizes, both are self-determined so sum with infinite width
if (nodep->type()==lhsp->type()) {
int shift1 = shift1p->castConst()->toUInt();
int shift2 = shift2p->castConst()->toUInt();
int newshift = shift1+shift2;
shift1p->deleteTree(); shift1p=NULL;
shift2p->deleteTree(); shift2p=NULL;
nodep->lhsp(ap);
nodep->rhsp(new AstAdd(nodep->fileline(), shift1p, shift2p));
nodep->rhsp(new AstConst(nodep->fileline(), newshift));
nodep->accept(*this); // Further reduce, either node may have more reductions.
} else {
// We know shift amounts are constant, but might be a mixed left/right shift
@@ -734,7 +744,7 @@ private:
int shift2 = shift2p->castConst()->toUInt(); if (nodep->castShiftR()) shift2=-shift2;
int newshift = shift1+shift2;
shift1p->deleteTree(); shift1p=NULL;
shift2p->deleteTree(); shift1p=NULL;
shift2p->deleteTree(); shift2p=NULL;
AstNode* newp;
V3Number mask1 (nodep->fileline(), nodep->width());
V3Number ones (nodep->fileline(), nodep->width());
@@ -868,10 +878,10 @@ private:
}
if (debug()>=9) nodep->dumpTree(cout," Ass_old: ");
// Unlink the stuff
AstNode* lc1p = nodep->lhsp()->castConcat()->lhsp()->unlinkFrBack();
AstNode* lc2p = nodep->lhsp()->castConcat()->rhsp()->unlinkFrBack();
AstNode* conp = nodep->lhsp()->castConcat()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* lc1p = nodep->lhsp()->castConcat()->lhsp()->unlinkFrBack();
AstNode* lc2p = nodep->lhsp()->castConcat()->rhsp()->unlinkFrBack();
AstNode* conp = nodep->lhsp()->castConcat()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* rhs2p = rhsp->cloneTree(false);
// Calc widths
int lsb2 = 0;
@@ -940,6 +950,64 @@ private:
// Further reduce, either node may have more reductions.
return true;
}
else if (m_doV && nodep->rhsp()->castStreamR()) {
// The right-streaming operator on rhs of assignment does not
// change the order of bits. Eliminate stream but keep its lhsp
// Unlink the stuff
AstNode* srcp = nodep->rhsp()->castStreamR()->lhsp()->unlinkFrBack();
AstNode* sizep = nodep->rhsp()->castStreamR()->rhsp()->unlinkFrBack();
AstNode* streamp = nodep->rhsp()->castStreamR()->unlinkFrBack();
nodep->rhsp(srcp);
// Cleanup
sizep->deleteTree(); sizep=NULL;
streamp->deleteTree(); streamp=NULL;
// Further reduce, any of the nodes may have more reductions.
return true;
}
else if (m_doV && nodep->lhsp()->castStreamL()) {
// Push the stream operator to the rhs of the assignment statement
int dWidth = nodep->lhsp()->castStreamL()->lhsp()->width();
int sWidth = nodep->rhsp()->width();
// Unlink the stuff
AstNode* dstp = nodep->lhsp()->castStreamL()->lhsp()->unlinkFrBack();
AstNode* streamp = nodep->lhsp()->castStreamL()->unlinkFrBack();
AstNode* srcp = nodep->rhsp()->unlinkFrBack();
// Connect the rhs to the stream operator and update its width
streamp->castStreamL()->lhsp(srcp);
streamp->dtypeSetLogicSized((srcp->width()),
(srcp->widthMin()),
AstNumeric::UNSIGNED);
// Shrink the RHS if necessary
if (sWidth > dWidth) {
streamp = new AstSel(streamp->fileline(), streamp, sWidth-dWidth, dWidth);
}
// Link the nodes back in
nodep->lhsp(dstp);
nodep->rhsp(streamp);
return true;
}
else if (m_doV && nodep->lhsp()->castStreamR()) {
// The right stream operator on lhs of assignment statement does
// not reorder bits. However, if the rhs is wider than the lhs,
// then we select bits from the left-most, not the right-most.
int dWidth = nodep->lhsp()->castStreamR()->lhsp()->width();
int sWidth = nodep->rhsp()->width();
// Unlink the stuff
AstNode* dstp = nodep->lhsp()->castStreamR()->lhsp()->unlinkFrBack();
AstNode* sizep = nodep->lhsp()->castStreamR()->rhsp()->unlinkFrBack();
AstNode* streamp = nodep->lhsp()->castStreamR()->unlinkFrBack();
AstNode* srcp = nodep->rhsp()->unlinkFrBack();
if (sWidth > dWidth) {
srcp = new AstSel(streamp->fileline(), srcp, sWidth-dWidth, dWidth);
}
nodep->lhsp(dstp);
nodep->rhsp(srcp);
// Cleanup
sizep->deleteTree(); sizep=NULL;
streamp->deleteTree(); streamp=NULL;
// Further reduce, any of the nodes may have more reductions.
return true;
}
else if (replaceAssignMultiSel(nodep)) {
return true;
}
@@ -1221,15 +1289,35 @@ private:
nodep->iterateChildren(*this);
m_attrp = oldAttr;
}
virtual void visit(AstArraySel* nodep, AstNUser*) {
nodep->bitp()->iterateAndNext(*this);
if (nodep->bitp()->castConst()
&& nodep->fromp()->castVarRef()
// Need to make sure it's an array object so don't mis-allow a constant (bug509.)
&& nodep->fromp()->castVarRef()->varp()
&& nodep->fromp()->castVarRef()->varp()->valuep()->castInitArray()) {
m_selp = nodep; // Ask visit(AstVarRef) to replace varref with const
}
nodep->fromp()->iterateAndNext(*this);
if (nodep->fromp()->castConst()) { // It did.
if (!m_selp) {
nodep->v3error("Illegal assignment of constant to unpacked array");
} else {
nodep->replaceWith(nodep->fromp()->unlinkFrBack());
}
}
m_selp = NULL;
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
bool did=false;
if (m_doV && nodep->varp()->hasSimpleInit() && !m_attrp) {
//if (debug()) nodep->varp()->valuep()->dumpTree(cout," visitvaref: ");
nodep->varp()->valuep()->iterateAndNext(*this);
if (operandConst(nodep->varp()->valuep())
&& !nodep->lvalue()
if (m_doV && nodep->varp()->valuep() && !m_attrp) {
//if (debug()) valuep->dumpTree(cout," visitvaref: ");
nodep->varp()->valuep()->iterateAndNext(*this); // May change nodep->varp()->valuep()
AstNode* valuep = nodep->varp()->valuep();
if (!nodep->lvalue()
&& ((!m_params // Can reduce constant wires into equations
&& m_doNConst
&& v3Global.opt.oConst()
@@ -1237,11 +1325,23 @@ private:
&& nodep->varp()->isInput())
&& !nodep->varp()->isSigPublic())
|| nodep->varp()->isParam())) {
AstConst* constp = nodep->varp()->valuep()->castConst();
const V3Number& num = constp->num();
//UINFO(2,"constVisit "<<(void*)constp<<" "<<num<<endl);
replaceNum(nodep, num); nodep=NULL;
did=true;
if (operandConst(valuep)) {
const V3Number& num = valuep->castConst()->num();
//UINFO(2,"constVisit "<<(void*)valuep<<" "<<num<<endl);
replaceNum(nodep, num); nodep=NULL;
did=true;
}
else if (m_selp && valuep->castInitArray()) {
int bit = m_selp->bitConst();
AstNode* itemp = valuep->castInitArray()->initsp();
for (int n=0; n<bit && itemp; ++n, itemp=itemp->nextp()) {}
if (itemp->castConst()) {
const V3Number& num = itemp->castConst()->num();
//UINFO(2,"constVisit "<<(void*)valuep<<" "<<num<<endl);
replaceNum(nodep, num); nodep=NULL;
did=true;
}
}
}
}
if (!did && m_required) {
@@ -1666,6 +1766,10 @@ private:
}
}
}
virtual void visit(AstInitArray* nodep, AstNUser*) {
// Constant if all children are constant
nodep->iterateChildren(*this);
}
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
@@ -1711,6 +1815,12 @@ private:
//-----
// Below lines are magic expressions processed by astgen
// TREE_SKIP_VISIT("AstNODETYPE") # Rename normal visit to visitGen and don't iterate
//-----
TREE_SKIP_VISIT("ArraySel");
//-----
// "AstNODETYPE { # bracket not paren
// $accessor_name, ...
// # ,, gets replaced with a , rather than &&
@@ -1751,8 +1861,14 @@ private:
TREEOP ("AstDivS {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstMul {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstMulS {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPow {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowS {$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPow {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPowSS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPowSU {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPowUS {$rhsp.isZero}", "replaceNum(nodep, 1)"); // Overrides lhs zero rule
TREEOP ("AstPow {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowUS {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstPowSU {$lhsp.isZero, !$rhsp.isZero}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstOr {$lhsp.isZero, $rhsp}", "replaceWRhs(nodep)");
TREEOP ("AstShiftL{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
TREEOP ("AstShiftR{$lhsp.isZero, $rhsp}", "replaceZeroChkPure(nodep,$rhsp)");
@@ -1791,7 +1907,6 @@ private:
TREEOP ("AstMul {operandIsPowTwo($lhsp), $rhsp}", "replaceMulShift(nodep)"); // a*2^n -> a<<n
TREEOP ("AstDiv {$lhsp, operandIsPowTwo($rhsp)}", "replaceDivShift(nodep)"); // a/2^n -> a>>n
TREEOP ("AstPow {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
TREEOP ("AstPowS {operandIsTwo($lhsp), $rhsp}", "replacePowShift(nodep)"); // 2**a == 1<<a
// Trinary ops
// Note V3Case::Sel requires Cond to always be conditionally executed in C to prevent core dump!
TREEOP ("AstNodeCond{$condp.isZero, $expr1p, $expr2p}", "replaceWChild(nodep,$expr2p)");
@@ -2038,6 +2153,7 @@ public:
m_warn = false;
m_wremove = true; // Overridden in visitors
m_modp = NULL;
m_selp = NULL;
m_scopep = NULL;
m_attrp = NULL;
//
+17 -8
View File
@@ -60,9 +60,14 @@ private:
}
};
// NODE STATE
// Entire netlist:
// AstIf::user1() -> bool. True indicates ifelse processed
AstUser1InUse m_inuser1;
// STATE
bool m_checkBlock; // Should this block get covered?
AstNodeModule* m_modp; // Current module to add statement to
bool m_checkBlock; // Should this block get covered?
AstNodeModule* m_modp; // Current module to add statement to
bool m_inToggleOff; // In function/task etc
bool m_inModOff; // In module with no coverage
FileMap m_fileps; // Column counts for each fileline
@@ -277,12 +282,18 @@ private:
virtual void visit(AstIf* nodep, AstNUser*) { // Note not AstNodeIf; other types don't get covered
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
// An else-if. When we iterate the if, use "elsif" marking
bool elsif = (nodep->elsesp()->castIf()
&& !nodep->elsesp()->castIf()->nextp());
if (elsif) nodep->elsesp()->castIf()->user1(true);
//
nodep->ifsp()->iterateAndNext(*this);
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it
if (!nodep->backp()->castIf()
|| nodep->backp()->castIf()->elsesp()!=nodep) { // Ignore if else; did earlier
UINFO(4," COVER: "<<nodep<<endl);
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->user1()) {
nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "elsif"));
} else {
nodep->addIfsp(newCoverInc(nodep->fileline(), "", "v_line", "if"));
}
}
@@ -293,9 +304,7 @@ private:
if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->elsesp()->castIf()) {
nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), "", "v_line", "elsif"));
} else {
if (!elsif) { // elsif done inside if()
nodep->addElsesp(newCoverInc(nodep->elsesp()->fileline(), "", "v_line", "else"));
}
}
+9 -7
View File
@@ -118,7 +118,7 @@ private:
nodep->v3warn(BLKANDNBLK,"Unsupported: Blocked and non-blocking assignments to same variable: "<<nodep->varp()->prettyName());
}
}
AstVarScope* createVarSc(AstVarScope* oldvarscp, string name, int width/*0==fromoldvar*/) {
AstVarScope* createVarSc(AstVarScope* oldvarscp, string name, int width/*0==fromoldvar*/, AstNodeDType* newdtypep) {
// Because we've already scoped it, we may need to add both the AstVar and the AstVarScope
if (!oldvarscp->scopep()) oldvarscp->v3fatalSrc("Var unscoped");
AstVar* varp;
@@ -129,7 +129,9 @@ private:
// Created module's AstVar earlier under some other scope
varp = it->second;
} else {
if (width==0) {
if (newdtypep) {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, newdtypep);
} else if (width==0) {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
varp->dtypeFrom(oldvarscp);
} else { // Used for vset and dimensions, so can zero init
@@ -219,7 +221,7 @@ private:
} else {
string bitvarname = (string("__Vdlyvdim")+cvtToStr(dimension)
+"__"+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width());
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, dimp->width(), NULL);
AstAssign* bitassignp
= new AstAssign (nodep->fileline(),
new AstVarRef(nodep->fileline(), bitvscp, true),
@@ -237,7 +239,7 @@ private:
bitreadp = lsbvaluep;
} else {
string bitvarname = (string("__Vdlyvlsb__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width());
AstVarScope* bitvscp = createVarSc(varrefp->varScopep(), bitvarname, lsbvaluep->width(), NULL);
AstAssign* bitassignp = new AstAssign (nodep->fileline(),
new AstVarRef(nodep->fileline(), bitvscp, true),
lsbvaluep);
@@ -252,7 +254,7 @@ private:
valreadp = nodep->rhsp()->unlinkFrBack();
} else {
string valvarname = (string("__Vdlyvval__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, nodep->rhsp()->width());
AstVarScope* valvscp = createVarSc(varrefp->varScopep(), valvarname, 0, nodep->rhsp()->dtypep());
newlhsp = new AstVarRef(nodep->fileline(), valvscp, true);
valreadp = new AstVarRef(nodep->fileline(), valvscp, false);
}
@@ -270,7 +272,7 @@ private:
++m_statSharedSet;
} else { // Create new one
string setvarname = (string("__Vdlyvset__")+oldvarp->shortName()+"__v"+cvtToStr(modVecNum));
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1);
setvscp = createVarSc(varrefp->varScopep(), setvarname, 1, NULL);
setinitp = new AstAssignPre (nodep->fileline(),
new AstVarRef(nodep->fileline(), setvscp, true),
new AstConst(nodep->fileline(), 0));
@@ -399,7 +401,7 @@ private:
}
if (!dlyvscp) { // First use of this delayed variable
string newvarname = (string("__Vdly__")+nodep->varp()->shortName());
dlyvscp = createVarSc(oldvscp, newvarname, 0);
dlyvscp = createVarSc(oldvscp, newvarname, 0, NULL);
AstNodeAssign* prep
= new AstAssignPre (nodep->fileline(),
new AstVarRef(nodep->fileline(), dlyvscp, true),
+60 -24
View File
@@ -32,6 +32,7 @@
#include "V3String.h"
#include "V3EmitC.h"
#include "V3EmitCBase.h"
#include "V3Number.h"
#define VL_VALUE_STRING_MAX_WIDTH 8192 // We use a static char array in VL_VALUE_STRING
@@ -71,7 +72,7 @@ public:
string vfmt, char fmtLetter);
void emitVarDecl(AstVar* nodep, const string& prefixIfImp);
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_STATIC, EVL_ALL} EisWhich;
typedef enum {EVL_IO, EVL_SIG, EVL_TEMP, EVL_PAR, EVL_ALL} EisWhich;
void emitVarList(AstNode* firstp, EisWhich which, const string& prefixIfImp);
void emitVarCtors();
bool emitSimpleOk(AstNodeMath* nodep);
@@ -552,6 +553,28 @@ public:
emitOpName(nodep, nodep->emitC(), nodep->lhsp(), nodep->rhsp(), NULL);
}
}
virtual void visit(AstStreamL* nodep, AstNUser*) {
// Attempt to use a "fast" stream function for slice size = power of 2
if (!nodep->isWide()) {
uint32_t isPow2 = nodep->rhsp()->castConst()->num().countOnes() == 1;
uint32_t sliceSize = nodep->rhsp()->castConst()->toUInt();
if (isPow2 && sliceSize <= (nodep->isQuad() ? sizeof(uint64_t) : sizeof(uint32_t))) {
puts("VL_STREAML_FAST_");
emitIQW(nodep);
emitIQW(nodep->lhsp());
puts("I(");
puts(cvtToStr(nodep->widthMin()));
puts(","+cvtToStr(nodep->lhsp()->widthMin()));
puts(","+cvtToStr(nodep->rhsp()->widthMin()));
puts(",");
nodep->lhsp()->iterateAndNext(*this); puts(", ");
uint32_t rd_log2 = V3Number::log2b(nodep->rhsp()->castConst()->toUInt());
puts(cvtToStr(rd_log2)+")");
return;
}
}
emitOpName(nodep, "VL_STREAML_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)", nodep->lhsp(), nodep->rhsp(), NULL);
}
// Terminals
virtual void visit(AstVarRef* nodep, AstNUser*) {
puts(nodep->hiername());
@@ -581,7 +604,15 @@ public:
}
ofp()->printf(",0x%08" VL_PRI64 "x)", (vluint64_t)(nodep->num().dataWord(0)));
} else if (nodep->isDouble()) {
ofp()->printf("%.17g", nodep->num().toDouble());
if (int(nodep->num().toDouble()) == nodep->num().toDouble()
&& nodep->num().toDouble() < 1000
&& nodep->num().toDouble() > -1000) {
ofp()->printf("%3.1f", nodep->num().toDouble()); // Force decimal point
} else {
// Not %g as will not always put in decimal point, so not obvious to compiler
// is a real number
ofp()->printf("%.17e", nodep->num().toDouble());
}
} else if (nodep->isQuad()) {
vluint64_t num = nodep->toUQuad();
if (num<10) ofp()->printf("VL_ULL(%" VL_PRI64 "d)", num);
@@ -690,7 +721,8 @@ class EmitCImp : EmitCStmts {
}
changep->lhsp()->iterateAndNext(*this);
if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]");
puts(" ^ ");
if (changep->lhsp()->isDouble()) puts(" != ");
else puts(" ^ ");
changep->rhsp()->iterateAndNext(*this);
if (changep->lhsp()->isWide()) puts("["+cvtToStr(word)+"]");
puts(")");
@@ -786,9 +818,7 @@ class EmitCImp : EmitCStmts {
if (nodep->stmtsp()) puts("// Body\n");
nodep->stmtsp()->iterateAndNext(*this);
#ifndef NEW_ORDERING
if (!m_blkChangeDetVec.empty()) emitChangeDet();
#endif
if (nodep->finalsp()) puts("// Final\n");
nodep->finalsp()->iterateAndNext(*this);
@@ -802,7 +832,7 @@ class EmitCImp : EmitCStmts {
void emitChangeDet() {
puts("// Change detection\n");
puts("IData __req = false; // Logically a bool\n"); // But not because it results in faster code
puts("QData __req = false; // Logically a bool\n"); // But not because it results in faster code
bool gotOne = false;
for (vector<AstChangeDet*>::iterator it = m_blkChangeDetVec.begin();
it != m_blkChangeDetVec.end(); ++it) {
@@ -900,6 +930,11 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
puts(nodep->name());
emitDeclArrayBrackets(nodep);
puts(";\n");
} else if (basicp && basicp->isOpaque()) {
// strings and other fundamental c types; no VL_ macro can be used
puts(nodep->vlArgType(true,false,false));
emitDeclArrayBrackets(nodep);
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
nodep->dtypeSkipRefp()->widthTotalBytes());
@@ -923,7 +958,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
} else if (basicp && basicp->isOpaque()) {
// strings and other fundamental c types
puts(nodep->vlArgType(true,false));
puts(nodep->vlArgType(true,false,false));
emitDeclArrayBrackets(nodep);
puts(";\n");
} else {
@@ -1074,9 +1109,13 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format,
break;
}
}
} else if (pos[0] == ')') {
nextComma=""; puts(")");
} else if (pos[0] == '(') {
COMMA; needComma = false; puts("(");
} else {
// Normal text
if (pos[0] == ')') nextComma="";
if (isalnum(pos[0])) needComma = true;
COMMA;
string s; s+=pos[0]; puts(s);
}
@@ -1310,7 +1349,9 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
// Constructor deals with it
}
else if (varp->isParam()) {
if (!varp->hasSimpleInit()) nodep->v3fatalSrc("No init for a param?");
if (!varp->valuep()) nodep->v3fatalSrc("No init for a param?");
// If a simple CONST value we initialize it using an enum
// If an ARRAYINIT we initialize it using an initial block similar to a signal
//puts("// parameter "+varp->name()+" = "+varp->valuep()->name()+"\n");
}
else if (AstInitArray* initarp = varp->valuep()->castInitArray()) {
@@ -1621,20 +1662,16 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
}
puts("// Evaluate till stable\n");
puts("VL_DEBUG_IF(VL_PRINTF(\"\\n----TOP Evaluate "+modClassName(modp)+"::eval\\n\"); );\n");
#ifndef NEW_ORDERING
puts("int __VclockLoop = 0;\n");
puts("IData __Vchange=1;\n");
puts("QData __Vchange=1;\n");
puts("while (VL_LIKELY(__Vchange)) {\n");
puts( "VL_DEBUG_IF(VL_PRINTF(\" Clock loop\\n\"););\n");
#endif
puts( "vlSymsp->__Vm_activity = true;\n");
puts( "_eval(vlSymsp);\n");
#ifndef NEW_ORDERING
puts( "__Vchange = _change_request(vlSymsp);\n");
puts( "if (++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
+") vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't converge\");\n");
puts("}\n");
#endif
puts("}\n");
splitSizeInc(10);
@@ -1642,20 +1679,16 @@ void EmitCImp::emitWrapEval(AstNodeModule* modp) {
puts("\nvoid "+modClassName(modp)+"::_eval_initial_loop("+EmitCBaseVisitor::symClassVar()+") {\n");
puts("vlSymsp->__Vm_didInit = true;\n");
puts("_eval_initial(vlSymsp);\n");
#ifndef NEW_ORDERING
puts( "vlSymsp->__Vm_activity = true;\n");
puts( "int __VclockLoop = 0;\n");
puts( "IData __Vchange=1;\n");
puts( "QData __Vchange=1;\n");
puts( "while (VL_LIKELY(__Vchange)) {\n");
#endif
puts( "_eval_settle(vlSymsp);\n");
puts( "_eval(vlSymsp);\n");
#ifndef NEW_ORDERING
puts( "__Vchange = _change_request(vlSymsp);\n");
puts( "if (++__VclockLoop > "+cvtToStr(v3Global.opt.convergeLimit())
+") vl_fatal(__FILE__,__LINE__,__FILE__,\"Verilated model didn't DC converge\");\n");
puts( "}\n");
#endif
puts("}\n");
splitSizeInc(10);
}
@@ -1682,6 +1715,7 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
case EVL_IO: doit = varp->isIO(); break;
case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break;
case EVL_TEMP: doit = (varp->isTemp() && !varp->isIO()); break;
case EVL_PAR: doit = (varp->isParam() && !varp->valuep()->castConst()); break;
default: v3fatalSrc("Bad Case");
}
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
@@ -1837,6 +1871,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
puts("\n// PARAMETERS\n");
if (modp->isTop()) puts("// Parameters marked /*verilator public*/ for use by application code\n");
ofp()->putsPrivate(false); // public:
emitVarList(modp->stmtsp(), EVL_PAR, ""); // Only those that are non-CONST
for (AstNode* nodep=modp->stmtsp(); nodep; nodep = nodep->nextp()) {
if (AstVar* varp = nodep->castVar()) {
if (varp->isParam() && (varp->isUsedParam() || varp->isSigPublic())) {
@@ -1846,7 +1881,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
if (varp->isWide()) { // Unsupported for output
puts("// enum WData "+varp->name()+" //wide");
} else if (!varp->valuep()->castConst()) { // Unsupported for output
puts("// enum IData "+varp->name()+" //not simple value");
//puts("// enum ..... "+varp->name()+" //not simple value, see variable above instead");
} else {
puts("enum ");
puts(varp->isQuad()?"_QData":"_IData");
@@ -2061,6 +2096,7 @@ void EmitCImp::main(AstNodeModule* modp, bool slow, bool fast) {
m_ofp = newOutCFile (modp, !m_fast, true/*source*/, splitFilenumInc());
emitImp (modp);
}
splitSizeInc(10); // Even blank functions get a file with a low csplit
mainDoFunc(funcp);
}
}
@@ -2184,7 +2220,7 @@ class EmitCTrace : EmitCStmts {
}
void emitTraceInitOne(AstTraceDecl* nodep) {
if (nodep->isDouble()) {
if (nodep->dtypep()->basicp()->isDouble()) {
puts("vcdp->declDouble");
} else if (nodep->isWide()) {
puts("vcdp->declArray");
@@ -2204,7 +2240,7 @@ class EmitCTrace : EmitCStmts {
} else {
puts(",-1");
}
if (!nodep->isDouble() // When float/double no longer have widths this can go
if (!nodep->dtypep()->basicp()->isDouble() // When float/double no longer have widths this can go
&& nodep->bitRange().ranged()) {
puts(","+cvtToStr(nodep->bitRange().left())+","+cvtToStr(nodep->bitRange().right()));
}
@@ -2216,7 +2252,7 @@ class EmitCTrace : EmitCStmts {
string full = ((m_funcp->funcType() == AstCFuncType::TRACE_FULL
|| m_funcp->funcType() == AstCFuncType::TRACE_FULL_SUB)
? "full":"chg");
if (nodep->isDouble()) {
if (nodep->dtypep()->basicp()->isDouble()) {
puts("vcdp->"+full+"Double");
} else if (nodep->isWide() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep)) {
puts("vcdp->"+full+"Array");
@@ -2231,7 +2267,7 @@ class EmitCTrace : EmitCStmts {
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
puts(",");
emitTraceValue(nodep, arrayindex);
if (!nodep->isDouble() // When float/double no longer have widths this can go
if (!nodep->dtypep()->basicp()->isDouble() // When float/double no longer have widths this can go
&& (nodep->declp()->bitRange().ranged() || emitTraceIsScBv(nodep) || emitTraceIsScBigUint(nodep))) {
puts(","+cvtToStr(nodep->declp()->widthMin()));
}
+1 -1
View File
@@ -78,7 +78,7 @@ public:
args += portp->dpiArgType(true,false);
else if (nodep->funcPublic())
args += portp->cPubArgType(true,false);
else args += portp->vlArgType(true,false);
else args += portp->vlArgType(true,false,true);
}
}
}
+2
View File
@@ -203,6 +203,7 @@ class EmitCSyms : EmitCBaseVisitor {
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
nameCheck(nodep);
nodep->iterateChildren(*this);
if (nodep->isSigUserRdPublic()
&& !nodep->isParam()) { // The VPI functions require a pointer to allow modification, but parameters are constants
@@ -220,6 +221,7 @@ class EmitCSyms : EmitCBaseVisitor {
nodep->iterateChildren(*this);
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
nameCheck(nodep);
if (nodep->dpiImport() || nodep->dpiExportWrapper()) {
m_dpis.push_back(nodep);
}
+20 -12
View File
@@ -245,23 +245,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstFOpen* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
if (nodep->filep()) nodep->filep()->iterateAndNext(*this);
putbs(",");
if (nodep->filenamep()) nodep->filenamep()->iterateChildren(*this);
if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this);
putbs(",");
if (nodep->modep()) nodep->modep()->iterateChildren(*this);
if (nodep->modep()) nodep->modep()->iterateAndNext(*this);
puts(");\n");
}
virtual void visit(AstFClose* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
if (nodep->filep()) nodep->filep()->iterateAndNext(*this);
puts(");\n");
}
virtual void visit(AstFFlush* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filep()) nodep->filep()->iterateChildren(*this);
if (nodep->filep()) nodep->filep()->iterateAndNext(*this);
puts(");\n");
}
virtual void visit(AstJumpGo* nodep, AstNUser*) {
@@ -269,23 +269,23 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstJumpLabel* nodep, AstNUser*) {
putbs("begin : "+cvtToStr((void*)(nodep))+"\n");
if (nodep->stmtsp()) nodep->stmtsp()->iterateChildren(*this);
if (nodep->stmtsp()) nodep->stmtsp()->iterateAndNext(*this);
puts("end\n");
}
virtual void visit(AstReadMem* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
if (nodep->filenamep()) nodep->filenamep()->iterateChildren(*this);
if (nodep->filenamep()) nodep->filenamep()->iterateAndNext(*this);
putbs(",");
if (nodep->memp()) nodep->memp()->iterateChildren(*this);
if (nodep->lsbp()) { putbs(","); nodep->lsbp()->iterateChildren(*this); }
if (nodep->msbp()) { putbs(","); nodep->msbp()->iterateChildren(*this); }
if (nodep->memp()) nodep->memp()->iterateAndNext(*this);
if (nodep->lsbp()) { putbs(","); nodep->lsbp()->iterateAndNext(*this); }
if (nodep->msbp()) { putbs(","); nodep->msbp()->iterateAndNext(*this); }
puts(");\n");
}
virtual void visit(AstSysIgnore* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
putbs(" (");
nodep->exprsp()->iterateChildren(*this);
nodep->exprsp()->iterateAndNext(*this);
puts(");\n");
}
virtual void visit(AstNodeFor* nodep, AstNUser*) {
@@ -446,6 +446,14 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
puts(")");
}
virtual void visit(AstInitArray* nodep, AstNUser*) {
putfs(nodep,"`{");
for (AstNode* subp = nodep->initsp(); subp; subp=subp->nextp()) {
subp->accept(*this);
if (subp->nextp()) putbs(",");
}
puts("}");
}
virtual void visit(AstNodeCond* nodep, AstNUser*) {
putbs("(");
nodep->condp()->iterateAndNext(*this); putfs(nodep," ? ");
@@ -560,7 +568,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstVar* nodep, AstNUser*) {
putfs(nodep,nodep->verilogKwd());
puts(" ");
nodep->dtypep()->iterateAndNext(*this); puts(" ");
nodep->dtypep()->iterate(*this); puts(" ");
puts(nodep->prettyName());
puts(";\n");
}
+10 -2
View File
@@ -84,6 +84,7 @@ public:
MULTIDRIVEN, // Driven from multiple blocks
PINMISSING, // Cell pin not specified
PINNOCONNECT, // Cell pin not connected
PINCONNECTEMPTY,// Cell pin connected by name with empty reference: ".name()" (can be used to mark unused pins)
REALCVT, // Real conversion
REDEFMACRO, // Redefining existing define macro
SELRANGE, // Selection index out of range
@@ -127,7 +128,7 @@ public:
"INCABSPATH", "INITIALDLY",
"LITENDIAN", "MODDUP",
"MULTIDRIVEN",
"PINMISSING", "PINNOCONNECT",
"PINMISSING", "PINNOCONNECT", "PINCONNECTEMPTY",
"REALCVT", "REDEFMACRO",
"SELRANGE", "STMTDLY", "SYMRSVDWORD", "SYNCASYNCNET",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNPACKED", "UNSIGNED", "UNUSED",
@@ -165,6 +166,7 @@ public:
|| m_e==DEFPARAM
|| m_e==DECLFILENAME
|| m_e==INCABSPATH
|| m_e==PINCONNECTEMPTY
|| m_e==PINNOCONNECT
|| m_e==SYNCASYNCNET
|| m_e==UNDRIVEN
@@ -270,12 +272,18 @@ template< class T> std::string cvtToStr (const T& t) {
inline uint32_t cvtToHash(const void* vp) {
// We can shove a 64 bit pointer into a 32 bit bucket
// On 32 bit systems, lower is always 0, but who cares?
// On 32-bit systems, lower is always 0, but who cares?
union { const void* up; struct {uint32_t upper; uint32_t lower;} l;} u;
u.l.upper=0; u.l.lower=0; u.up=vp;
return u.l.upper^u.l.lower;
}
inline string ucfirst(const string& text) {
string out = text;
out[0] = toupper(out[0]);
return out;
}
//######################################################################
class FileLine;
+3 -3
View File
@@ -30,7 +30,7 @@
#include <memory>
#include <map>
#if defined(__unix__)
#if defined(__unix__) || defined(__unix) || (defined(__APPLE__) && defined(__MACH__))
# define INFILTER_PIPE // Allow pipe filtering. Needs fork()
#endif
@@ -120,7 +120,7 @@ V3FileDependImp dependImp; // Depend implementation class
// V3FileDependImp
inline void V3FileDependImp::writeDepend(const string& filename) {
const auto_ptr<ofstream> ofp (V3File::new_ofstream(filename));
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
for (set<DependFile>::iterator iter=m_filenameList.begin();
@@ -156,7 +156,7 @@ inline void V3FileDependImp::writeDepend(const string& filename) {
}
inline void V3FileDependImp::writeTimes(const string& filename, const string& cmdlineIn) {
const auto_ptr<ofstream> ofp (V3File::new_ofstream(filename));
const VL_UNIQUE_PTR<ofstream> ofp (V3File::new_ofstream(filename));
if (ofp->fail()) v3fatalSrc("Can't write "<<filename);
string cmdline = stripQuotes(cmdlineIn);
+8 -3
View File
@@ -222,7 +222,7 @@ private:
// V3Const cleans up any NOTs by flipping the edges for us
if (m_buffersOnly
&& !(nodep->rhsp()->castVarRef()
// Until NEW_ORDERING, avoid making non-clocked logic into clocked,
// Avoid making non-clocked logic into clocked,
// as it slows down the verilator_sim_benchmark
|| (nodep->rhsp()->castNot()
&& nodep->rhsp()->castNot()->lhsp()->castVarRef()
@@ -929,7 +929,12 @@ private:
public:
// CONSTUCTORS
GateDedupeVarVisitor() {}
GateDedupeVarVisitor() {
m_assignp = NULL;
m_ifCondp = NULL;
m_always = false;
m_dedupable = true;
}
// PUBLIC METHODS
AstNodeVarRef* findDupe(AstNode* nodep, AstVarScope* consumerVarScopep, AstActive* activep) {
m_assignp = NULL;
@@ -978,7 +983,7 @@ private:
AstVarScope* dupVarScopep = dupVarRefp->varScopep();
GateVarVertex* dupVvertexp = (GateVarVertex*) (dupVarScopep->user1p());
UINFO(4,"replacing " << vvertexp << " with " << dupVvertexp << endl);
m_numDeduped++;
++m_numDeduped;
// Replace all of this varvertex's consumers with dupVarRefp
for (V3GraphEdge* outedgep = vvertexp->outBeginp();outedgep;) {
GateLogicVertex* consumeVertexp = dynamic_cast<GateLogicVertex*>(outedgep->top());
+2 -2
View File
@@ -115,7 +115,7 @@ private:
}
virtual void visit(AstActive* nodep, AstNUser*) {
m_activep = nodep;
nodep->sensesp()->iterateChildren(*this);
nodep->sensesp()->iterateChildren(*this); // iterateAndNext?
m_activep = NULL;
nodep->iterateChildren(*this);
}
@@ -201,7 +201,7 @@ private:
virtual void visit(AstActive* nodep, AstNUser*) {
UINFO(8,"ACTIVE "<<nodep<<endl);
m_activep = nodep;
nodep->sensesp()->iterateChildren(*this);
nodep->sensesp()->iterateChildren(*this); // iterateAndNext?
m_activep = NULL;
nodep->iterateChildren(*this);
}
+1 -1
View File
@@ -80,7 +80,7 @@ private:
if (m_modp->user2() != CIL_NOTHARD) {
UINFO(4," No inline hard: "<<reason<<" "<<m_modp<<endl);
m_modp->user2(CIL_NOTHARD);
m_statUnsup++;
++m_statUnsup;
}
} else {
if (m_modp->user2() == CIL_MAYBE) {
+7 -1
View File
@@ -308,7 +308,13 @@ private:
set<string> ports; // Symbol table of all connected port names
for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
if (pinp->name()=="") pinp->v3error("Connect by position is illegal in .* connected cells");
if (!pinp->exprp()) pinp->v3warn(PINNOCONNECT,"Cell pin is not connected: "<<pinp->prettyName());
if (!pinp->exprp()) {
if (pinp->name().substr(0, 11) == "__pinNumber") {
pinp->v3warn(PINNOCONNECT,"Cell pin is not connected: "<<pinp->prettyName());
} else {
pinp->v3warn(PINCONNECTEMPTY,"Cell pin connected by name with empty reference: "<<pinp->prettyName());
}
}
if (ports.find(pinp->name()) == ports.end()) {
ports.insert(pinp->name());
}
+46 -30
View File
@@ -96,6 +96,12 @@ private:
AstUser2InUse m_inuser2;
AstUser4InUse m_inuser4;
public:
// ENUMS
// In order of priority, compute first ... compute last
enum SAMNum { SAMN_MODPORT, SAMN_IFTOP, SAMN__MAX }; // Values for m_scopeAliasMap
private:
// TYPES
typedef multimap<string,VSymEnt*> NameScopeSymMap;
typedef map<VSymEnt*,VSymEnt*> ScopeAliasMap;
@@ -110,7 +116,7 @@ private:
VSymEnt* m_dunitEntp; // $unit entry
NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it
ScopeAliasMap m_scopeAliasMap; // Map of <lhs,rhs> aliases
ScopeAliasMap m_scopeAliasMap[SAMN__MAX]; // Map of <lhs,rhs> aliases
IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
bool m_forPrimary; // First link
@@ -127,13 +133,22 @@ public:
void dump(const string& nameComment="linkdot", bool force=false) {
if (debug()>=6 || force) {
string filename = v3Global.debugFilename(nameComment)+".txt";
const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
const VL_UNIQUE_PTR<ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
ostream& os = *logp;
m_syms.dump(os);
if (!m_scopeAliasMap.empty()) os<<"\nScopeAliasMap:\n";
for (ScopeAliasMap::iterator it = m_scopeAliasMap.begin(); it != m_scopeAliasMap.end(); ++it) {
os<<"\t"<<it->first<<" -> "<<it->second<<endl;
bool first = true;
for (int samn=0; samn<SAMN__MAX; ++samn) {
if (!m_scopeAliasMap[samn].empty()) {
if (first) os<<"\nScopeAliasMap:\n";
first = false;
for (ScopeAliasMap::iterator it = m_scopeAliasMap[samn].begin();
it != m_scopeAliasMap[samn].end(); ++it) {
// left side is what we will import into
os<<"\t"<<samn<<"\t"<<it->first<<" ("<<it->first->nodep()->typeName()
<<") <- "<<it->second<<" "<<it->second->nodep()<<endl;
}
}
}
}
}
@@ -181,11 +196,6 @@ public:
else if (nodep->castIface()) return "interface";
else return nodep->prettyTypeName();
}
static string ucfirst(const string& text) {
string out = text;
out[0] = toupper(out[0]);
return out;
}
VSymEnt* rootEntp() const { return m_syms.rootp(); }
VSymEnt* dunitEntp() const { return m_dunitEntp; }
@@ -382,31 +392,36 @@ public:
<<"': "<<ifacerefp->prettyName(ifacerefp->modportName()));
}
// Alias won't expand until interfaces and modport names are known; see notes at top
insertScopeAlias(varSymp, ifOrPortSymp);
insertScopeAlias(SAMN_IFTOP, varSymp, ifOrPortSymp);
}
m_ifaceVarSyms.clear();
}
// Track and later insert scope aliases
void insertScopeAlias(VSymEnt* lhsp, VSymEnt* rhsp) { // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
void insertScopeAlias(SAMNum samn, VSymEnt* lhsp, VSymEnt* rhsp) {
// Track and later insert scope aliases; an interface referenced by a child cell connecting to that interface
// Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
UINFO(9," insertScopeAlias se"<<(void*)lhsp<<" se"<<(void*)rhsp<<endl);
m_scopeAliasMap.insert(make_pair(lhsp, rhsp));
m_scopeAliasMap[samn].insert(make_pair(lhsp, rhsp));
}
void computeScopeAliases() {
UINFO(9,"computeIfaceAliases\n");
for (ScopeAliasMap::iterator it=m_scopeAliasMap.begin(); it!=m_scopeAliasMap.end(); ++it) {
VSymEnt* lhsp = it->first;
VSymEnt* srcp = lhsp;
while (1) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap::iterator it2 = m_scopeAliasMap.find(srcp);
if (it2 != m_scopeAliasMap.end()) { srcp = it2->second; continue; }
else break;
for (int samn=0; samn<SAMN__MAX; ++samn) {
for (ScopeAliasMap::iterator it=m_scopeAliasMap[samn].begin();
it!=m_scopeAliasMap[samn].end(); ++it) {
VSymEnt* lhsp = it->first;
VSymEnt* srcp = lhsp;
while (1) { // Follow chain of aliases up to highest level non-alias
ScopeAliasMap::iterator it2 = m_scopeAliasMap[samn].find(srcp);
if (it2 != m_scopeAliasMap[samn].end()) { srcp = it2->second; continue; }
else break;
}
UINFO(9," iiasa: Insert alias se"<<lhsp<<" ("<<lhsp->nodep()->typeName()
<<") <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
}
UINFO(9," iiasa: Insert alias se"<<lhsp<<" <- se"<<srcp<<" "<<srcp->nodep()<<endl);
// srcp should be an interface reference pointing to the interface we want to import
lhsp->importFromIface(symsp(), srcp);
//m_scopeAliasMap[samn].clear(); // Done with it, but put into debug file
}
m_scopeAliasMap.clear();
}
private:
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
@@ -1105,7 +1120,7 @@ class LinkDotScopeVisitor : public AstNVisitor {
}
// Interface reference; need to put whole thing into symtable, but can't clone it now
// as we may have a later alias for it.
m_statep->insertScopeAlias(varSymp, cellSymp);
m_statep->insertScopeAlias(LinkDotState::SAMN_IFTOP, varSymp, cellSymp);
}
}
}
@@ -1151,7 +1166,7 @@ class LinkDotScopeVisitor : public AstNVisitor {
}
// Remember the alias - can't do it yet because we may have additional symbols to be added,
// or maybe an alias of an alias
m_statep->insertScopeAlias(lhsSymp, rhsSymp);
m_statep->insertScopeAlias(LinkDotState::SAMN_IFTOP, lhsSymp, rhsSymp);
// We have stored the link, we don't need these any more
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
@@ -1212,7 +1227,8 @@ class LinkDotIfaceVisitor : public AstNVisitor {
} else if (AstNodeFTask* ftaskp = symp->nodep()->castNodeFTask()) {
// Make symbol under modport that points at the _interface_'s var, not the modport.
nodep->ftaskp(ftaskp);
m_statep->insertSym(m_curSymp, nodep->name(), ftaskp, NULL/*package*/);
VSymEnt* subSymp = m_statep->insertSym(m_curSymp, nodep->name(), ftaskp, NULL/*package*/);
m_statep->insertScopeAlias(LinkDotState::SAMN_MODPORT, subSymp, symp);
} else {
nodep->v3error("Modport item is not a function/task: "<<nodep->prettyName());
}
@@ -1446,9 +1462,9 @@ private:
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
return;
}
nodep->v3error(LinkDotState::ucfirst(whatp)<<" not found: "<<nodep->prettyName());
nodep->v3error(ucfirst(whatp)<<" not found: "<<nodep->prettyName());
} else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
nodep->v3error(LinkDotState::ucfirst(whatp)<<" is not an in/out/inout/param/interface: "<<nodep->prettyName());
nodep->v3error(ucfirst(whatp)<<" is not an in/out/inout/param/interface: "<<nodep->prettyName());
} else {
nodep->modVarp(refp);
if (refp->user5p() && refp->user5p()->castNode()!=nodep) {
+12
View File
@@ -107,6 +107,18 @@ private:
nodep->iterateChildren(*this);
}
}
virtual void visit(AstMemberDType* nodep, AstNUser*) {
if (!nodep->user1()) {
rename(nodep, false);
nodep->iterateChildren(*this);
}
}
virtual void visit(AstMemberSel* nodep, AstNUser*) {
if (!nodep->user1()) {
rename(nodep, false);
nodep->iterateChildren(*this);
}
}
virtual void visit(AstScope* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) {
if (nodep->aboveScopep()) nodep->aboveScopep()->iterate(*this);
+55 -15
View File
@@ -47,6 +47,7 @@ V3Number::V3Number(VerilogString, FileLine* fileline, const string& str) {
}
}
}
opCleanThis();
}
V3Number::V3Number (FileLine* fileline, const char* sourcep) {
@@ -252,6 +253,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
setBit(obit, bitIs(obit-1));
obit++;
}
opCleanThis();
//printf("Dump \"%s\" CP \"%s\" B '%c' %d W %d\n", sourcep, value_startp, base, width(), m_value[0]);
}
@@ -276,11 +278,13 @@ V3Number& V3Number::setQuad(vluint64_t value) {
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
m_value[0] = value & VL_ULL(0xffffffff);
m_value[1] = (value>>VL_ULL(32)) & VL_ULL(0xffffffff);
opCleanThis();
return *this;
}
V3Number& V3Number::setLong(uint32_t value) {
for (int i=0; i<words(); i++) m_value[i]=m_valueX[i] = 0;
m_value[0] = value;
opCleanThis();
return *this;
}
V3Number& V3Number::setLongS(vlsint32_t value) {
@@ -288,6 +292,7 @@ V3Number& V3Number::setLongS(vlsint32_t value) {
union { uint32_t u; vlsint32_t s; } u;
u.s = value;
m_value[0] = u.u;
opCleanThis();
return *this;
}
V3Number& V3Number::setDouble(double value) {
@@ -314,14 +319,17 @@ V3Number& V3Number::setAllBits0() {
}
V3Number& V3Number::setAllBits1() {
for (int i=0; i<words(); i++) { m_value[i]= ~0; m_valueX[i] = 0; }
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsX() {
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsZ() {
for (int i=0; i<words(); i++) { m_value[i]=0; m_valueX[i] = ~0; }
opCleanThis();
return *this;
}
V3Number& V3Number::setMask(int nbits) {
@@ -341,6 +349,8 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
if (width()!=64) out<<"%E-bad-width-double";
else out<<toDouble();
return out.str();
} else {
if ((m_value[words()-1] | m_valueX[words()-1]) & ~hiWordMask()) out<<"%E-hidden-bits";
}
if (prefixed) {
if (sized()) {
@@ -751,6 +761,7 @@ V3Number& V3Number::opCountOnes (const V3Number& lhs) {
if (lhs.isFourState()) return setAllBitsX();
setZero();
m_value[0] = lhs.countOnes();
opCleanThis();
return *this;
}
V3Number& V3Number::opIsUnknown (const V3Number& lhs) {
@@ -891,6 +902,23 @@ V3Number& V3Number::opRepl (const V3Number& lhs, uint32_t rhsval) { // rhs is #
return *this;
}
V3Number& V3Number::opStreamL (const V3Number& lhs, const V3Number& rhs) {
setZero();
// See also error in V3Width
if (!lhs.sized()) {
m_fileline->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in streams.");
}
// Slice size should never exceed the lhs width
int ssize=min(rhs.toUInt(), (unsigned)lhs.width());
for (int istart=0; istart<lhs.width(); istart+=ssize) {
int ostart=max(0, lhs.width()-ssize-istart);
for (int bit=0; bit<ssize && bit<lhs.width()-istart; bit++) {
setBit(ostart+bit, lhs.bitIs(istart+bit));
}
}
return *this;
}
V3Number& V3Number::opLogAnd (const V3Number& lhs, const V3Number& rhs) {
// i op j, 1 bit return, max(L(lhs),L(rhs)) calculation
char loutc = 0;
@@ -1291,6 +1319,7 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
}
UINFO(9, " opmoddiv-1w "<<lhs<<" "<<rhs<<" q="<<*this<<" rem=0x"<<hex<<k<<dec<<endl);
if (is_modulus) { setZero(); m_value[0] = k; }
opCleanThis();
return *this;
}
@@ -1373,21 +1402,33 @@ V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool
m_value[i] = (un[i] >> s) | (shift_mask & (un[i+1] << (32-s)));
}
for (int i=vw; i<words; i++) m_value[i] = 0;
opCleanThis();
UINFO(9, " opmoddiv-mod "<<lhs<<" "<<rhs<<" now="<<*this<<endl);
return *this;
} else { // division
opCleanThis();
UINFO(9, " opmoddiv-div "<<lhs<<" "<<rhs<<" now="<<*this<<endl);
return *this;
}
}
V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign, bool rsign) {
// L(i) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (lhs.isEqZero()) return setZero();
if (rhs.isEqZero()) return setQuad(1); // Overrides lhs 0 -> return 0
// We may want to special case when the lhs is 2, so we can get larger outputs
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** math not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** math not implemented yet: "<<*this);
if (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large >64bit ** power operator not implemented yet: "<<*this);
if (rsign && rhs.isNegative()) {
if (lhs.isEqZero()) return setAllBitsX();
else if (lhs.isEqOne()) return setQuad(1);
else if (lsign && lhs.isEqAllOnes()) {
if (rhs.bitIs1(0)) return setAllBits1(); // -1^odd=-1
else return setQuad(1); // -1^even=1
}
return setZero();
}
if (lhs.isEqZero()) return setZero();
setZero();
m_value[0] = 1;
V3Number power (lhs.m_fileline, width()); power.opAssign(lhs);
@@ -1404,14 +1445,14 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs) {
}
return *this;
}
V3Number& V3Number::opPowS (const V3Number& lhs, const V3Number& rhs) {
// Signed multiply
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (lhs.isEqZero() && rhs.isNegative()) return setAllBitsX(); // Per spec
if (!lhs.isNegative() && !rhs.isNegative()) return opPow(lhs,rhs);
//if (lhs.isNegative() || rhs.isNonIntegral()) return setAllBitsX(); // Illegal pow() call
m_fileline->v3fatalSrc("Unsupported: Power (**) operator with negative numbers: "<<*this);
return setAllBitsX();
V3Number& V3Number::opPowSU (const V3Number& lhs, const V3Number& rhs) {
return opPow(lhs,rhs,true,false);
}
V3Number& V3Number::opPowSS (const V3Number& lhs, const V3Number& rhs) {
return opPow(lhs,rhs,true,true);
}
V3Number& V3Number::opPowUS (const V3Number& lhs, const V3Number& rhs) {
return opPow(lhs,rhs,false,true);
}
V3Number& V3Number::opBufIf1 (const V3Number& ens, const V3Number& if1s) {
@@ -1447,9 +1488,8 @@ V3Number& V3Number::opClean (const V3Number& lhs, uint32_t bits) {
void V3Number::opCleanThis() {
// Clean in place number
if (uint32_t okbits = (width() & 31)) {
m_value[words()-1] &= ((1UL<<okbits)-1);
}
m_value[words()-1] &= hiWordMask();
m_valueX[words()-1] &= hiWordMask();
}
V3Number& V3Number::opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
+8 -6
View File
@@ -61,10 +61,8 @@ public:
private:
char bitIs (int bit) const {
if (bit>=m_width) {
bit = m_width-1;
// We never sign extend
return ( "00zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
return '0';
}
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
@@ -103,6 +101,7 @@ private:
}
int words() const { return ((width()+31)/32); }
uint32_t hiWordMask() const { return VL_MASK_I(width()); }
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
@@ -111,7 +110,7 @@ public:
// CONSTRUCTORS
V3Number(FileLine* fileline) { init(fileline, 1); }
V3Number(FileLine* fileline, int width) { init(fileline, width); } // 0=unsized
V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; }
V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; opCleanThis(); }
V3Number(FileLine* fileline, const char* source); // Create from a verilog 32'hxxxx number.
V3Number(VerilogString, FileLine* fileline, const string& vvalue);
@@ -213,6 +212,7 @@ public:
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl (const V3Number& lhs, uint32_t rhs);
V3Number& opStreamL (const V3Number& lhs, const V3Number& rhs);
V3Number& opSel (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opSel (const V3Number& lhs, uint32_t rhs, uint32_t ths);
V3Number& opCond (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
@@ -238,8 +238,10 @@ public:
V3Number& opDivS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opModDiv (const V3Number& lhs, const V3Number& rhs);
V3Number& opModDivS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opPow (const V3Number& lhs, const V3Number& rhs);
V3Number& opPowS (const V3Number& lhs, const V3Number& rhs); // Signed
V3Number& opPow (const V3Number& lhs, const V3Number& rhs, bool lsign=false, bool rsign=false);
V3Number& opPowSU (const V3Number& lhs, const V3Number& rhs); // Signed lhs, unsigned rhs
V3Number& opPowSS (const V3Number& lhs, const V3Number& rhs); // Signed lhs, signed rhs
V3Number& opPowUS (const V3Number& lhs, const V3Number& rhs); // Unsigned lhs, signed rhs
V3Number& opAnd (const V3Number& lhs, const V3Number& rhs);
V3Number& opChangeXor(const V3Number& lhs, const V3Number& rhs);
V3Number& opXor (const V3Number& lhs, const V3Number& rhs);
+4 -5
View File
@@ -591,9 +591,6 @@ string V3Options::getenvVERILATOR_ROOT() {
string V3Options::version() {
string ver = DTVERSION;
ver += " rev "+cvtToStr(DTVERSION_rev);
#ifdef NEW_ORDERING
ver += " (ord)";
#endif
return ver;
}
@@ -715,7 +712,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strcmp (sw, "-E") ) { m_preprocOnly = true; }
else if ( onoff (sw, "-MMD", flag/*ref*/) ) { m_makeDepend = flag; }
else if ( onoff (sw, "-MP", flag/*ref*/) ) { m_makePhony = flag; }
else if ( onoff (sw, "-assert", flag/*ref*/) ) { m_assert = flag; m_psl = flag; }
else if ( onoff (sw, "-assert", flag/*ref*/) ) { m_assert = flag; }
else if ( onoff (sw, "-autoflush", flag/*ref*/) ) { m_autoflush = flag; }
else if ( onoff (sw, "-bbox-sys", flag/*ref*/) ) { m_bboxSys = flag; }
else if ( onoff (sw, "-bbox-unsup", flag/*ref*/) ) { m_bboxUnsup = flag; }
@@ -745,7 +742,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( onoff (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
else if ( !strcmp (sw, "-private") ) { m_public = false; }
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, "-psl-deprecated", flag/*ref*/) ) { m_psl = flag; } // Undocumented
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; }
@@ -756,6 +753,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
else if ( !strcmp (sw, "-sv") ) { m_defaultLanguage = V3LangCode::L1800_2005; }
else if ( onoff (sw, "-trace", flag/*ref*/) ) { m_trace = flag; }
else if ( onoff (sw, "-trace-dups", flag/*ref*/) ) { m_traceDups = flag; }
else if ( onoff (sw, "-trace-params", flag/*ref*/) ) { m_traceParams = flag; }
else if ( onoff (sw, "-trace-structs", flag/*ref*/) ) { m_traceStructs = flag; }
else if ( onoff (sw, "-trace-underscore", flag/*ref*/) ) { m_traceUnderscore = flag; }
else if ( onoff (sw, "-underline-zero", flag/*ref*/) ) { m_underlineZero = flag; } // Undocumented, old Verilator-2
@@ -1223,6 +1221,7 @@ V3Options::V3Options() {
m_systemPerl = false;
m_trace = false;
m_traceDups = false;
m_traceParams = true;
m_traceStructs = false;
m_traceUnderscore = false;
m_underlineZero = false;
+2
View File
@@ -90,6 +90,7 @@ class V3Options {
bool m_stats; // main switch: --stats
bool m_trace; // main switch: --trace
bool m_traceDups; // main switch: --trace-dups
bool m_traceParams; // main switch: --trace-params
bool m_traceStructs; // main switch: --trace-structs
bool m_traceUnderscore;// main switch: --trace-underscore
bool m_underlineZero;// main switch: --underline-zero; undocumented old Verilator 2
@@ -215,6 +216,7 @@ class V3Options {
bool exe() const { return m_exe; }
bool trace() const { return m_trace; }
bool traceDups() const { return m_traceDups; }
bool traceParams() const { return m_traceParams; }
bool traceStructs() const { return m_traceStructs; }
bool traceUnderscore() const { return m_traceUnderscore; }
bool orderClockDly() const { return m_orderClockDly; }
+63 -431
View File
@@ -63,16 +63,6 @@
// the generated signal to become a primary input again.
//
//
#ifdef NEW_ORDERING
// Determine nodes that form loops within combo logic
// (Strongly connected ignoring assign post/pre's)
// Make a subgraph for each loop of combo logic
// Break circular logic in each subgraph
//
// Determine nodes that form loops within a single eval call
// Make a subgraph for each loop of sequential logic
// Break circular logic in each subgraph
#endif
//
// Rank the graph starting at INPUTS (see V3Graph)
//
@@ -349,7 +339,8 @@ private:
varscp->user1p(newup);
}
OrderUser* up = (OrderUser*)(varscp->user1p());
return up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp);
OrderVarVertex* varVxp = up->newVarUserVertex(&m_graph, m_scopep, varscp, type, createdp);
return varVxp;
}
V3GraphEdge* findEndEdge(V3GraphVertex* vertexp, AstNode* errnodep, OrderLoopEndVertex*& evertexpr) {
@@ -366,14 +357,6 @@ private:
}
void process();
#ifdef NEW_ORDERING
void processLoops(string stepName, V3EdgeFuncP edgeFuncp);
void processInsLoop();
void processInsLoopEdge(V3GraphEdge* edgep);
void processInsLoopNewEdge(V3GraphEdge* oldEdgep, V3GraphVertex* newFromp, V3GraphVertex* newTop);
OrderVarVertex* processInsLoopNewVar(OrderVarVertex* oldVertexp, bool& createdr);
void processBrokeLoop();
#endif
void processCircular();
typedef deque<OrderEitherVertex*> VertexVec;
void processInputs();
@@ -414,41 +397,56 @@ private:
void nodeMarkCircular(OrderVarVertex* vertexp, OrderEdge* edgep) {
AstVarScope* nodep = vertexp->varScp();
nodep->circular(true);
++m_statCut[vertexp->type()];
if (edgep) ++m_statCut[edgep->type()];
if (vertexp->isClock()) {
// Seems obvious; no warning yet
//nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<<nodep->prettyName());
} else if (nodep->varp()->isSigPublic()) {
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
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);
}
} else {
// We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more
// First v3warn not inside warnIsOff so we can see the suppressions with --debug
nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
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");
OrderLogicVertex* fromLVtxp = NULL;
OrderLogicVertex* toLVtxp = NULL;
if (edgep) {
fromLVtxp = dynamic_cast<OrderLogicVertex*>(edgep->fromp());
toLVtxp = dynamic_cast<OrderLogicVertex*>(edgep->top());
}
//
if ((fromLVtxp && fromLVtxp->nodep()->castInitial())
|| (toLVtxp && toLVtxp->nodep()->castInitial())) {
// IEEE does not specify ordering between initial blocks, so we can do whatever we want
// We especially do not want to evaluate multiple times, so do not mark the edge circular
}
else {
nodep->circular(true);
++m_statCut[vertexp->type()];
if (edgep) ++m_statCut[edgep->type()];
//
if (vertexp->isClock()) {
// Seems obvious; no warning yet
//nodep->v3warn(GENCLK,"Signal unoptimizable: Generated clock: "<<nodep->prettyName());
} else if (nodep->varp()->isSigPublic()) {
nodep->v3warn(UNOPT,"Signal unoptimizable: Feedback to public clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
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);
}
} else {
// We don't use UNOPT, as there are lots of V2 places where it was needed, that aren't any more
// First v3warn not inside warnIsOff so we can see the suppressions with --debug
nodep->v3warn(UNOPTFLAT,"Signal unoptimizable: Feedback to clock or circular logic: "<<nodep->prettyName());
if (!nodep->fileline()->warnIsOff(V3ErrorCode::UNOPTFLAT)) {
nodep->fileline()->modifyWarnOff(V3ErrorCode::UNOPTFLAT, true); // Complain just once
// Give the user an example.
bool tempWeight = (edgep && edgep->weight()==0);
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");
}
}
}
}
@@ -573,12 +571,7 @@ private:
UINFO(5," DeleteDomain = "<<m_deleteDomainp<<endl);
// Base vertices
m_activeSenVxp = NULL;
#ifdef NEW_ORDERING
m_inputsVxp = new OrderInputsVertex(&m_graph, m_comboDomainp);
m_settleVxp = new OrderSettleVertex(&m_graph, m_settleDomainp);
#else
m_inputsVxp = new OrderInputsVertex(&m_graph, NULL);
#endif
//
nodep->iterateChildren(*this);
// Done topscope, erase extra user information
@@ -603,7 +596,6 @@ private:
}
virtual void visit(AstActive* nodep, AstNUser*) {
// Create required activation blocks and add to module
if (nodep->hasInitial()) return; // Ignore initials
UINFO(4," ACTIVE "<<nodep<<endl);
m_activep = nodep;
m_activeSenVxp = NULL;
@@ -666,32 +658,7 @@ private:
|| m_inPost
) {
// Combo logic
if (
#ifdef NEW_ORDERING
m_activep && m_activep->hasSettle()
#else
0
#endif
) {
// Inside settlement; we use special variable names to prevent
// having extra logic to break arcs within
#ifdef NEW_ORDERING
if (gen) {
// Add edge logic_vertex->logic_generated_var
bool created = false;
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_SETL, &created);
new OrderComboCutEdge(&m_graph, m_logicVxp, varVxp);
if (created) new OrderEdge(&m_graph, m_settleVxp, varVxp, WEIGHT_INPUT);
}
if (con) {
// Add edge logic_consumed_var->logic_vertex
bool created = false;
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_SETL, &created);
new OrderEdge(&m_graph, varVxp, m_logicVxp, WEIGHT_MEDIUM);
if (created) new OrderEdge(&m_graph, m_settleVxp, varVxp, WEIGHT_INPUT);
}
#endif // NEW_ORDERING
} else { // not settle and (combo or inPost)
{ // not settle and (combo or inPost)
if (gen) {
// Add edge logic_vertex->logic_generated_var
OrderVarVertex* varVxp = newVarUserVertex(varscp, WV_STD);
@@ -806,6 +773,11 @@ private:
virtual void visit(AstCoverToggle* nodep, AstNUser*) {
iterateNewStmt(nodep);
}
virtual void visit(AstInitial* nodep, AstNUser*) {
// We use initials to setup parameters and static consts's which may be referenced
// in user initial blocks. So use ordering to sort them all out.
iterateNewStmt(nodep);
}
virtual void visit(AstCFunc*, AstNUser*) {
// Ignore for now
// We should detect what variables are set in the function, and make
@@ -858,212 +830,6 @@ public:
}
};
//######################################################################
// Pre-Loop elimination
#ifdef NEW_ORDERING
void OrderVisitor::processInsLoop() {
// Input is graph with color() reflecting the sub-graphs we need
// to loop remove. Take all the I/O from each subgraph and route
// through a new begin/end vertex
// Note we DON'T only do certain edges; we want all edges to be preserved,
// we'll select which are important later on.
uint32_t maxcolor = 0;
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
if (maxcolor <= vertexp->color()) maxcolor = vertexp->color() + 1;
if (OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp)) {
vvertexp->pilNewVertexp(NULL); // Clear user-ish information before loop
}
}
m_pmlLoopEndps.clear();
m_pmlLoopEndps.reserve(maxcolor);
m_pmlLoopEndps.assign(maxcolor,NULL);
m_graph.userClearVertices(); // Vertex::user() // true if added as begin/end
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
if (uint32_t loopColor = vertexp->color()) {
OrderEitherVertex* evertexp = dynamic_cast<OrderEitherVertex*>(vertexp);
if (!evertexp) v3fatalSrc("Non either vertex found");
if (!vertexp->user()) {
UINFO(8," pil:nowInLoop lp="<<m_loopIdMax<<" waslp="
<<evertexp->inLoop()<<" "<<evertexp<<endl);
if (!m_pmlLoopEndps[loopColor]) {
AstUntilStable* untilp = new AstUntilStable(m_topScopep->fileline(), NULL, NULL);
m_topScopep->addStmtsp(untilp);
OrderLoopBeginVertex* beginp
= new OrderLoopBeginVertex(&m_graph, m_scopetopp,
evertexp->domainp(),
untilp,
m_loopIdMax, loopColor);
m_loopIdMax = (OrderLoopId)(m_loopIdMax+1);
UASSERT(LOOPID_MAX>m_loopIdMax, "loopid overflow "<<m_loopIdMax<<" "<<LOOPID_MAX);
OrderLoopEndVertex* endp = new OrderLoopEndVertex(&m_graph, beginp);
new OrderEdge(&m_graph, beginp, endp, WEIGHT_LOOPBE);
m_pmlLoopEndps[loopColor] = endp;
// Color edges to belong to subgraph
beginp->color(loopColor);
endp->color(loopColor);
beginp->user(1); // Added; don't iterate on it
endp->user(1); // Added; don't iterate on it
}
if (evertexp->inLoop()) {
// Adding node to loop, but already in loop...
// Ok if the nodes were a combo loop and now become a sequent loop,
// The combo loop will be "under" the sequent loop, so keep the combo #.
//UINFO(9, "Adding node to loop, but already in loop: "<<evertexp->name()<<endl);
} else {
// Make all nodes point from/to the begin/end nodes
OrderLoopEndVertex* endp = m_pmlLoopEndps[loopColor];
OrderLoopBeginVertex* beginp = endp->beginVertexp();
new OrderEdge(&m_graph, beginp, vertexp, WEIGHT_LOOPBE);
new OrderEdge(&m_graph, vertexp, endp, WEIGHT_LOOPBE);
evertexp->inLoop(beginp->loopId());
}
}
}
}
m_graph.userClearEdges(); // Edge::user() // true if we added it
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
if (vertexp->color()) {
for (V3GraphEdge* nextp,* edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp(); // Func may edit the list
if (edgep->weight()) {
processInsLoopEdge(edgep);
} else { // No purpose to this edge any longer
edgep->unlinkDelete(); edgep=NULL; // remove old edge
}
}
for (V3GraphEdge* nextp,* edgep = vertexp->inBeginp(); edgep; edgep = nextp) {
nextp = edgep->inNextp(); // Func may edit the list
if (edgep->weight()) {
processInsLoopEdge(edgep);
} else { // No purpose to this edge any longer
edgep->unlinkDelete(); edgep=NULL; // remove old edge
}
}
}
}
// Done with space
m_pmlLoopEndps.clear();
}
void OrderVisitor::processInsLoopNewEdge(V3GraphEdge* oldEdgep, V3GraphVertex* newFromp, V3GraphVertex* newTop) {
// Create new edge based on the old edge's parameters
const OrderEdge* oedgep = dynamic_cast<const OrderEdge*>(oldEdgep);
V3GraphEdge* newEdgep = oedgep->clone(&m_graph, newFromp, newTop);
newEdgep->user(1); // New edge doesn't need to be changed
}
OrderVarVertex* OrderVisitor::processInsLoopNewVar(OrderVarVertex* oldVertexp, bool& createdr) {
// Create new VarVertex from given template
if (oldVertexp->pilNewVertexp()) {
createdr = false;
} else {
OrderVarVertex* newVertexp = oldVertexp->clone(&m_graph);
oldVertexp->pilNewVertexp(newVertexp);
createdr = true;
}
return oldVertexp->pilNewVertexp();
}
void OrderVisitor::processInsLoopEdge(V3GraphEdge* oldEdgep) {
if (!oldEdgep->user()) { // if not processed
oldEdgep->user(1); // mark as processed
if (oldEdgep->fromp()->color() == oldEdgep->top()->color()) {
return; // Doesn't cross subgraphs
} else {
V3GraphVertex* newFromp = oldEdgep->fromp();
V3GraphVertex* newTop = oldEdgep->top();
//UINFO(6, " pile: "<<newFromp<<" -> "<<newTop<<endl);
if (uint32_t fromId = oldEdgep->fromp()->color()) {
// Change to come from end block
OrderLoopEndVertex* endp = m_pmlLoopEndps[fromId];
newFromp = endp;
// If it goes from(to) a cutable VarVertex inside the Begin/End block,
// we can't lose the variable, as we might need to cut that variable out
// in the next pass of processLoops, and processBrokeLoops needs the var pointer.
// We'll make another VarVertex (dup of the one "inside" the loop)
// and point to it.
if (oldEdgep->cutable()) {
if (OrderVarVertex* vvFromp = dynamic_cast<OrderVarVertex*>(oldEdgep->fromp())) {
// end => newvarvtx -> {whatever}
bool created;
newFromp = processInsLoopNewVar(vvFromp, created/*ref*/);
if (created) processInsLoopNewEdge(oldEdgep, endp, newFromp);
}
}
}
if (uint32_t toId = oldEdgep->top()->color()) {
// Change to go to begin block
OrderLoopEndVertex* endp = m_pmlLoopEndps[toId];
OrderLoopBeginVertex* beginp = endp->beginVertexp();
newTop = beginp;
// Ditto above
if (oldEdgep->cutable()) {
if (OrderVarVertex* vvTop = dynamic_cast<OrderVarVertex*>(oldEdgep->top())) {
// oldfrom -> newvarvtx => begin
bool created;
newTop = processInsLoopNewVar(vvTop, created/*ref*/);
if (created) processInsLoopNewEdge(oldEdgep, newTop, beginp);
}
}
}
// New edge with appropriate to/from
processInsLoopNewEdge(oldEdgep, newFromp, newTop);
oldEdgep->unlinkDelete(); oldEdgep=NULL; // remove old edge
}
}
}
#endif // NEW_ORDERING
//######################################################################
// Pre-Loop elimination
#ifdef NEW_ORDERING
void OrderVisitor::processBrokeLoop() {
// Find those loops that were broken
for (V3GraphVertex* vertexp = m_graph.verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
// Above processInsLoopEdge makes sure there's always a OrderVarVertex on
// boundaries to/from LoopBegin/EndVertex'es
if (OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp)) {
// Any cut edges?
bool anyCut = false;
for (V3GraphEdge* nextp,* edgep = vertexp->inBeginp(); edgep; edgep = nextp) {
nextp = edgep->inNextp(); // We may edit the list
if (edgep->weight()==0) { // was cut
anyCut = true;
edgep->unlinkDelete(); edgep=NULL; // remove old edge
}
}
for (V3GraphEdge* nextp,* edgep = vertexp->outBeginp(); edgep; edgep = nextp) {
nextp = edgep->outNextp(); // We may edit the list
if (edgep->weight()==0) { // was cut
anyCut = true;
edgep->unlinkDelete(); edgep=NULL; // remove old edge
}
}
if (anyCut) {
UINFO(6," pbl: Cut "<<vertexp->name()<<endl);
nodeMarkCircular(vvertexp, NULL);
OrderLoopEndVertex* endp = NULL; // Set below in findEndEdge
V3GraphEdge* endedgep = findEndEdge(vertexp, vvertexp->varScp(), endp/*ref*/);
// Add edge to graphically indicate change detect required
endedgep->unlinkDelete(); endedgep=NULL; // remove old edge
new OrderChangeDetEdge(&m_graph, vvertexp, endp);
// Add variable dependency to until loop
AstUntilStable* untilp = endp->beginVertexp()->untilp();
untilp->addStablesp(new AstVarRef(vvertexp->varScp()->fileline(), vvertexp->varScp(), false));
}
}
}
}
#endif // NEW_ORDERING
//######################################################################
// Clock propagation
@@ -1146,7 +912,6 @@ void OrderVisitor::processInputsOutIterate(OrderEitherVertex* vertexp, VertexVec
//######################################################################
// Circular detection
#ifndef NEW_ORDERING // *NOT* new ordering
void OrderVisitor::processCircular() {
// Take broken edges and add circular flags
// The change detect code will use this to force changedets
@@ -1193,7 +958,6 @@ void OrderVisitor::processCircular() {
}
}
}
#endif
void OrderVisitor::processSensitive() {
// Sc sensitives are required on all inputs that go to a combo
@@ -1238,11 +1002,9 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
OrderVarVertex* vvertexp = dynamic_cast<OrderVarVertex*>(vertexp);
AstSenTree* domainp = NULL;
UASSERT(m_comboDomainp, "not preset");
#ifndef NEW_ORDERING // New ordering set the input node as combo, so this happens automatically
if (vvertexp && vvertexp->varScp()->varp()->isInput()) {
domainp = m_comboDomainp;
}
#endif
if (vvertexp && vvertexp->varScp()->isCircular()) {
domainp = m_comboDomainp;
}
@@ -1250,13 +1012,12 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
for (V3GraphEdge* edgep = vertexp->inBeginp(); edgep; edgep = edgep->inNextp()) {
OrderEitherVertex* fromVertexp = (OrderEitherVertex*)edgep->fromp();
if (edgep->weight()
#ifndef NEW_ORDERING
&& fromVertexp->domainMatters()
#endif
) {
UINFO(9," from d="<<(void*)fromVertexp->domainp()<<" "<<fromVertexp<<endl);
if (!domainp // First input to this vertex
|| domainp->hasSettle()) { // or, we can ignore being in the settle domain
|| domainp->hasSettle() // or, we can ignore being in the settle domain
|| domainp->hasInitial()) {
domainp = fromVertexp->domainp();
}
else if (domainp->hasCombo()) {
@@ -1266,7 +1027,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
// Any combo input means this vertex must remain combo
domainp = m_comboDomainp;
}
else if (fromVertexp->domainp()->hasSettle()) {
else if (fromVertexp->domainp()->hasSettle()
|| fromVertexp->domainp()->hasInitial()) {
// Ignore that we have a constant (initial) input
}
else if (domainp != fromVertexp->domainp()) {
@@ -1323,7 +1085,7 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
void OrderVisitor::processEdgeReport() {
// Make report of all signal names and what clock edges they have
string filename = v3Global.debugFilename("order_edges.txt");
const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
const VL_UNIQUE_PTR<ofstream> logp (V3File::new_ofstream(filename));
if (logp->fail()) v3fatalSrc("Can't write "<<filename);
//Testing emitter: V3EmitV::verilogForTree(v3Global.rootp(), *logp);
@@ -1426,58 +1188,6 @@ void OrderVisitor::processMove() {
// New domain... another loop
UINFO(5," MoveIterate\n");
#ifdef NEW_ORDERING
OrderMoveDomScope* domScopep = NULL; // Currently active domain/scope
while (!m_pomReadyDomScope.empty()) {
// Always need to reamin in same loop construct
OrderLoopId curLoop = processMoveLoopCurrent();
// Scan list to find search candidates
OrderMoveDomScope* loopHuntp = NULL; // Found domscope under same loop
OrderMoveDomScope* domHuntp = NULL; // Found domscope under same domain
OrderMoveDomScope* scopeHuntp = NULL; // Found domscope under same scope
if (domScopep) { UINFO(6," MoveSearch: loop="<<curLoop<<" "<<*domScopep<<endl); }
else { UINFO(6," MoveSearch: loop="<<curLoop<<" NULL"<<endl); }
for (OrderMoveDomScope* huntp = m_pomReadyDomScope.begin(); huntp; huntp = huntp->readyDomScopeNextp()) {
if (huntp->inLoop() == curLoop) {
if (!loopHuntp) loopHuntp = huntp;
if (domScopep && huntp->domainp() == domScopep->domainp()) {
if (!domHuntp) domHuntp = huntp;
if (domScopep && huntp->scopep() == domScopep->scopep()) {
if (!scopeHuntp) scopeHuntp = huntp;
break; // Exact match; all we can hope for
}
}
}
}
// Recompute the next domScopep to process
if (scopeHuntp) {
domScopep = scopeHuntp;
UINFO(6," MoveIt: SameScope "<<*domScopep<<endl);
} else if (domHuntp) { // No exact scope matches, try only matching the domain
domScopep = domHuntp;
UINFO(6," MoveIt: SameDomain "<<*domScopep<<endl);
} else if (loopHuntp) { // No exact scope or domain matches, only match the loop
domScopep = loopHuntp;
UINFO(6," MoveIt: SameLoop "<<*domScopep<<endl);
} else { // else we're hopefully all done
if (curLoop != LOOPID_NOTLOOPED)
domScopep->domainp()->v3fatalSrc("Can't find more nodes like "<<*domScopep); // Should be at least a "end loop"
break;
}
// Work on all vertices in this loop/domain/scope
OrderMoveVertex* topVertexp = domScopep->readyVertices().begin();
UASSERT(topVertexp, "domScope on ready list without any nodes ready under it");
m_pomNewFuncp = NULL;
while (OrderMoveVertex* vertexp = domScopep->readyVertices().begin()) {
processMoveOne(vertexp, domScopep, 1);
if (curLoop != processMoveLoopCurrent()) break; // Hit a LoopBegin/end, change loop
}
}
if (!m_pomWaiting.empty()) {
OrderMoveVertex* vertexp = m_pomWaiting.begin();
vertexp->logicp()->nodep()->v3fatalSrc("Didn't converge; nodes waiting, none ready, perhaps some input activations lost: "<<vertexp<<endl);
}
#else
while (!m_pomReadyDomScope.empty()) {
// Start with top node on ready list's domain & scope
OrderMoveDomScope* domScopep = m_pomReadyDomScope.begin();
@@ -1504,7 +1214,6 @@ void OrderVisitor::processMove() {
}
}
UASSERT (m_pomWaiting.empty(), "Didn't converge; nodes waiting, none ready, perhaps some input activations lost.");
#endif
// Cleanup memory
processMoveClear();
}
@@ -1578,36 +1287,7 @@ void OrderVisitor::processMoveOne(OrderMoveVertex* vertexp, OrderMoveDomScope* d
AstNode* nodep = lvertexp->nodep();
AstNodeModule* modp = scopep->user1p()->castNode()->castNodeModule(); UASSERT(modp,"NULL"); // Stashed by visitor func
if (nodep->castUntilStable()) {
#ifdef NEW_ORDERING
// Beginning of loop.
if (OrderLoopBeginVertex* beginp = dynamic_cast<OrderLoopBeginVertex*>(lvertexp)) {
m_pomNewFuncp = NULL; // Close out any old function
// Create new active record
string name = cfuncName(modp, domainp, scopep, nodep);
AstActive* callunderp = new AstActive(nodep->fileline(), name, domainp);
if (domainp == m_deleteDomainp) {
UINFO(6," Delete loop "<<beginp<<endl);
pushDeletep(callunderp);
} else {
processMoveLoopStmt(callunderp);
}
// Put loop under the activate
nodep->unlinkFrBack();
callunderp->addStmtsp(nodep);
// Remember we're in a loop
processMoveLoopPush(beginp);
}
else if (OrderLoopEndVertex* endp = dynamic_cast<OrderLoopEndVertex*>(lvertexp)) {
// Nodep is identical to OrderLoopBeginVertex's, so we don't move it
m_pomNewFuncp = NULL; // Close out any old function
processMoveLoopPop(endp->beginVertexp());
}
else {
nodep->v3fatalSrc("AstUntilStable node isn't under an OrderLoop{End}Vertex.\n");
}
#else
nodep->v3fatalSrc("Not implemented");
#endif
}
else if (nodep->castSenTree()) {
// Just ignore sensitivities, we'll deal with them when we move statements that need them
@@ -1708,55 +1388,10 @@ inline void OrderMoveDomScope::movedVertex(OrderVisitor* ovp, OrderMoveVertex* v
//######################################################################
// Top processing
#ifdef NEW_ORDERING
void OrderVisitor::processLoops(string stepName, V3EdgeFuncP edgeFuncp) {
UINFO(2," "<<stepName<<" Loop Detect...\n");
m_graph.stronglyConnected(edgeFuncp);
m_graph.dumpDotFilePrefixed((string)"orderg_"+stepName+"_strong", true);
UINFO(2," "<<stepName<<" Insert Loop Begin/Ends...\n");
processInsLoop();
if (debug()>=4) m_graph.dumpDotFilePrefixed((string)"orderg_"+stepName+"_loops", true);
// Remove loops from the graph
UINFO(2," "<<stepName<<" Acyclic...\n");
m_graph.acyclic(edgeFuncp);
if (debug()) m_graph.dumpDotFilePrefixed((string)"orderg_"+stepName+"_acyc", true);
// For any broken edges, add to change detect and remove edge
UINFO(2," "<<stepName<<" ProcessBrokeLoop...\n");
processBrokeLoop();
if (debug()>=4) m_graph.dumpDotFilePrefixed((string)"orderg_"+stepName+"_broke", true);
m_graph.makeEdgesNonCutable(edgeFuncp);
m_graph.dumpDotFilePrefixed((string)"orderg_"+stepName+"_done", true);
}
#endif
void OrderVisitor::process() {
// Dump data
m_graph.dumpDotFilePrefixed("orderg_pre");
#ifdef NEW_ORDERING
// Ignoring POST assignments and clocked statements, detect strongly connected components
// Split components into subgraphs
// Detect, loop begin/end, and acyc combo loops
UINFO(2," Combo loop elimination...\n");
processLoops("combo", &OrderEdge::followComboConnected);
// Detect, loop begin/end, and acyc post assigns
UINFO(2," Sequential loop elimination...\n");
processLoops("sequent", &OrderEdge::followSequentConnected);
// Detect and acyc any PRE assigns
// As breaking these does not cause any problems, we don't need to loop begin/end, etc.
UINFO(2," Pre Loop Detect & Acyc...\n");
m_graph.stronglyConnected(&V3GraphEdge::followAlwaysTrue);
if (debug()>=4) m_graph.dumpDotFilePrefixed("orderg_preasn_strong", true);
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_preasn_done", true);
#else
// 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
@@ -1764,7 +1399,6 @@ void OrderVisitor::process() {
UINFO(2," Acyclic & Order...\n");
m_graph.acyclic(&V3GraphEdge::followAlwaysTrue);
m_graph.dumpDotFilePrefixed("orderg_acyc");
#endif
// Assign ranks so we know what to follow
// Then, sort vertices and edges by that ordering
@@ -1777,10 +1411,8 @@ void OrderVisitor::process() {
UINFO(2," Process Clocks...\n");
processInputs(); // must be before processCircular
#ifndef NEW_ORDERING
UINFO(2," Process Circulars...\n");
processCircular(); // must be before processDomains
#endif
// Assign logic verticesto new domains
UINFO(2," Domains...\n");
+2 -1
View File
@@ -228,7 +228,8 @@ class OrderVarVertex : public OrderEitherVertex {
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) {}
, m_varScp(old.m_varScp), m_pilNewVertexp(old.m_pilNewVertexp), m_isClock(old.m_isClock)
, m_isDelayed(old.m_isDelayed) {}
public:
OrderVarVertex(V3Graph* graphp, AstScope* scopep, AstVarScope* varScp)
: OrderEitherVertex(graphp, scopep, NULL), m_varScp(varScp)
+9 -1
View File
@@ -230,8 +230,16 @@ private:
if (!nodep->user5SetOnce()) { // Process once
nodep->iterateChildren(*this);
if (nodep->isParam()) {
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
if (!nodep->valuep()) { nodep->v3fatalSrc("Parameter without initial value"); }
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
if (!nodep->valuep()->castConst()) { // Complex init, like an array
// Make a new INITIAL to set the value.
// This allows the normal array/struct handling code to properly initialize the parameter
nodep->addNext(new AstInitial(nodep->fileline(),
new AstAssign(nodep->fileline(),
new AstVarRef(nodep->fileline(), nodep, true),
nodep->valuep()->cloneTree(true))));
}
}
}
}
+36 -11
View File
@@ -46,10 +46,13 @@ 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;
// TYPES
typedef map<AstPackage*, AstScope*> PackageScopeMap;
typedef map<pair<AstVar*, AstScope*>, AstVarScope*> VarScopeMap;
typedef set<pair<AstVarRef*, AstScope*> > VarRefScopeSet;
// STATE, inside processing a single module
AstNodeModule* m_modp; // Current module
@@ -57,6 +60,10 @@ private:
// STATE, for passing down one level of hierarchy (may need save/restore)
AstCell* m_aboveCellp; // Cell that instantiates this module
AstScope* m_aboveScopep; // Scope that instantiates this scope
PackageScopeMap m_packageScopes; // Scopes for each package
VarScopeMap m_varScopes; // Varscopes created for each scope and var
VarRefScopeSet m_varRefScopes; // Varrefs-in-scopes needing fixup when donw
// METHODS
static int debug() {
@@ -65,6 +72,23 @@ private:
return level;
}
void cleanupVarRefs() {
for (VarRefScopeSet::iterator it = m_varRefScopes.begin();
it!=m_varRefScopes.end(); ++it) {
AstVarRef* nodep = it->first;
AstScope* scopep = it->second;
if (nodep->packagep()) {
PackageScopeMap::iterator it2 = m_packageScopes.find(nodep->packagep());
if (it2==m_packageScopes.end()) nodep->v3fatalSrc("Can't locate package scope");
scopep = it2->second;
}
VarScopeMap::iterator it3 = m_varScopes.find(make_pair(nodep->varp(), scopep));
if (it3==m_varScopes.end()) nodep->v3fatalSrc("Can't locate varref scope");
AstVarScope* varscp = it3->second;
nodep->varScopep(varscp);
}
}
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
AstNodeModule* modp = nodep->topModulep();
@@ -73,6 +97,7 @@ private:
m_aboveCellp = NULL;
m_aboveScopep = NULL;
modp->accept(*this);
cleanupVarRefs();
}
virtual void visit(AstNodeModule* nodep, AstNUser*) {
// Create required blocks and add to module
@@ -85,6 +110,7 @@ private:
m_scopep = new AstScope((m_aboveCellp?(AstNode*)m_aboveCellp:(AstNode*)nodep)->fileline(),
nodep, scopename, m_aboveScopep, m_aboveCellp);
if (nodep->castPackage()) m_packageScopes.insert(make_pair(nodep->castPackage(), m_scopep));
// Now for each child cell, iterate the module this cell points to
for (AstNode* cellnextp = nodep->stmtsp(); cellnextp; cellnextp=cellnextp->nextp()) {
@@ -211,12 +237,13 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
// Make new scope variable
if (m_modp->castPackage()
? !nodep->user3p() : !nodep->user1p()) {
// This is called cross-module by AstVar, so we cannot trust any m_ variables
if (!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);
if (!m_scopep) nodep->v3fatalSrc("No scope for var");
m_varScopes.insert(make_pair(make_pair(nodep, m_scopep), varscp));
m_scopep->addVarp(varscp);
}
}
@@ -227,12 +254,10 @@ private:
if (nodep->varp()->isIfaceRef()) {
nodep->varScopep(NULL);
} else {
nodep->varp()->accept(*this);
AstVarScope* varscp = nodep->packagep()
? (AstVarScope*)nodep->varp()->user3p()
: (AstVarScope*)nodep->varp()->user1p();
if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
nodep->varScopep(varscp);
// We may have not made the variable yet, and we can't make it now as
// the var's referenced package etc might not be created yet.
// So push to a list and post-correct
m_varRefScopes.insert(make_pair(nodep, m_scopep));
}
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
+41 -31
View File
@@ -70,7 +70,7 @@ class SliceCloneVisitor : public AstNVisitor {
// VISITORS
virtual void visit(AstArraySel* nodep, AstNUser*) {
if (!nodep->backp()->castArraySel()) {
// This is the top of an ArraySel, setup
// This is the top of an ArraySel, setup for iteration
m_refp = nodep->user1p()->castNode()->castVarRef();
m_vecIdx += 1;
if (m_vecIdx == (int)m_selBits.size()) {
@@ -78,6 +78,7 @@ class SliceCloneVisitor : public AstNVisitor {
AstVar* varp = m_refp->varp();
pair<uint32_t,uint32_t> arrDim = varp->dtypep()->dimensions(false);
uint32_t dimensions = arrDim.second;
// for 3-dimensions we want m_selBits[m_vecIdx]=[0,0,0]
for (uint32_t i = 0; i < dimensions; ++i) {
m_selBits[m_vecIdx].push_back(0);
}
@@ -165,19 +166,15 @@ class SliceCloneVisitor : public AstNVisitor {
nodep->addNextHere(lhsp);
nodep->unlinkFrBack()->deleteTree(); nodep = NULL;
}
virtual void visit(AstRedOr* nodep, AstNUser*) {
cloneUniop(nodep);
}
virtual void visit(AstRedAnd* nodep, AstNUser*) {
cloneUniop(nodep);
}
virtual void visit(AstRedXor* nodep, AstNUser*) {
cloneUniop(nodep);
}
virtual void visit(AstRedXnor* nodep, AstNUser*) {
cloneUniop(nodep);
}
@@ -188,8 +185,8 @@ class SliceCloneVisitor : public AstNVisitor {
}
public:
// CONSTUCTORS
SliceCloneVisitor(AstNode* assignp) {
assignp->accept(*this);
SliceCloneVisitor(AstNode* nodep) {
nodep->accept(*this);
}
virtual ~SliceCloneVisitor() {}
};
@@ -223,8 +220,8 @@ class SliceVisitor : public AstNVisitor {
return level;
}
// Find out how many explicit dimensions are in a given ArraySel.
unsigned explicitDimensions(AstArraySel* nodep) {
// Find out how many explicit dimensions are in a given ArraySel.
unsigned dim = 0;
AstNode* fromp = nodep;
AstArraySel* selp;
@@ -243,10 +240,23 @@ class SliceVisitor : public AstNVisitor {
return dim;
}
int countClones(AstArraySel* nodep) {
// Count how many clones we need to make from this ArraySel
int clones = 1;
AstNode* fromp = nodep;
AstArraySel* selp;
do {
selp = fromp->castArraySel();
fromp = (selp) ? selp->fromp() : NULL;
if (fromp && selp) clones *= selp->length();
} while (fromp && selp);
return clones;
}
AstArraySel* insertImplicit(AstNode* nodep, unsigned start, unsigned count) {
// Insert any implicit slices as explicit slices (ArraySel nodes).
// Return a new pointer to replace nodep() in the ArraySel.
UINFO(9," insertImplicit "<<nodep<<endl);
UINFO(9," insertImplicit (start="<<start<<",c="<<count<<") "<<nodep<<endl);
AstVarRef* refp = nodep->user1p()->castNode()->castVarRef();
if (!refp) nodep->v3fatalSrc("No VarRef in user1 of node "<<nodep);
AstVar* varp = refp->varp();
@@ -269,28 +279,15 @@ class SliceVisitor : public AstNVisitor {
newp->user1p(refp);
newp->start(lsb);
newp->length(msb - lsb + 1);
topp = newp->castNode();
topp = newp;
}
return topp->castArraySel();
}
int countClones(AstArraySel* nodep) {
// Count how many clones we need to make from this ArraySel
int clones = 1;
AstNode* fromp = nodep;
AstArraySel* selp;
do {
selp = fromp->castArraySel();
fromp = (selp) ? selp->fromp() : NULL;
if (fromp && selp) clones *= selp->length();
} while (fromp && selp);
return clones;
}
// VISITORS
virtual void visit(AstVarRef* nodep, AstNUser*) {
// 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
// case we need to create a slice across the entire Var
if (m_assignp && !nodep->backp()->castArraySel()) {
pair<uint32_t,uint32_t> arrDim = nodep->varp()->dtypep()->dimensions(false);
uint32_t dimensions = arrDim.second; // unpacked only
@@ -382,8 +379,8 @@ class SliceVisitor : public AstNVisitor {
refp = findVarRefRecurse(nodep->op3p());
if (refp) return refp;
}
if (nodep->op3p()) {
refp = findVarRefRecurse(nodep->op3p());
if (nodep->op4p()) {
refp = findVarRefRecurse(nodep->op4p());
if (refp) return refp;
}
if (nodep->nextp()) {
@@ -411,6 +408,23 @@ class SliceVisitor : public AstNVisitor {
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (!nodep->user1()) {
// Cleanup initArrays
if (AstInitArray* initp = nodep->rhsp()->castInitArray()) {
//if (debug()>=9) nodep->dumpTree(cout, "-InitArrayIn: ");
AstNode* newp = NULL;
int index = 0;
while (AstNode* subp=initp->initsp()) {
AstNode* lhsp = new AstArraySel(nodep->fileline(),
nodep->lhsp()->cloneTree(false),
index++);
// cppcheck-suppress nullPointer
newp = newp->addNext(nodep->cloneType(lhsp, subp->unlinkFrBack()));
}
//if (debug()>=9) newp->dumpTreeAndNext(cout, "-InitArrayOut: ");
nodep->replaceWith(newp);
pushDeletep(nodep); nodep=NULL;
return; // WIll iterate in a moment
}
// Hasn't been searched for implicit slices yet
findImplicit(nodep);
}
@@ -424,7 +438,7 @@ class SliceVisitor : public AstNVisitor {
dim = explicitDimensions(selp);
}
if (dim == 0 && !nodep->lhsp()->castVarRef()) {
// No ArraySel or VarRef, not something we can expand
// No ArraySel nor VarRef, not something we can expand
nodep->iterateChildren(*this);
} else {
AstVarRef* refp = findVarRefRecurse(nodep->lhsp());
@@ -445,25 +459,21 @@ class SliceVisitor : public AstNVisitor {
}
}
}
virtual void visit(AstRedOr* nodep, AstNUser*) {
if (!nodep->user1()) {
expandUniOp(nodep);
}
}
virtual void visit(AstRedAnd* nodep, AstNUser*) {
if (!nodep->user1()) {
expandUniOp(nodep);
}
}
virtual void visit(AstRedXor* nodep, AstNUser*) {
if (!nodep->user1()) {
expandUniOp(nodep);
}
}
virtual void visit(AstRedXnor* nodep, AstNUser*) {
if (!nodep->user1()) {
expandUniOp(nodep);
+16 -13
View File
@@ -31,6 +31,9 @@
#include "V3Ast.h"
#include "V3File.h"
// This visitor does not edit nodes, and is called at error-exit, so should use constant iterators
#include "V3AstConstOnly.h"
//######################################################################
// Stats class functions
@@ -74,14 +77,14 @@ private:
virtual void visit(AstNodeModule* nodep, AstNUser*) {
allNodes(nodep);
if (!m_fast) {
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
} else {
for (AstNode* searchp = nodep->stmtsp(); searchp; searchp=searchp->nextp()) {
if (AstCFunc* funcp = searchp->castCFunc()) {
if (funcp->name() == "_eval") {
m_instrs=0;
m_counting = true;
funcp->iterateChildren(*this);
funcp->iterateChildrenConst(*this);
m_counting = false;
}
}
@@ -90,7 +93,7 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
allNodes(nodep);
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
if (m_counting && nodep->dtypep()) {
if (nodep->isUsedClock()) ++m_statVarClock;
if (nodep->dtypeSkipRefp()->castUnpackArrayDType()) ++m_statVarArray;
@@ -103,7 +106,7 @@ private:
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
allNodes(nodep);
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
if (m_counting) {
if (nodep->varp()->dtypeSkipRefp()->castBasicDType()) {
m_statVarScpBytes += nodep->varp()->dtypeSkipRefp()->widthTotalBytes();
@@ -114,13 +117,13 @@ private:
UINFO(4," IF "<<nodep<<endl);
allNodes(nodep);
// Condition is part of PREVIOUS block
nodep->condp()->iterateAndNext(*this);
nodep->condp()->iterateAndNextConst(*this);
// Track prediction
if (m_counting) {
++m_statPred[nodep->branchPred()];
}
if (!m_fast) {
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
} else {
// See which path we want to take
bool takeElse = false;
@@ -135,11 +138,11 @@ private:
m_counting = false;
// Check if
m_instrs = 0;
nodep->ifsp()->iterateAndNext(*this);
nodep->ifsp()->iterateAndNextConst(*this);
double instrIf = m_instrs;
// Check else
m_instrs = 0;
nodep->elsesp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNextConst(*this);
double instrElse = m_instrs;
// Max of if or else condition
takeElse = (instrElse > instrIf);
@@ -150,9 +153,9 @@ private:
// Count the block
if (m_counting) {
if (takeElse) {
nodep->elsesp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNextConst(*this);
} else {
nodep->ifsp()->iterateAndNext(*this);
nodep->ifsp()->iterateAndNextConst(*this);
}
}
}
@@ -163,7 +166,7 @@ private:
virtual void visit(AstCCall* nodep, AstNUser*) {
//UINFO(4," CCALL "<<nodep<<endl);
allNodes(nodep);
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
if (m_fast) {
// Enter the function and trace it
nodep->funcp()->accept(*this);
@@ -172,12 +175,12 @@ private:
virtual void visit(AstCFunc* nodep, AstNUser*) {
m_cfuncp = nodep;
allNodes(nodep);
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
m_cfuncp = NULL;
}
virtual void visit(AstNode* nodep, AstNUser*) {
allNodes(nodep);
nodep->iterateChildren(*this);
nodep->iterateChildrenConst(*this);
}
public:
// CONSTRUCTORS
+4 -4
View File
@@ -188,11 +188,11 @@ public:
UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
const string& name = it->first;
VSymEnt* srcp = it->second;
VSymEnt* symp = new VSymEnt(graphp, srcp);
reinsert(name, symp);
VSymEnt* subSrcp = it->second;
VSymEnt* subSymp = new VSymEnt(graphp, subSrcp);
reinsert(name, subSymp);
// And recurse to create children
srcp->importFromIface(graphp, symp);
subSymp->importFromIface(graphp, subSrcp);
}
}
void cellErrorScopes(AstNode* lookp, string prettyName="") {
+4 -4
View File
@@ -188,7 +188,7 @@ private:
// Change it variable
FileLine* fl = nodep->fileline();
AstNodeDType* dtypep
AstNodeArrayDType* dtypep
= new AstUnpackArrayDType (fl,
nodep->findBitDType(m_outVarps.size(),
m_outVarps.size(), AstNumeric::UNSIGNED),
@@ -199,7 +199,7 @@ private:
"__Vtablechg" + cvtToStr(m_modTables),
dtypep);
chgVarp->isConst(true);
chgVarp->valuep(new AstInitArray (nodep->fileline(), NULL));
chgVarp->valuep(new AstInitArray (nodep->fileline(), dtypep, NULL));
m_modp->addStmtp(chgVarp);
AstVarScope* chgVscp = new AstVarScope (chgVarp->fileline(), m_scopep, chgVarp);
m_scopep->addVarp(chgVscp);
@@ -236,7 +236,7 @@ private:
AstVarScope* outvscp = *it;
AstVar* outvarp = outvscp->varp();
FileLine* fl = nodep->fileline();
AstNodeDType* dtypep
AstNodeArrayDType* dtypep
= new AstUnpackArrayDType (fl, outvarp->dtypep(),
new AstRange (fl, VL_MASK_I(m_inWidth), 0));
v3Global.rootp()->typeTablep()->addTypesp(dtypep);
@@ -246,7 +246,7 @@ private:
dtypep);
tablevarp->isConst(true);
tablevarp->isStatic(true);
tablevarp->valuep(new AstInitArray (nodep->fileline(), NULL));
tablevarp->valuep(new AstInitArray (nodep->fileline(), dtypep, NULL));
m_modp->addStmtp(tablevarp);
AstVarScope* tablevscp = new AstVarScope(tablevarp->fileline(), m_scopep, tablevarp);
m_scopep->addVarp(tablevscp);
+13 -7
View File
@@ -108,12 +108,15 @@ private:
void addCFuncStmt(AstCFunc* basep, AstNode* nodep, VNumRange arrayRange) {
basep->addStmtsp(nodep);
}
void addTraceDecl(const VNumRange& arrayRange) {
void addTraceDecl(const VNumRange& arrayRange,
int widthOverride) { // If !=0, is packed struct/array where basicp size misreflects one element
VNumRange bitRange;
AstBasicDType* bdtypep = m_traValuep->dtypep()->basicp();
if (bdtypep) bitRange = bdtypep->nrange();
if (widthOverride) bitRange = VNumRange(widthOverride-1,0,false);
else if (bdtypep) bitRange = bdtypep->nrange();
AstTraceDecl* declp = new AstTraceDecl(m_traVscp->fileline(), m_traShowname, m_traValuep,
bitRange, arrayRange);
UINFO(9,"Decl "<<declp<<endl);
if (m_initSubStmts && v3Global.opt.outputSplitCTrace()
&& m_initSubStmts > v3Global.opt.outputSplitCTrace()) {
@@ -199,7 +202,7 @@ private:
&& m_traVscp->dtypep()->skipRefp() == nodep) { // Nothing above this array
// Simple 1-D array, use exising V3EmitC runtime loop rather than unrolling
// This will put "(index)" at end of signal name for us
addTraceDecl(nodep->declRange());
addTraceDecl(nodep->declRange(), 0);
} else {
// Unroll now, as have no other method to get right signal names
AstNodeDType* subtypep = nodep->subDTypep()->skipRefp();
@@ -225,7 +228,7 @@ private:
if (!v3Global.opt.traceStructs()) {
// Everything downstream is packed, so deal with as one trace unit
// This may not be the nicest for user presentation, but is a much faster way to trace
addTraceDecl(VNumRange());
addTraceDecl(VNumRange(), nodep->width());
} else {
AstNodeDType* subtypep = nodep->subDTypep()->skipRefp();
for (int i=nodep->lsb(); i<=nodep->msb(); ++i) {
@@ -250,7 +253,7 @@ private:
if (nodep->packed() && !v3Global.opt.traceStructs()) {
// Everything downstream is packed, so deal with as one trace unit
// This may not be the nicest for user presentation, but is a much faster way to trace
addTraceDecl(VNumRange());
addTraceDecl(VNumRange(), nodep->width());
} else {
if (!nodep->packed()) {
addIgnore("Unsupported: Unpacked struct/union");
@@ -261,7 +264,6 @@ private:
AstNode* oldValuep = m_traValuep;
{
m_traShowname += string(" ")+itemp->prettyName();
m_traValuep->dumpTree(cout, "-tv: ");
if (nodep->castStructDType()) {
m_traValuep = new AstSel(nodep->fileline(), m_traValuep->cloneTree(true),
itemp->lsb(), subtypep->width());
@@ -280,7 +282,11 @@ private:
}
virtual void visit(AstBasicDType* nodep, AstNUser*) {
if (m_traVscp) {
addTraceDecl(VNumRange());
if (nodep->keyword()==AstBasicDTypeKwd::STRING) {
addIgnore("Unsupported: strings");
} else {
addTraceDecl(VNumRange(), 0);
}
}
}
virtual void visit(AstNodeDType* nodep, AstNUser*) {
+1 -1
View File
@@ -75,7 +75,7 @@ public:
private:
// METHODS
inline bool bitNumOk(int bit) const { return (bit*FLAGS_PER_BIT < (int)m_flags.size()); }
inline bool bitNumOk(int bit) const { return bit>=0 && (bit*FLAGS_PER_BIT < (int)m_flags.size()); }
inline bool usedFlag(int bit) const { return m_usedWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_USED]; }
inline bool drivenFlag(int bit) const { return m_drivenWhole || m_flags[bit*FLAGS_PER_BIT + FLAG_DRIVEN]; }
enum BitNamesWhich { BN_UNUSED, BN_UNDRIVEN, BN_BOTH };
+1099 -733
View File
File diff suppressed because it is too large Load Diff
+17 -7
View File
@@ -69,6 +69,22 @@ class WidthCommitVisitor : public AstNVisitor {
// AstVar::user1p -> bool, processed
AstUser1InUse m_inuser1;
public:
// METHODS
static AstConst* newIfConstCommitSize (AstConst* nodep) {
if ((nodep->dtypep()->width() != nodep->num().width())
|| !nodep->num().sized()) { // Need to force the number rrom unsized to sized
V3Number num (nodep->fileline(), nodep->dtypep()->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstConst* newp = new AstConst(nodep->fileline(), num);
newp->dtypeFrom(nodep);
return newp;
} else {
return NULL;
}
}
private:
// METHODS
void editDType(AstNode* nodep) {
@@ -97,13 +113,7 @@ private:
virtual void visit(AstConst* nodep, AstNUser*) {
if (!nodep->dtypep()) nodep->v3fatalSrc("No dtype");
nodep->dtypep()->accept(*this); // Do datatype first
if ((nodep->dtypep()->width() != nodep->num().width())
|| !nodep->num().sized()) { // Need to force the number rrom unsized to sized
V3Number num (nodep->fileline(), nodep->dtypep()->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstConst* newp = new AstConst(nodep->fileline(), num);
newp->dtypeFrom(nodep);
if (AstConst* newp = newIfConstCommitSize(nodep)) {
nodep->replaceWith(newp);
AstNode* oldp = nodep; nodep = newp;
//if (debug()>4) oldp->dumpTree(cout," fixConstSize_old: ");
-4
View File
@@ -435,11 +435,9 @@ void process () {
V3Order::orderAll(v3Global.rootp());
V3Global::dumpCheckGlobalTree("order.tree");
#ifndef NEW_ORDERING
// Change generated clocks to look at delayed signals
V3GenClk::genClkAll(v3Global.rootp());
V3Global::dumpCheckGlobalTree("genclk.tree");
#endif
// Convert sense lists into IF statements.
V3Clock::clockAll(v3Global.rootp());
@@ -464,11 +462,9 @@ void process () {
V3Dead::deadifyAll(v3Global.rootp());
V3Global::dumpCheckGlobalTree("const.tree");
#ifndef NEW_ORDERING
// Detect change loop
V3Changed::changedAll(v3Global.rootp());
V3Global::dumpCheckGlobalTree("changed.tree");
#endif
// Create tracing logic, since we ripped out some signals the user might want to trace
// Note past this point, we presume traced variables won't move between CFuncs
+10 -2
View File
@@ -424,6 +424,11 @@ sub tree_line {
($typefunc->{uinfo} = $func) =~ s/[ \t\"\{\}]+/ /g;
push @{$self->{treeop}{$type}}, $typefunc;
}
elsif ($func =~ /TREE_SKIP_VISIT\s*\(\s* \"([^\"]*)\" \s*\)/sx) {
my $type = $1;
$self->{tree_skip_visit}{$type} = 1;
$::Classes{$type} or $self->error("Unknown node type: $type");
}
else {
$self->error("Unknown astgen op: $func");
}
@@ -598,9 +603,12 @@ sub tree_base {
@out_for_type,
" }\n") if ($out_for_type[0]);
} elsif ($out_for_type[0]) { # Other types with something to print
my $skip = $self->{tree_skip_visit}{$type};
my $gen = $skip ? "Gen" : "";
$self->print(" // Generated by astgen\n",
" virtual void visit(Ast${type}* nodep, AstNUser*) {\n",
" nodep->iterateChildren(*this);\n",
" virtual void visit$gen(Ast${type}* nodep, AstNUser*) {\n",
($skip?"":
" nodep->iterateChildren(*this);\n"),
@out_for_type,
" }\n");
}
+6 -4
View File
@@ -9,7 +9,7 @@ use Pod::Usage;
use strict;
use vars qw ($Debug $VERSION);
$VERSION = '3.318';
$VERSION = '3.404';
our $Self;
@@ -304,10 +304,12 @@ sub clean_input {
foreach my $line (@linesin) {
$l++;
if ($line =~ /BISONPRE_VERSION/) {
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*([^\),]+)\)\s*$/)
# 1 3 4
($line =~ /BISONPRE_VERSION\((\S+)\s*,\s*((\S+)\s*,)?\s*([^\),]+)\)\s*$/)
or die "%Error: $filename:$l: Bad form of BISONPRE_VERSION: $line\n";
my $ver=$1; my $cmd=$2;
if ($Self->{bison_version} >= $1) {
my $ver=$1; my $ver_max=$3; my $cmd=$4;
if ($Self->{bison_version} >= $1
&& (!$ver_max || $Self->{bison_version} <= $ver_max)) {
$line = $cmd."\n";
} else {
$line = "//NOP: $line";
+183
View File
@@ -0,0 +1,183 @@
#!/usr/bin/perl -w
# See copyright, etc in below POD section.
######################################################################
require 5.006_001;
use Getopt::Long;
use IO::File;
use Pod::Usage;
use strict;
use vars qw ($Debug $VERSION);
$VERSION = '3.857';
#======================================================================
# main
our $Opt_Debug;
autoflush STDOUT 1;
autoflush STDERR 1;
Getopt::Long::config ("no_auto_abbrev","pass_through");
our @Opt_Args = ("cppcheck", @ARGV);
if (! GetOptions (
# Local options
"help" => \&usage,
"version" => sub { print "Version $VERSION\n"; system("cppcheck","--version"); exit(0); },
)) {
die "%Error: Bad usage, try 'cppcheck_filtered --help'\n";
}
process();
#----------------------------------------------------------------------
sub usage {
print "Version $VERSION\n";
pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT, -noperldoc=>1);
exit (1);
}
#######################################################################
sub process {
my $cmd = join(' ',@Opt_Args);
print "\t$cmd\n" if $Debug;
my $fh = IO::File->new("$cmd 2>&1 |");
my %uniq;
my %errs;
while (defined(my $line = $fh->getline())) {
$line =~ s/Checking usage of global functions\.+//; # Sometimes tacked at end-of-line
# General gunk
next if $uniq{$line}++;
next if $line =~ m!^<\?xml version!;
next if $line =~ m!^<results>!;
next if $line =~ m!^</results>!;
next if $line =~ m!^<error.*id="unmatchedSuppression"!; # --suppress=unmatchedSuppression doesn't work
next if $line =~ m!Cppcheck cannot find all the include files!; # An earlier id line is more specific
next if $line =~ m!^Checking !;
next if $line =~ m!^make.*Entering directory !;
next if $line =~ m!^make.*Leaving directory !;
next if $line =~ m!^\s+$!g;
# Specific suppressions
next if $line =~ m!id="missingInclude" .*systemc.h!;
next if $line =~ m!id="missingInclude" .*svdpi.h!;
next if $line =~ m!file=".*obj_dbg/V3ParseBison.c".* id="unreachableCode"!;
# Output
if ($line =~ /^cppcheck --/) {
print $line if $Debug;
} else {
my $suppress;
if ($line =~ /file="([^"]+)"\s+line="(\d+)"\s+id="([^"]+)"/) {
my $file = $1; my $linenum = $2; my $id = $3;
$suppress = 1 if _suppress($file,$linenum,$id);
}
if (!$suppress) {
my $eline = "%Error: cppcheck: $line";
print $eline;
$errs{$eline}++;
}
}
}
if (scalar(keys %errs)) {
#my $all = join('',sort(keys %errs));
#$Self->error("Cppcheck errors:\n$all");
die "%Error: cppcheck_filtered found errors";
}
}
######################################################################
sub _suppress {
my $filename = shift;
my $linenum = shift;
my $id = shift;
#print "-Suppression search $filename $linenum $id\n" if $Self->{verbose};
my $fh = IO::File->new("<$filename");
if (!$fh) {
warn "%Warning: $! $filename,";
return undef;
}
my $l = 0;
while (defined(my $line = $fh->getline())) {
++$l;
if ($l+1 == $linenum) {
if ($line =~ /cppcheck-suppress\s+(\S+)/) {
my $supid = $1;
if ($supid eq $id) {
return 1;
} else {
warn "%Warning: $filename: $l: Found suppress for id='$supid', not expected id='$id'\n";
}
}
}
}
return undef;
}
1;
#######################################################################
__END__
=pod
=head1 NAME
cppcheck_filtered - cppcheck wrapper with post-processing
=head1 SYNOPSIS
cppcheck_filtered ...normal cpp check flags...
=head1 DESCRIPTION
Cppcheck_Filtered is a wrapper for cppcheck that filters out unnecessary
warnings related to Verilator.
=head1 ARGUMENTS
Most arguments are passed through to cppcheck
=over 4
=item --help
Displays this message and program version and exits.
=item --version
Print the version number and exit.
=back
=head1 DISTRIBUTION
This is part of the L<http://www.veripool.org/> free Verilog EDA software
tool suite. The latest version is available from CPAN and from
L<http://www.veripool.org/>.
Copyright 2014-2014 by Wilson Snyder. This package 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.
This program 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.
=head1 AUTHORS
Wilson Snyder <[email protected]>
=head1 SEE ALSO
C<cppcheck>
=cut
######################################################################
### Local Variables:
### compile-command: "./cppcheck_filtered --xml V3Width.cpp"
### End:
+22 -22
View File
@@ -138,7 +138,7 @@ void yyerrorf(const char* format, ...) {
%s V95 V01 V05 S05 S09 S12
%s STRING ATTRMODE TABLE
%s VA5 SA9 PSL VLT
%s VA5 SAX PSL VLT
%s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
%s IGNORE
@@ -179,7 +179,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* Verilog 1995 */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
{ws} { } /* otherwise ignore white-space */
{crnl} { NEXTLINE(); } /* Count line numbers */
/* Extensions to Verilog set, some specified by PSL */
@@ -352,7 +352,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* Verilog 2001 */
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
/* System Tasks */
"$signed" { FL; return yD_SIGNED; }
"$unsigned" { FL; return yD_UNSIGNED; }
@@ -383,13 +383,13 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* Verilog 2005 */
<V05,S05,S09,S12,SA9,PSL>{
<V05,S05,S09,S12,SAX,PSL>{
/* Keywords */
"uwire" { FL; return yWIRE; }
}
/* System Verilog 2005 */
<S05,S09,S12,PSL>{
<S05,S09,S12,SAX,PSL>{
/* System Tasks */
"$bits" { FL; return yD_BITS; }
"$clog2" { FL; return yD_CLOG2; }
@@ -506,7 +506,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* SystemVerilog 2005 ONLY not PSL; different rules for PSL as specified below */
<S05,S09,S12>{
<S05,S09,S12,SAX>{
/* Keywords */
"assert" { FL; return yASSERT; }
"const" { FL; return yCONST__LEX; }
@@ -521,7 +521,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* SystemVerilog 2009 */
<S09,S12,PSL>{
<S09,S12,SAX,PSL>{
/* Keywords */
"global" { FL; return yGLOBAL__LEX; }
"unique0" { FL; return yUNIQUE0; }
@@ -550,7 +550,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* System Verilog 2012 */
<S12,PSL>{
<S12,SAX,PSL>{
/* Keywords */
"implements" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
"interconnect" { yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
@@ -559,7 +559,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* Default PLI rule */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,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
@@ -572,7 +572,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* AMS */
<VA5,SA9>{
<VA5,SAX>{
/* Generic unsupported warnings */
"above" { yyerrorf("Unsupported: AMS reserved word not implemented: %s",yytext); }
"abs" { yyerrorf("Unsupported: AMS reserved word not implemented: %s",yytext); }
@@ -666,7 +666,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* PSL */
/*Entry into PSL; mode change */
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
"psl" { yy_push_state(PSL); FL; return yPSL; }
}
@@ -755,7 +755,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Meta comments */
/* Converted from //{cmt}verilator ...{cmt} by preprocessor */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,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; }
@@ -790,11 +790,11 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* Single character operator thingies */
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
"{" { FL; return yytext[0]; }
"}" { FL; return yytext[0]; }
}
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
"!" { FL; return yytext[0]; }
"#" { FL; return yytext[0]; }
"$" { FL; return yytext[0]; }
@@ -826,7 +826,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* Operators and multi-character symbols */
/* Verilog 1995 Operators */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
"&&" { FL; return yP_ANDAND; }
"||" { FL; return yP_OROR; }
"<=" { FL; return yP_LTE; }
@@ -848,7 +848,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* Verilog 2001 Operators */
<V01,V05,VA5,S05,S09,S12,SA9,PSL>{
<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
"<<<" { FL; return yP_SLEFT; }
">>>" { FL; return yP_SSRIGHT; }
"**" { FL; return yP_POW; }
@@ -858,7 +858,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* SystemVerilog Operators */
<S05,S09,S12>{
<S05,S09,S12,SAX>{
"'" { FL; return yP_TICK; }
"'{" { FL; return yP_TICKBRA; }
"==?" { FL; return yP_WILDEQUAL; }
@@ -907,7 +907,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
}
/* Identifiers and numbers */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT>{
{escid} { FL; yylval.strp = PARSEP->newString
(AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash
return yaID__LEX;
@@ -980,7 +980,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* Attributes */
/* Note simulators vary in support for "(* /_*something*_/ foo*)" where _ doesn't exist */
<V95,V01,V05,VA5,S05,S09,S12,SA9>{
<V95,V01,V05,VA5,S05,S09,S12,SAX>{
"(*"({ws}|{crnl})*({id}|{escid}) { yymore(); yy_push_state(ATTRMODE); } // Doesn't match (*), but (* attr_spec
}
@@ -997,7 +997,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/* 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,S12,SA9,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
"`accelerate" { } // Verilog-XL compatibility
"`autoexpand_vectornets" { } // Verilog-XL compatibility
"`celldefine" { PARSEP->inCellDefine(true); }
@@ -1042,7 +1042,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
"`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); }
"`begin_keywords"[ \t]*\"1800[+]VAMS\" { yy_push_state(SAX); PARSEP->pushBeginKeywords(YY_START); } /*Latest SV*/
"`end_keywords" { yy_pop_state(); if (!PARSEP->popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); }
/* Verilator */
@@ -1073,7 +1073,7 @@ vnum {vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
/************************************************************************/
/* Default rules - leave last */
<V95,V01,V05,VA5,S05,S09,S12,SA9,PSL,VLT>{
<V95,V01,V05,VA5,S05,S09,S12,SAX,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. */
+38 -9
View File
@@ -1892,10 +1892,6 @@ netId<strp>:
| idSVKwd { $$ = $1; $<fl>$=$<fl>1; }
;
sigId<varp>:
id { $$ = VARDONEA($<fl>1,*$1, NULL, NULL); }
;
sigAttrListE<nodep>:
/* empty */ { $$ = NULL; }
| sigAttrList { $$ = $1; }
@@ -1958,7 +1954,8 @@ packed_dimension<rangep>: // ==IEEE: packed_dimension
param_assignment<varp>: // ==IEEE: param_assignment
// // IEEE: constant_param_expression
// // constant_param_expression: '$' is in expr
sigId sigAttrListE '=' expr { $$ = $1; $1->addAttrsp($2); $$->valuep($4); }
id/*new-parameter*/ variable_dimensionListE sigAttrListE '=' expr
/**/ { $$ = VARDONEA($<fl>1,*$1, $2, $3); $$->valuep($5); }
//UNSUP: exprOrDataType instead of expr
;
@@ -2088,6 +2085,7 @@ senitem<senitemp>: // IEEE: part of event_expression, non-'OR' ',' terms
| senitemVar { $$ = $1; }
| '(' senitemVar ')' { $$ = $2; }
//UNSUP expr { UNSUP }
| '{' event_expression '}' { $$ = $2; }
//UNSUP expr yIFF expr { UNSUP }
// Since expr is unsupported we allow and ignore constants (removed in V3Const)
| yaINTNUM { $$ = NULL; }
@@ -2848,8 +2846,8 @@ expr<nodep>: // IEEE: part of expression/constant_expression/primary
| '~' ~r~expr %prec prNEGATION { $$ = new AstNot ($1,$2); }
| '|' ~r~expr %prec prREDUCTION { $$ = new AstRedOr ($1,$2); }
| '^' ~r~expr %prec prREDUCTION { $$ = new AstRedXor ($1,$2); }
| yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedAnd($1,$2)); }
| yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstNot($1,new AstRedOr ($1,$2)); }
| yP_NAND ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1,new AstRedAnd($1,$2)); }
| yP_NOR ~r~expr %prec prREDUCTION { $$ = new AstLogNot($1,new AstRedOr ($1,$2)); }
| yP_XNOR ~r~expr %prec prREDUCTION { $$ = new AstRedXnor ($1,$2); }
//
// // IEEE: inc_or_dec_expression
@@ -3005,7 +3003,8 @@ exprNoStr<nodep>: // expression with string removed
exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
~l~exprScope { $$ = $1; }
// // IEEE: concatenation/constant_concatenation
| '{' cateList '}' { $$ = $2; }
// // Replicate(1) required as otherwise "{a}" would not be self-determined
| '{' cateList '}' { $$ = new AstReplicate($1,$2,1); }
// // IEEE: assignment_pattern_expression
// // IEEE: [ assignment_pattern_expression_type ] == [ ps_type_id /ps_paremeter_id/data_type]
// // We allow more here than the spec requires
@@ -3013,7 +3012,7 @@ exprOkLvalue<nodep>: // expression that's also OK to use as a variable_lvalue
| data_type assignment_pattern { $$ = $2; $2->childDTypep($1); }
| assignment_pattern { $$ = $1; }
//
//UNSUP streaming_concatenation { UNSUP }
| streaming_concatenation { $$ = $1; }
;
fexprOkLvalue<nodep>: // exprOkLValue, For use as first part of statement (disambiguates <=)
@@ -3115,6 +3114,32 @@ argsDotted<nodep>: // IEEE: part of list_of_arguments
| '.' idAny '(' expr ')' { $$ = new AstArg($1,*$2,$4); }
;
streaming_concatenation<nodep>: // ==IEEE: streaming_concatenation
// // Need to disambiguate {<< expr-{ ... expr-} stream_concat }
// // From {<< stream-{ ... stream-} }
// // Likewise simple_type's idScoped from constExpr's idScope
// // Thus we allow always any two operations. Sorry
// // IEEE: "'{' yP_SL/R stream_concatenation '}'"
// // IEEE: "'{' yP_SL/R simple_type stream_concatenation '}'"
// // IEEE: "'{' yP_SL/R constExpr stream_concatenation '}'"
'{' yP_SLEFT stream_concOrExprOrType '}' { $$ = new AstStreamL($1, $3, new AstConst($1,1)); }
| '{' yP_SRIGHT stream_concOrExprOrType '}' { $$ = new AstStreamR($1, $3, new AstConst($1,1)); }
| '{' yP_SLEFT stream_concOrExprOrType stream_concatenation '}' { $$ = new AstStreamL($1, $4, $3); }
| '{' yP_SRIGHT stream_concOrExprOrType stream_concatenation '}' { $$ = new AstStreamR($1, $4, $3); }
;
stream_concOrExprOrType<nodep>: // IEEE: stream_concatenation | slice_size:simple_type | slice_size:constExpr
cateList { $$ = $1; }
| simple_type { $$ = $1; }
// // stream_concatenation found via cateList:stream_expr:'{-normal-concat'
// // simple_typeRef found via cateList:stream_expr:expr:id
// // constant_expression found via cateList:stream_expr:expr
;
stream_concatenation<nodep>: // ==IEEE: stream_concatenation
'{' cateList '}' { $$ = $2; }
;
stream_expression<nodep>: // ==IEEE: stream_expression
// // IEEE: array_range_expression expanded below
expr { $$ = $1; }
@@ -3384,6 +3409,7 @@ variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue
//UNSUP idClassSel yP_TICKBRA variable_lvalueList '}' { UNSUP }
//UNSUP /**/ yP_TICKBRA variable_lvalueList '}' { UNSUP }
//UNSUP streaming_concatenation { UNSUP }
| streaming_concatenation { $$ = $1; }
;
variable_lvalueConcList<nodep>: // IEEE: part of variable_lvalue: '{' variable_lvalue { ',' variable_lvalue } '}'
@@ -3647,6 +3673,8 @@ void V3ParseGrammar::argWrapList(AstNodeFTaskRef* nodep) {
AstNode* outp = NULL;
while (nodep->pinsp()) {
AstNode* exprp = nodep->pinsp()->unlinkFrBack();
// addNext can handle nulls:
// cppcheck-suppress nullPointer
outp = outp->addNext(new AstArg(exprp->fileline(), "", exprp));
}
if (outp) nodep->addPinsp(outp);
@@ -3728,6 +3756,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
//
// Propagate from current module tracing state
if (nodep->isGenVar()) nodep->trace(false);
else if (nodep->isParam() && !v3Global.opt.traceParams()) nodep->trace(false);
else nodep->trace(v3Global.opt.trace() && nodep->fileline()->tracingOn());
// Remember the last variable created, so we can attach attributes to it in later parsing
+19 -2
View File
@@ -61,6 +61,7 @@ my $opt_vlt;
my $opt_vcs;
my $opt_verbose;
my $Opt_Verilated_Debug;
our $Opt_Unsupported;
our $Opt_Verilation = 1;
our @Opt_Driver_Verilator_Flags;
@@ -83,6 +84,7 @@ if (! GetOptions (
"site!" => \$opt_site,
"stop!" => \$opt_stop,
"trace!" => \$opt_trace,
"unsupported!"=> \$Opt_Unsupported,
"v3!" => \$opt_vlt, # Old
"vl!" => \$opt_vlt, # Old
"vlt!" => \$opt_vlt,
@@ -333,7 +335,11 @@ sub new {
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
all_run_flags => [],
pli_flags => ["-I$ENV{VERILATOR_ROOT}/include/vltstd -fPIC -export-dynamic -shared -o $self->{obj_dir}/libvpi.so"],
pli_flags => ["-I$ENV{VERILATOR_ROOT}/include/vltstd -fPIC -shared"
.(($^O eq "darwin" )
? " -Wl,-undefined,dynamic_lookup"
: " -export-dynamic")
." -o $self->{obj_dir}/libvpi.so"],
# ATSIM
atsim => 0,
atsim_flags => [split(/\s+/,"-c +sv +define+ATSIM"),
@@ -430,7 +436,9 @@ sub unsupported {
my $self = shift;
my $msg = join('',@_);
warn "%Unsupported: $self->{mode}/$self->{name}: ".$msg."\n";
$self->{unsupporteds} ||= "Unsupported: ".$msg;
if (!$::Opt_Unsupported) {
$self->{unsupporteds} ||= "Unsupported: ".$msg;
}
}
sub prep {
@@ -817,6 +825,11 @@ sub ok {
return $self->{ok};
}
sub continuing {
my $self = (ref $_[0]? shift : $Self);
return !($self->errors || $self->skips || $self->unsupporteds);
}
sub errors {
my $self = (ref $_[0]? shift : $Self);
return $self->{errors};
@@ -1848,6 +1861,10 @@ Stop on the first error.
Set the simulator specific flags to request waveform tracing.
=item --unsupported
Run tests even if marked as unsupported.
=item --vcs
Run using Synopsys VCS simulator.
+5 -2
View File
@@ -11,7 +11,7 @@ module t (/*AUTOARG*/
input clk;
integer cyc; initial cyc=1;
reg [31:0] a, b, c, d, e, f, g;
reg [31:0] a, b, c, d, e, f, g, h;
always @ (*) begin // Test Verilog 2001 (*)
// verilator lint_off COMBDLY
@@ -33,6 +33,9 @@ module t (/*AUTOARG*/
always @ (1'b0, CONSTANT, f) begin // not technically legal, see bug412
g = f;
end
always @ ({CONSTANT, g}) begin // bug745
h = g;
end
//always @ ((posedge b) or (a or b)) begin // note both illegal
always @ (posedge clk) begin
@@ -46,7 +49,7 @@ module t (/*AUTOARG*/
if (c != 32'hfeedface) $stop;
end
if (cyc==3) begin
if (g != 32'hfeedface) $stop;
if (h != 32'hfeedface) $stop;
end
if (cyc==7) begin
$write("*-* All Finished *-*\n");
-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, bug355");
compile (
);
+15 -5
View File
@@ -26,11 +26,21 @@ module t (/*AUTOARG*/
//array_simp[0] = '{ 1:4'd3, default:13};
//if (array_simp[0] !== 16'hDD3D) $stop;
array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }};
array_simp = '{ '{ 4'd3, 4'd2, 4'd1, 4'd0 }, '{ 4'd1, 4'd2, 4'd3, 4'd4 }};
if (array_simp !== 32'h3210_1234) $stop;
// IEEE says '{} allowed only on assignments, not !=, ==.
// Doesn't seem to work for unpacked arrays in other simulators
//array_simp <= '{2 { '{4 { 4'd3, 4'd2, 4'd1, 4'd0 }} } };
array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }};
if (array_simp !== 32'h3210_3210) $stop;
array_simp = '{2{ '{4{ 4'd3 }} }};
if (array_simp !== 32'h3333_3333) $stop;
// Not legal in other simulators - replication doesn't match
// However IEEE suggests this is legal.
//array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2}
$write("*-* All Finished *-*\n");
$finish;
@@ -86,8 +96,8 @@ module t (/*AUTOARG*/
else if (cnt[30:2]== 2) array_bg <= '{default:13};
else if (cnt[30:2]== 3) array_bg <= '{0:4, 1:5, 2:6, 3:7};
else if (cnt[30:2]== 4) array_bg <= '{2:15, default:13};
else if (cnt[30:2]== 5) array_bg <= '{WA { {WB {2'b10}} }};
else if (cnt[30:2]== 6) array_bg <= '{cnt+0, cnt+1, cnt+2, cnt+3};
else if (cnt[30:2]== 5) array_bg <= '{WA { {WB/2 {2'b10}} }};
else if (cnt[30:2]== 6) array_bg <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3};
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]== 0) begin if (array_bg !== 16'b0000000000000000) begin $display("%b", array_bg); $stop(); end end
@@ -122,7 +132,7 @@ module t (/*AUTOARG*/
else if (cnt[30:2]== 3) array_lt <= '{3:4, 2:5, 1:6, 0:7};
else if (cnt[30:2]== 4) array_lt <= '{1:15, default:13};
else if (cnt[30:2]== 5) array_lt <= '{WA { {WB/2 {2'b10}} }};
else if (cnt[30:2]==10) array_lt <= '{cnt+0, cnt+1, cnt+2, cnt+3};
else if (cnt[30:2]==10) array_lt <= '{cnt[3:0]+0, cnt[3:0]+1, cnt[3:0]+2, cnt[3:0]+3};
end else if (cnt[1:0]==2'd2) begin
// chack array agains expected value
if (cnt[30:2]== 0) begin if (array_lt !== 16'b0000000000000000) begin $display("%b", array_lt); $stop(); end end
@@ -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, bug355");
compile (
);
+11 -1
View File
@@ -25,7 +25,17 @@ module t (/*AUTOARG*/);
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_1234) $stop;
// Doesn't seem to work for unpacked arrays in other simulators
//array_simp <= '{2{ '{4{ 4'd3, 4'd2, 4'd1, 4'd0 }} }};
array_simp = '{2{ '{4'd3, 4'd2, 4'd1, 4'd0 } }};
if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0],
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3210_3210) $stop;
array_simp = '{2{ '{4{ 4'd3 }} }};
if ({array_simp[1][3],array_simp[1][2],array_simp[1][1],array_simp[1][0],
array_simp[0][3],array_simp[0][2],array_simp[0][1],array_simp[0][0]} !== 32'h3333_3333) $stop;
// Not legal in other simulators - replication doesn't match
// However IEEE suggests this is legal.
//array_simp = '{2{ '{2{ 4'd3, 4'd2 }} }}; // Note it's not '{3,2}
$write("*-* All Finished *-*\n");
$finish;
+1
View File
@@ -27,6 +27,7 @@ module t (/*AUTOARG*/
if (cyc!=0) begin
cyc <= cyc + 1;
toggle <= !cyc[0];
if (cyc==7) assert (cyc[0] == cyc[1]); // bug743
if (cyc==9) begin
`ifdef FAILING_ASSERTIONS
assert (0) else $info;
+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;
@@ -3,16 +3,13 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_chg (/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
clk, fastclk
);
input clk;
input fastclk; // surefire lint_off_line UDDIXN
output passed; reg passed; initial passed = 0;
integer _mode; initial _mode=0;
@@ -54,8 +51,8 @@ module t_chg (/*AUTOARG*/
else if (_mode==1) begin
_mode<=2;
if (ord7 !== 7) $stop;
$write("[%0t] t_chg: Passed\n", $time);
passed <= 1'b1;
$write("*-* All Finished *-*\n");
$finish;
end
end
+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;
+101 -13
View File
@@ -3,17 +3,39 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_clk (/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
fastclk, clk, reset_l
clk, fastclk
);
input fastclk;
input clk;
input clk /*verilator sc_clock*/;
input fastclk /*verilator sc_clock*/;
reg reset_l;
int cyc;
initial reset_l = 0;
always @ (posedge clk) begin
if (cyc==0) reset_l <= 1'b1;
else if (cyc==1) reset_l <= 1'b0;
else if (cyc==10) reset_l <= 1'b1;
end
t_clk t (/*AUTOINST*/
// Inputs
.clk (clk),
.fastclk (fastclk),
.reset_l (reset_l));
endmodule
module t_clk (/*AUTOARG*/
// Inputs
clk, fastclk, reset_l
);
input clk /*verilator sc_clock*/;
input fastclk /*verilator sc_clock*/;
input reset_l;
output passed; reg passed; initial passed = 0;
// surefire lint_off STMINI
// surefire lint_off CWECSB
// surefire lint_off NBAJAM
@@ -35,7 +57,9 @@ module t_clk (/*AUTOARG*/
// verilator lint_on GENCLK
always @ (posedge clk) begin
//$write("CLK1 %x\n", reset_l);
`ifdef TEST_VERBOSE
$write("[%0t] CLK1 %x\n", $time, reset_l);
`endif
if (!reset_l) begin
clk_clocks <= 0;
int_clocks <= 0;
@@ -46,7 +70,9 @@ module t_clk (/*AUTOARG*/
internal_clk <= ~internal_clk;
if (!_ranit) begin
_ranit <= 1;
`ifdef TEST_VERBOSE
$write("[%0t] t_clk: Running\n",$time);
`endif
reset_int_ <= 1;
end
end
@@ -54,7 +80,9 @@ module t_clk (/*AUTOARG*/
reg [7:0] sig_rst;
always @ (posedge clk or negedge reset_l) begin
//$write("CLK2 %x sr=%x\n", reset_l, sig_rst);
`ifdef TEST_VERBOSE
$write("[%0t] CLK2 %x sr=%x\n", $time, reset_l, sig_rst);
`endif
if (!reset_l) begin
sig_rst <= 0;
end
@@ -64,7 +92,9 @@ module t_clk (/*AUTOARG*/
end
always @ (posedge clk) begin
//$write("CLK3 %x cc=%x sr=%x\n", reset_l, clk_clocks, sig_rst);
`ifdef TEST_VERBOSE
$write("[%0t] CLK3 %x cc=%x sr=%x\n", $time, reset_l, clk_clocks, sig_rst);
`endif
if (!reset_l) begin
clk_clocks <= 0;
end
@@ -77,15 +107,17 @@ module t_clk (/*AUTOARG*/
if (int_clocks_copy !== 2) $stop;
if (clk_clocks_d1r !== clk_clocks_cp2_d1r) $stop;
if (clk_clocks_d1sr !== clk_clocks_cp2_d1sr) $stop;
passed <= 1'b1;
$write("[%0t] t_clk: Passed\n",$time);
$write("*-* All Finished *-*\n");
$finish;
end
end
end
reg [7:0] resetted;
always @ (posedge clk or negedge reset_int_) begin
//$write("CLK4 %x\n", reset_l);
`ifdef TEST_VERBOSE
$write("[%0t] CLK4 %x\n", $time, reset_l);
`endif
if (!reset_int_) begin
resetted <= 0;
end
@@ -112,3 +144,59 @@ module t_clk (/*AUTOARG*/
.reset_l (reset_l));
endmodule
module t_clk_flop (/*AUTOARG*/
// Outputs
q, q2,
// Inputs
clk, clk2, a
);
parameter WIDTH=8;
input clk;
input clk2;
input [(WIDTH-1):0] a;
output [(WIDTH-1):0] q;
output [(WIDTH-1):0] q2;
reg [(WIDTH-1):0] q;
reg [(WIDTH-1):0] q2;
always @ (posedge clk) q<=a;
always @ (posedge clk2) q2<=a;
endmodule
module t_clk_two (/*AUTOARG*/
// Inputs
fastclk, reset_l
);
input fastclk;
input reset_l;
// verilator lint_off GENCLK
reg clk2;
// verilator lint_on GENCLK
reg [31:0] count;
t_clk_twob tb (.*);
wire reset_h = ~reset_l;
always @ (posedge fastclk) begin
if (reset_h) clk2 <= 0;
else clk2 <= ~clk2;
end
always @ (posedge clk2) begin
if (reset_h) count <= 0;
else count <= count + 1;
end
endmodule
module t_clk_twob (/*AUTOARG*/
// Inputs
fastclk, reset_l
);
input fastclk;
input reset_l;
always @ (posedge fastclk) begin
// Extra line coverage point, just to make sure coverage
// hierarchy under inlining lands properly
if (reset_l) ;
end
endmodule
+2 -2
View File
@@ -19,7 +19,7 @@ if (!-r "$root/.git") {
my $files = `cd $root && git ls-files --exclude-standard`;
print "ST $files\n" if $Debug;
$files =~ s/\s+/ /g;
my $cmd = "cd $root && fgrep -n FIXME $files | sort | grep -v t_dist_fixme";
my $cmd = "cd $root && fgrep -n FIX"."ME $files | sort | grep -v t_dist_fixme";
my $grep = `$cmd`;
print "$grep\n";
if ($grep ne "") {
@@ -27,7 +27,7 @@ if (!-r "$root/.git") {
foreach my $line (split /\n/, $grep) {
$names{$1} = 1 if $line =~ /^([^:]+)/;
}
$Self->error("Files with FIXMEs: ",join(' ',sort keys %names));
$Self->error("Files with FIX"."MEs: ",join(' ',sort keys %names));
}
}
+56
View File
@@ -0,0 +1,56 @@
// -*- mode: C++; c-file-style: "cc-mode" -*-
//
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
#include <verilated.h>
#include "Vt_dpi_vams.h"
//======================================================================
#if defined(VERILATOR)
# include "Vt_dpi_vams__Dpi.h"
#elif defined(VCS)
# include "../vc_hdrs.h"
#elif defined(CADENCE)
# define NEED_EXTERNS
#else
# error "Unknown simulator for DPI test"
#endif
#ifdef NEED_EXTERNS
extern "C" {
extern void dpii_call (double in, double* outp);
}
#endif
void dpii_call (double in, double* outp) {
*outp = in + 0.1;
}
//======================================================================
unsigned int main_time = 0;
double sc_time_stamp () {
return main_time;
}
VM_PREFIX* topp = NULL;
int main (int argc, char *argv[]) {
topp = new VM_PREFIX;
Verilated::debug(0);
topp->in = 1.1;
topp->eval();
if (topp->out != 1.2) {
VL_PRINTF("*-* All Finished *-*\n");
topp->final();
} else {
vl_fatal(__FILE__,__LINE__,"top", "Unexpected results\n");
}
return 0;
}
+21
View File
@@ -0,0 +1,21 @@
#!/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 (
make_top_shell => 0,
make_main => 0,
verilator_flags2 => ["--exe","$Self->{t_dir}/$Self->{name}.cpp"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+28
View File
@@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
//`begin_keywords "VAMS-2.3"
`begin_keywords "1800+VAMS"
module t (/*AUTOARG*/
// Outputs
out,
// Inputs
in
);
input in;
wreal in;
output out;
wreal out;
import "DPI-C" context function void dpii_call(input real in, output real out);
initial begin
dpii_call(in,out);
$finish;
end
endmodule
+1 -1
View File
@@ -16,7 +16,7 @@ $Self->_run (cmd=>["cd $Self->{obj_dir}"
check_finished=>0);
$Self->_run (cmd=>["cd $Self->{obj_dir}"
." && g++ -fPIC -c ../../t/t_flag_ldflags_so.cpp"
." && ld -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"],
." && g++ -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"],
check_finished=>0);
compile (
+2 -2
View File
@@ -13,9 +13,9 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
q{created tag with scope = top.v.tag
created tag with scope = top.v.b.gen[0].tag
q{created tag with scope = top.v.b.gen[0].tag
created tag with scope = top.v.b.gen[1].tag
created tag with scope = top.v.tag
mod a has scope = top.v
mod a has tag = top.v.tag
mod b has scope = top.v.b
+1 -1
View File
@@ -11,7 +11,7 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
q{%Error: t/t_inst_array_bad.v:\d+: Port connection __pinNumber2 as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits.
q{%Error: t/t_inst_array_bad.v:\d+: Input port connection 'onebit' as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits.
%Error: Exiting due to.*},
);
+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 2004 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;
+131
View File
@@ -0,0 +1,131 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2012 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [31:0] in = crc[31:0];
localparam WIDTH = 31;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [WIDTH-1:0] b; // From test of Test.v
wire [WIDTH-1:0] c; // From test of Test.v
// End of automatics
reg rst_l;
Test #(.WIDTH(WIDTH))
test (/*AUTOINST*/
// Outputs
.b (b[WIDTH-1:0]),
.c (c[WIDTH-1:0]),
// Inputs
.clk (clk),
.rst_l (rst_l),
.in (in[WIDTH-1:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {1'h0, c, 1'b0, b};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
rst_l <= ~1'b1;
end
else if (cyc<10) begin
sum <= 64'h0;
rst_l <= ~1'b1;
// Hold reset while summing
end
else if (cyc<20) begin
rst_l <= ~1'b0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'hbcfcebdb75ec9d32
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
b, c,
// Inputs
clk, rst_l, in
);
parameter WIDTH = 5;
input clk;
input rst_l;
input [WIDTH-1:0] in;
output wire [WIDTH-1:0] b;
output wire [WIDTH-1:0] c;
dff # ( .WIDTH (WIDTH),
.RESET ('0), // Although this is a single bit, the parameter must be the specified type
.RESET_WIDTH (1) )
sub1
( .clk(clk), .rst_l(rst_l), .q(b), .d(in) );
dff # ( .WIDTH (WIDTH),
.RESET ({ 1'b1, {(WIDTH-1){1'b0}} }),
.RESET_WIDTH (WIDTH))
sub2
( .clk(clk), .rst_l(rst_l), .q(c), .d(in) );
endmodule
module dff (/*AUTOARG*/
// Outputs
q,
// Inputs
clk, rst_l, d
);
parameter WIDTH = 1;
parameter RESET = {WIDTH{1'b0}};
parameter RESET_WIDTH = WIDTH;
input clk;
input rst_l;
input [WIDTH-1:0] d;
output reg [WIDTH-1:0] q;
always_ff @(posedge clk or negedge rst_l) begin
if ($bits(RESET) != RESET_WIDTH) $stop;
// verilator lint_off WIDTH
if (~rst_l) q <= RESET;
// verilator lint_on WIDTH
else q <= d;
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;
@@ -3,23 +3,20 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_inst(/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
clk, fastclk
);
input clk;
input fastclk;
output passed; reg passed; initial passed = 0;
genvar unused;
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire o_com; // From b of t_inst_b.v
wire o_seq_d1r; // From b of t_inst_b.v
wire o_com; // From b of t_inst_first_b.v
wire o_seq_d1r; // From b of t_inst_first_b.v
// End of automatics
integer _mode; // initial _mode=0
@@ -50,7 +47,7 @@ module t_inst(/*AUTOARG*/
wire [168:0] r_wide3 = {ra,rb,rc,rd,rd};
reg [127:0] _guard6; initial _guard6=0;
t_inst_a a (
t_inst_first_a a (
.clk (clk),
// Outputs
.o_w5 ({ma,mb,mc,md,me}),
@@ -66,19 +63,20 @@ module t_inst(/*AUTOARG*/
reg i_seq;
reg i_com;
wire [15:14] o2_comhigh;
t_inst_b b (
t_inst_first_b b (
.o2_com (o2_comhigh),
.i2_com ({i_com,~i_com}),
.wide_for_trace (128'h1234_5678_aaaa_bbbb_cccc_dddd),
.wide_for_trace_2 (_guard6 + 128'h1234_5678_aaaa_bbbb_cccc_dddd),
/*AUTOINST*/
// Outputs
.o_seq_d1r (o_seq_d1r),
.o_com (o_com),
// Inputs
.clk (clk),
.i_seq (i_seq),
.i_com (i_com));
// Outputs
.o_seq_d1r (o_seq_d1r),
.o_com (o_com),
// Inputs
.clk (clk),
.i_seq (i_seq),
.i_com (i_com));
// surefire lint_off STMINI
initial _mode = 0;
@@ -115,8 +113,8 @@ module t_inst(/*AUTOARG*/
if ({da,db,dc,dd,de} !== 5'b10110) $stop;
if (o_seq_d1r !== ~i_seq) $stop;
//
$write("[%0t] t_inst: Passed\n", $time);
passed <= 1'b1;
$write("*-* All Finished *-*\n");
$finish;
end
if (|{_guard1,_guard2,_guard3,_guard4,_guard5,_guard6}) begin
$write("Guard error %x %x %x %x %x\n",_guard1,_guard2,_guard3,_guard4,_guard5);
@@ -3,7 +3,7 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_inst_a (/*AUTOARG*/
module t_inst_first_a (/*AUTOARG*/
// Outputs
o_w5, o_w5_d1r, o_w40, o_w104,
// Inputs
@@ -3,7 +3,7 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_inst_b (/*AUTOARG*/
module t_inst_first_b (/*AUTOARG*/
// Outputs
o_seq_d1r, o_com, o2_com,
// Inputs
+2 -2
View File
@@ -11,8 +11,8 @@ compile (
verilator_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_inst_misarray_bad.v:\d+: Illegal port connection \'foo\', mismatch between port which is not an array, and expression which is an array.
%Error: Exiting due to.*',
q{%Error: t/t_inst_misarray_bad.v:\d+: Illegal input port connection 'foo', mismatch between port which is not an array, and expression which is an array.
%Error: Exiting due to.*},
);
+5 -3
View File
@@ -6,10 +6,12 @@
module t (/*AUTOARG*/);
wire ok = 1'b0;
// verilator lint_off PINNOCONNECT
sub sub (.ok(ok), .nc());
// verilator lint_off PINCONNECTEMPTY
sub sub (.ok(ok), , .nc());
// verilator lint_on PINCONNECTEMPTY
// verilator lint_on PINNOCONNECT
endmodule
module sub (input ok, input nc);
initial if (ok&&nc) begin end // No unused warning
module sub (input ok, input none, input nc);
initial if (ok && none && nc) begin end // No unused warning
endmodule
+3 -2
View File
@@ -11,9 +11,10 @@ compile (
v_flags2 => ["--lint-only --Wall -Wno-DECLFILENAME"],
fails=>1,
expect=>
q{%Warning-PINNOCONNECT: t/t_inst_missing_bad.v:\d+: Cell pin is not connected: nc
q{%Warning-PINNOCONNECT: t/t_inst_missing_bad.v:8: Cell pin is not connected: __pinNumber2
%Warning-PINNOCONNECT: Use .*
%Warning-PINMISSING: t/t_inst_missing_bad.v:\d+: Cell has missing pin: missing
%Warning-PINCONNECTEMPTY: t/t_inst_missing_bad.v:8: Cell pin connected by name with empty reference: nc
%Warning-PINMISSING: t/t_inst_missing_bad.v:8: Cell has missing pin: missing
%Error: Exiting due to.*},
);
+3 -3
View File
@@ -5,9 +5,9 @@
module t (/*AUTOARG*/);
wire ok = 1'b0;
sub sub (.ok(ok), .nc());
sub sub (.ok(ok), , .nc());
endmodule
module sub (input ok, input nc, input missing);
initial if (ok&&nc&&missing) begin end // No unused warning
module sub (input ok, input none, input nc, input missing);
initial if (ok && none && nc && missing) begin end // No unused warning
endmodule
+4 -4
View File
@@ -16,11 +16,11 @@ compile (
verilator_make_gcc=>0,
fails=>$Self->{v3},
expect=>
q{%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outy_w92 expects 92 bits but connection's VARREF 'outc_w30' generates 30 bits.
q{%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection 'outy_w92' expects 92 bits on the pin connection, but pin connection's VARREF 'outc_w30' generates 30 bits.
%Warning-WIDTH: Use .* to disable this message.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outz_w22 expects 22 bits but connection's VARREF 'outd_w73' generates 73 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inw_w31 expects 31 bits but connection's VARREF 'ina_w1' generates 1 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inx_w11 expects 11 bits but connection's VARREF 'inb_w61' generates 61 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection 'outz_w22' expects 22 bits on the pin connection, but pin connection's VARREF 'outd_w73' generates 73 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection 'inw_w31' expects 31 bits on the pin connection, but pin connection's VARREF 'ina_w1' generates 1 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection 'inx_w11' expects 11 bits on the pin connection, but pin connection's VARREF 'inb_w61' generates 61 bits.
%Error: Exiting due to.*},
);
+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;
+28
View File
@@ -0,0 +1,28 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
interface pads_if();
modport mp_dig(
import fIn,
import fOut );
integer exists[8];
function automatic integer fIn (integer i);
fIn = exists[i];
endfunction
task automatic fOut (integer i);
exists[i] = 33;
endtask
endinterface
module t();
pads_if padsif();
initial begin
padsif.fOut(3);
if (padsif.fIn(3) != 33) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+1 -1
View File
@@ -13,7 +13,7 @@ module t (/*AUTOARG*/
read r (.clk(clk), .data( ( ( oe == 1'd001 ) && implicit_write ) ) );
set s (.clk(clk), .enable(implicit_write));
set u (.clk(clk), .enable(~implicit_also));
read u (.clk(clk), .data(~implicit_also));
endmodule
+6 -1
View File
@@ -13,8 +13,13 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
q{.*%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits.
q{.*%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator VAR 'XS' expects 4 bits on the Initial value, but Initial value's CONST '\?32\?bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' generates 32 bits.
%Warning-WIDTH: Use .*
%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits.
%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator SHIFTL expects 5 bits on the LHS, but LHS's CONST '1'h1' generates 1 bits.
%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ASSIGNW expects 6 bits on the Assign RHS, but Assign RHS's SHIFTL generates 7 bits.
%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ADD expects 3 bits on the LHS, but LHS's VARREF 'one' generates 1 bits.
%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ADD expects 3 bits on the RHS, but RHS's VARREF 'one' generates 1 bits.
%Error: Exiting due to.*},
);
+20
View File
@@ -5,11 +5,31 @@
module t ();
// See also t_math_width
// This shows the uglyness in width warnings across param modules
// TODO: Would be nice to also show relevant parameter settings
p #(.WIDTH(4)) p4 (.in(4'd0));
p #(.WIDTH(5)) p5 (.in(5'd0));
//====
localparam [3:0] XS = 'hx; // User presumably intended to use 'x
//====
wire [4:0] c = 1'b1 << 2; // No width warning, as is common syntax
wire [4:0] d = (1'b1 << 2) + 5'b1; // Has warning as not obvious what expression width is
//====
localparam WIDTH = 6;
wire one_bit;
wire [2:0] shifter = 1;
wire [WIDTH-1:0] masked = (({{(WIDTH){1'b0}}, one_bit}) << shifter);
//====
// We presently warn here, in theory we could detect if the number of one bit additions could overflow the LHS
wire one = 1;
wire [2:0] cnt = (one + one + one + one);
endmodule
module p
+23
View File
@@ -42,6 +42,10 @@ module t (/*AUTOARG*/
wire one = 1'b1;
wire [5:0] rep6 = {6{one}};
// verilator lint_off WIDTH
localparam [3:0] bug764_p11 = 1'bx;
// verilator lint_on WIDTH
always @ (posedge clk) begin
if (!_ranit) begin
_ranit <= 1;
@@ -111,6 +115,25 @@ module t (/*AUTOARG*/
// Test display extraction widthing
$display("[%0t] %x %x %x(%d)", $time, shq[2:0], shq[2:0]<<2, xor3[2:0], xor3[2:0]);
// bug736
//verilator lint_off WIDTH
if ((~| 4'b0000) != 4'b0001) $stop;
if ((~| 4'b0010) != 4'b0000) $stop;
if ((~& 4'b1111) != 4'b0000) $stop;
if ((~& 4'b1101) != 4'b0001) $stop;
//verilator lint_on WIDTH
// bug764
//verilator lint_off WIDTH
// X does not sign extend
if (bug764_p11 !== 4'b000x) $stop;
if (~& bug764_p11 !== 1'b1) $stop;
//verilator lint_on WIDTH
// However IEEE says for constants in 2012 5.7.1 that smaller-sizes do extend
if (4'bx !== 4'bxxxx) $stop;
if (4'bz !== 4'bzzzz) $stop;
if (4'b1 !== 4'b0001) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
+27 -19
View File
@@ -3,6 +3,12 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005 by Wilson Snyder.
`ifdef VERILATOR
`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)
`else
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); end while(0)
`endif
module t (/*AUTOARG*/
// Inputs
clk
@@ -28,11 +34,13 @@ module t (/*AUTOARG*/
$write("%0x %x %x\n", cyc, p, shifted);
`endif
// Constant versions
if (61'h1 ** 21'h31 != 61'h1) $stop;
if (61'h2 ** 21'h10 != 61'h10000) $stop;
if (61'd10 ** 21'h3 != 61'h3e8) $stop;
if (61'h3 ** 21'h7 != 61'h88b) $stop;
if (61'h7ab3811219 ** 21'ha6e30 != 61'h01ea58c703687e81) $stop;
`checkh(61'h1 ** 21'h31, 61'h1);
`checkh(61'h2 ** 21'h10, 61'h10000);
`checkh(61'd10 ** 21'h3, 61'h3e8);
`checkh(61'h3 ** 21'h7, 61'h88b);
`ifndef VCS
`checkh(61'h7ab3811219 ** 21'ha6e30, 61'h01ea58c703687e81);
`endif
if (cyc==1) begin
a <= 61'h0;
b <= 21'h0;
@@ -71,25 +79,25 @@ module t (/*AUTOARG*/
32'd01: ;
32'd02: ; // 0^x is indeterminate
32'd03: ; // 0^x is indeterminate
32'd04: if (p!=61'h1) $stop;
32'd05: if (p!=61'h10000) $stop;
32'd06: if (p!=61'h3e8) $stop;
32'd07: if (p!=61'h88b) $stop;
32'd08: if (p!=61'h01ea58c703687e81) $stop;
32'd09: if (p!=61'h01ea58c703687e81) $stop;
32'd04: `checkh(p, 61'h1);
32'd05: `checkh(p, 61'h10000);
32'd06: `checkh(p, 61'h3e8);
32'd07: `checkh(p, 61'h88b);
32'd08: `checkh(p, 61'h01ea58c703687e81);
32'd09: `checkh(p, 61'h01ea58c703687e81);
default: $stop;
endcase
case (cyc)
32'd00: ;
32'd01: ;
32'd02: if (shifted!=61'h0000000000000001) $stop;
32'd03: if (shifted!=61'h0000000000000008) $stop;
32'd04: if (shifted!=61'h0002000000000000) $stop;
32'd05: if (shifted!=61'h0000000000010000) $stop;
32'd06: if (shifted!=61'h0000000000000008) $stop;
32'd07: if (shifted!=61'h0000000000000080) $stop;
32'd08: if (shifted!=61'h0000000000000000) $stop;
32'd09: if (shifted!=61'h0000000000000000) $stop;
32'd02: `checkh(shifted, 61'h0000000000000001);
32'd03: `checkh(shifted, 61'h0000000000000008);
32'd04: `checkh(shifted, 61'h0002000000000000);
32'd05: `checkh(shifted, 61'h0000000000010000);
32'd06: `checkh(shifted, 61'h0000000000000008);
32'd07: `checkh(shifted, 61'h0000000000000080);
32'd08: `checkh(shifted, 61'h0000000000000000);
32'd09: `checkh(shifted, 61'h0000000000000000);
default: $stop;
endcase
end
+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;
+50
View File
@@ -0,0 +1,50 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Aggregate outputs into a single result vector
//wire [31:0] pow32b = {24'h0,crc[15:8]}**crc[7:0]; // Overflows
wire [3:0] pow4b = crc[7:4]**crc[3:0];
wire [63:0] result = {60'h0, pow4b};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h1fec4b2b71cf8024
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule

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