mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b46f656d17 | ||
|
|
58fd602bbd | ||
|
|
9cc95704cd | ||
|
|
5f5a3dbb0a | ||
|
|
f8f53df4ec | ||
|
|
56b85cc63c | ||
|
|
90aca97e66 | ||
|
|
6ce2a52c5f | ||
|
|
1f56312132 | ||
|
|
3aa290cddb | ||
|
|
1d1eb4fedb | ||
|
|
266ff41386 | ||
|
|
02331e5536 | ||
|
|
621c51589a | ||
|
|
4a58e859a4 | ||
|
|
48d393d8f5 | ||
|
|
321552d998 | ||
|
|
a985a1f9f5 | ||
|
|
d532a36739 | ||
|
|
b631b5927b | ||
|
|
adb39ceb98 | ||
|
|
84b91b19ca | ||
|
|
aaea68d3d6 | ||
|
|
2accba2e71 | ||
|
|
8f4f4eb5ae | ||
|
|
c5aabb3c6e | ||
|
|
60c2d136e1 | ||
|
|
cae6ec16ba | ||
|
|
30601c77d4 | ||
|
|
b0f4cf3c9c | ||
|
|
c41dfcf6ad | ||
|
|
2e10555f03 | ||
|
|
6b2ee0fcf3 | ||
|
|
0dbdbffba7 | ||
|
|
9c5dd8d767 | ||
|
|
fff0ebb5f3 | ||
|
|
d34275150c | ||
|
|
d04eb977c2 | ||
|
|
fb4928b2f5 | ||
|
|
5c39420d91 | ||
|
|
14fcfd8a40 | ||
|
|
ff19dd94f9 | ||
|
|
b6913ff9b3 | ||
|
|
4573fd3069 | ||
|
|
6cf6d9f7e1 | ||
|
|
28e35a64ea | ||
|
|
091818483a | ||
|
|
3b43556c41 | ||
|
|
ed39c66715 | ||
|
|
446b0e4e5e | ||
|
|
6e3e8318d0 | ||
|
|
17b8b660f0 | ||
|
|
40bceea68a | ||
|
|
b655c17c09 | ||
|
|
a3813f94fc | ||
|
|
c70540a825 | ||
|
|
9caffe330b | ||
|
|
8d8c5da812 | ||
|
|
55bb766c15 | ||
|
|
c18df68ead | ||
|
|
3996e94c39 | ||
|
|
1bdf017f9e | ||
|
|
93790c1dc6 | ||
|
|
ba8c11b25d | ||
|
|
ca57edfa0b | ||
|
|
ccb6545c32 | ||
|
|
d146dbc9d7 | ||
|
|
b4eaaccc88 | ||
|
|
c9ed9e74f2 | ||
|
|
587c7c70f5 |
@@ -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
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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)
|
||||
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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() {}
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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
@@ -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
@@ -8,7 +8,7 @@ use strict;
|
||||
#======================================================================
|
||||
# main
|
||||
|
||||
eval `modulecmd perl add synopsys-vcs`;
|
||||
eval `modulecmd perl add synopsys-vcs_mx`;
|
||||
exec('vcs',@ARGV);
|
||||
|
||||
#######################################################################
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -94,9 +94,9 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
BranchVisitor(AstNetlist* rootp) {
|
||||
BranchVisitor(AstNetlist* nodep) {
|
||||
reset();
|
||||
rootp->iterateChildren(*this);
|
||||
nodep->iterateChildren(*this);
|
||||
}
|
||||
virtual ~BranchVisitor() {}
|
||||
};
|
||||
|
||||
+12
-8
@@ -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:
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
File diff suppressed because it is too large
Load Diff
+17
-7
@@ -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: ");
|
||||
|
||||
@@ -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
@@ -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
@@ -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";
|
||||
|
||||
Executable
+183
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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");
|
||||
|
||||
@@ -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 (
|
||||
);
|
||||
|
||||
|
||||
@@ -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 (
|
||||
);
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
Executable
+18
@@ -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
|
||||
|
||||
Executable
+18
@@ -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,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
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
Executable
+21
@@ -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;
|
||||
@@ -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
|
||||
@@ -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 (
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
Executable
+18
@@ -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
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
Executable
+18
@@ -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;
|
||||
@@ -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
Reference in New Issue
Block a user