Compare commits

...
61 Commits
Author SHA1 Message Date
Wilson Snyder 55f0d4ddd8 Version bump 2014-11-15 08:38:44 -05:00
Wilson Snyder 6d66fcaa57 Fix +define+A+B to define A and B to match other simulators, bug847. 2014-11-13 19:05:07 -05:00
Wilson Snyder 26e79ca889 Fix quoted comment slashes in defines, bug845. 2014-11-12 16:37:51 -05:00
Wilson Snyder 62eb247c1e Optimize SUB/ADD together. 2014-11-09 18:33:54 -05:00
Wilson Snyder c5fd583b2c Fix select when partially out-of-bound, bug823. 2014-11-09 18:29:52 -05:00
Wilson Snyder 117db3e11c Trace_off now operates on cells, bug826. 2014-11-08 14:15:10 -05:00
Wilson Snyder 3f82fd2f37 Add public enums, bug833. 2014-11-07 07:50:11 -05:00
Wilson Snyder e9c46afcf7 Fix public parameters in unused packages, bug804. 2014-11-06 17:53:01 -05:00
Wilson Snyder 3234fa15ef Fix trace overflow on huge arrays, bug834. 2014-11-05 22:22:27 -05:00
Jie Xu 7ef84df852 Add optimization of wires from arrayed cells, msg1447.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 21:09:35 -05:00
Jie Xu 4e2884b509 Optimize e.g. {(b<<4)[7:4], (b<<4)[3:0]}. From assignmerge tree.
Signed-off-by: Wilson Snyder <[email protected]>
2014-11-05 20:58:36 -05:00
Wilson Snyder 03100020ab Fix not tracing modules following primitives, bug837. 2014-11-04 07:49:03 -05:00
Wilson Snyder 8bfb5cc5e9 Internals: Add sameGateTree. 2014-11-02 19:52:49 -05:00
Wilson Snyder cf6d07aafa Add optimization of operators between concats, msg1447. 2014-10-22 21:44:41 -04:00
Wilson Snyder 85c3179dbd Commentary 2014-10-21 19:11:46 -04:00
Wilson Snyder bfbca34eb0 Fix cast-to-size context-determined sizing, bug828. 2014-10-17 19:01:04 -04:00
Wilson Snyder b73edc0564 Fix generate unrolling with function call, bug830. 2014-10-15 21:29:37 -04:00
Wilson Snyder 6ba90e3a50 devel release 2014-09-21 09:06:40 -04:00
Wilson Snyder e8edbad18c Version bump 2014-09-21 09:04:36 -04:00
Wilson Snyder c86fec5307 Fix string formats under deep expressions, bug820. 2014-09-21 08:52:09 -04:00
Wilson Snyder 6e476255ca Support power operator with real, bug809. 2014-09-21 08:24:44 -04:00
Wilson Snyder 27af9b6b06 Fix clang warnings, bug818. 2014-09-11 21:28:53 -04:00
Wilson Snyder f8208fa961 Print Aborting before aborting, bug819 2014-09-05 21:40:04 -04:00
Wilson Snyder 87b9cb49ad Fix / multi-argument ordering, bug816. 2014-09-04 22:25:19 -04:00
Wilson Snyder b2da0772e6 Commentary 2014-09-04 22:15:11 -04:00
Wilson Snyder 4f73e0850e Improve verilator_profcfunc time attributions. 2014-08-28 22:10:39 -04:00
Wilson Snyder b6a39db627 Fix optional parameter keyword in module #(), bug810. 2014-08-27 07:57:20 -04:00
Wilson Snyder 3a83b06572 Fix over-shift structure optimization error, bug803. 2014-07-28 07:31:01 -04:00
Wilson Snyder fe5bf01b25 Fix dpiGetContext in dotted scopes, bug740. 2014-07-21 20:55:52 -04:00
Wilson Snyder 5559ec903b Fix error when tracing public parameters, bug722. 2014-07-21 20:44:33 -04:00
Wilson Snyder 18750028b2 Fix mis-optimization of bit-swap in wide signal, bug800. 2014-07-04 09:13:59 -04:00
Wilson Snyder 6b88648c67 Commentary, bug799 2014-07-02 21:04:51 -04:00
Wilson Snyder 58ee803cb4 Fix test GCC warning, bug794. 2014-06-26 21:45:14 -04:00
Wilson Snyder 894ff73c7d Internals: Fix clang warning, bug791. 2014-06-19 18:02:42 -04:00
Wilson Snyder 8031f0ed7f Fix duplicate anonymous structures in , bug788. 2014-06-15 11:18:47 -04:00
Wilson Snyder 3a56b5da47 devel release 2014-06-10 20:43:10 -04:00
Wilson Snyder fedcb6d26a Version bump 2014-06-10 20:39:51 -04:00
Wilson Snyder eed3c5e543 Tests: Add t_tri_array and enable t_sv_cpu. 2014-06-10 20:02:18 -04:00
Wilson Snyder e26ab67e25 Report tristate errors closer to code which created them. 2014-06-10 19:58:51 -04:00
Wilson Snyder e77b7427b4 Fix shift corner-case, bug 774. 2014-06-10 19:13:55 -04:00
Wilson Snyder 475e4207cc Fix late constant division by zero giving X error, bug775. 2014-06-09 22:27:04 -04:00
Wilson Snyder 71b2eed32c Fix false name conflict on cells in generate blocks, bug749. 2014-06-09 22:00:45 -04:00
Wilson Snyder 6cf50e6579 Fix string corruption, bug780. 2014-06-08 21:36:18 -04:00
Wilson Snyder 69468708e2 Fix DETECTARRAY error on packed arrays, bug770. 2014-06-07 09:53:40 -04:00
Wilson Snyder 5da5678e64 Fix pattern assignment to conditionals, bug769. 2014-06-06 21:52:16 -04:00
Wilson Snyder a428e7f618 Fix pattern assignment to arrayed basic type, bug769. 2014-06-06 21:14:44 -04:00
Wilson Snyder 0eb5a0a539 Add -P to suppress `line and blanks with preprocessing, bug781. 2014-06-06 20:22:20 -04:00
Wilson Snyder a1c1ff9981 Fix seg-fault with variable of parameterized interface, bug692. 2014-05-28 07:33:40 -04:00
Wilson Snyder 2029ade18c Change SYMRSVDWORD to print as warning rather than error. 2014-05-28 07:24:02 -04:00
Wilson Snyder 5f8f474c0c Fix shift with XOR mis-optimization, bug776. 2014-05-26 18:16:52 -04:00
Wilson Snyder f705f9b275 Fix C compiler interpreting signing, bug773. 2014-05-24 08:00:01 -04:00
Wilson Snyder 91e706ec1f Fix X shift issue, bug772. 2014-05-24 07:05:23 -04:00
Wilson Snyder dcf351f847 Copyright 2014-05-20 06:12:08 -04:00
Wilson Snyder 06744b664a Fix huge shifts to zero with -Wno-WIDTH, bug768. 2014-05-16 07:09:43 -04:00
Wilson Snyder d3049d9c89 Fix huge shifts to zero with -Wno-WIDTH, bug766. 2014-05-15 21:49:43 -04:00
Wilson Snyder 1f2abb9c0f Fix gate primitives with arrays and non-arrayed pins. 2014-05-15 20:57:09 -04:00
Wilson Snyder 9f0d7e50a5 Using command line -Wno-{WARNING} now overrides file-local lint_on. 2014-05-15 20:54:45 -04:00
Wilson Snyder 5f262a8f11 Fix ENDLABEL warnings on escaped identifiers. 2014-05-15 20:52:22 -04:00
Wilson Snyder f62bc6a2e5 Support SV 2012 package import before port list. 2014-05-15 20:50:42 -04:00
Wilson Snyder d7e4bc1379 Fix huge shifts to zero with -Wno-WIDTH, bug765. 2014-05-13 08:10:59 -04:00
Wilson Snyder cd2d6575c6 devel release 2014-05-11 16:58:01 -04:00
140 changed files with 3691 additions and 717 deletions
+85
View File
@@ -3,6 +3,91 @@ 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.866 2014-11-15
*** Fix +define+A+B to define A and B to match other simulators, bug847. [Adam Krolnik]
*** Add optimization of wires from arrayed cells, msg1447. [Jie Xu]
*** Add optimization of operators between concats, msg1447. [Jie Xu]
*** Add public enums, bug833. [Jonathon Donaldson]
*** Trace_off now operates on cells, bug826. [Lane Brooks]
**** Fix public parameters in unused packages, bug804. [Jonathon Donaldson]
**** Fix select when partially out-of-bound, bug823. [Cliffort Wolf]
**** Fix generate unrolling with function call, bug830. [Steven Slatter]
**** Fix cast-to-size context-determined sizing, bug828. [Geoff Barrett]
**** Fix not tracing modules following primitives, bug837. [Jie Xu]
**** Fix trace overflow on huge arrays, bug834. [Geoff Barrett]
**** Fix quoted comment slashes in defines, bug845. [Adam Krolnik]
* Verilator 3.864 2014-09-21
*** Support power operator with real, bug809. [Jonathon Donaldson]
**** Improve verilator_profcfunc time attributions. [Jonathon Donaldson]
**** Fix duplicate anonymous structures in $root, bug788. [Bob Newgard]
**** Fix mis-optimization of bit-swap in wide signal, bug800. [Jie Xu]
**** Fix error when tracing public parameters, bug722. [Jonathon Donaldson]
**** Fix dpiGetContext in dotted scopes, bug740. [Geoff Barrett]
**** Fix over-shift structure optimization error, bug803. [Jeff Bush]
**** Fix optional parameter keyword in module #(), bug810. [Iztok Jeras]
**** Fix $warning/$error multi-argument ordering, bug816. [Jonathon Donaldson]
**** Fix clang warnings, bug818. [Iztok Jeras]
**** Fix string formats under deep expressions, bug820. [Iztok Jeras]
* Verilator 3.862 2014-06-10
*** Using command line -Wno-{WARNING} now overrides file-local lint_on.
*** Add -P to suppress `line and blanks with preprocessing, bug781. [Derek Lockhart]
*** Support SV 2012 package import before port list.
**** Change SYMRSVDWORD to print as warning rather than error.
**** Fix seg-fault with variable of parameterized interface, bug692. [Jie Xu]
**** Fix false name conflict on cells in generate blocks, bug749. [Igor Lesik]
**** Fix pattern assignment to basic types, bug767. [Jie Xu]
**** Fix pattern assignment to conditionals, bug769. [Jie Xu]
**** Fix shift corner-cases, bug765, bug766, bug768, bug772, bug774, bug776. [Clifford Wolf]
**** Fix C compiler interpreting signing, bug773. [Clifford Wolf]
**** Fix late constant division by zero giving X error, bug775. [Clifford Wolf]
**** Fix gate primitives with arrays and non-arrayed pins.
**** Fix DETECTARRAY error on packed arrays, bug770. [Jie Xu]
**** Fix ENDLABEL warnings on escaped identifiers.
**** Fix string corruption, bug780. [Derek Lockhart]
* Verilator 3.860 2014-05-11
** PSL is no longer supported, please use System Verilog assertions.
+50 -23
View File
@@ -267,7 +267,7 @@ descriptions in the next sections for more information.
--debugi <level> Enable debugging at a specified level
--debugi-<srcfile> <level> Enable debugging a source file at a level
--default-language <lang> Default language to parse
+define+<var>+<value> Set preprocessor define
+define+<var>=<value> Set preprocessor define
--dump-tree Enable dumping .tree files
--dump-treei <level> Enable dumping .tree files at a level
-E Preprocess, but do not compile
@@ -303,6 +303,7 @@ descriptions in the next sections for more information.
--output-split <bytes> Split .cpp files into pieces
--output-split-cfuncs <statements> Split .cpp functions
--output-split-ctrace <statements> Split tracing functions
-P Disable line numbers and blanks with -E
--pins-bv <bits> Specify types for top level ports
--pins-sc-uint Specify types for top level ports
--pins-sc-biguint Specify types for top level ports
@@ -571,13 +572,16 @@ the comment "DefaultClock":
=item -DI<var>=I<value>
Defines the given preprocessor symbol. Same as +define; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
Defines the given preprocessor symbol, without allowing. Similar to
+define; +define is fairly standard across Verilog tools while -D is an
alias for GCC compatibility.
=item --debug
Select the debug built image of Verilator (if available), and enable more
internal assertions, debugging messages, and intermediate form dump files.
internal assertions (equivelent to C<--debug-check>), debugging messages
(equivelent to C<--debugi 4>), and intermediate form dump files (equivilent
to C<--dump-tree>).
=item --debug-check
@@ -589,9 +593,9 @@ changing debug verbosity. Enabled automatically when --debug specified.
=item --debugi-<srcfile> <level>
Rarely needed - for developer use. Set internal debugging level globally
to the specified debug level (1-10) or set the specified source file to the
specified level. Higher levels produce more detailed messages (plain
C<--debug> is equivalent to C<--debugi 4>).
to the specified debug level (1-10) or set the specified Verilator source
file to the specified level (e.g. C<--debugi-V3Width 9>). Higher levels
produce more detailed messages.
=item --default-language I<value>
@@ -612,10 +616,13 @@ used.
If no language is specified, either by this flag or +I<lang>ext+ options,
then the latest SystemVerilog language (IEEE 1800-2012) is used.
=item +define+I<var>+I<value>
=item +define+I<var>=I<value>
Defines the given preprocessor symbol. Same as -D; +define is fairly
standard across Verilog tools while -D is an alias for GCC compatibility.
=item +define+I<var>=I<value>+I<var2>=I<value2>...
Defines the given preprocessor symbol, or multiple symbols if separated by
plusses. Similar to -D; +define is fairly standard across Verilog tools
while -D is an alias for GCC compatibility.
=item --dump-tree
@@ -781,8 +788,10 @@ Disables optimization of the model.
=item -O3
Enables slow optimizations. This may reduce simulation runtimes at the
cost of compile time. This currently sets --inline-mult -1.
Enables slow optimizations for the code Verilator itself generates (as
opposed to "-CFLAGS -O3" which effects the C compiler's optimization. -O3
may reduce simulation runtimes at the cost of compile time. This currently
sets --inline-mult -1.
=item -OI<optimization-letter>
@@ -830,6 +839,11 @@ function.
Enables splitting trace functions in the output .cpp/.sp files into
multiple functions. Defaults to same setting as --output-split-cfuncs.
=item -P
With -E, disable generation of `line markers and blank lines, similar to
GCC -P flag.
=item --pins64
Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
@@ -1088,7 +1102,8 @@ supports which the older version does not support.
=item -Wno-I<message>
Disable the specified warning message.
Disable the specified warning message. This will override any lint_on
directives in the source, i.e. the warning will still not be printed.
=item -Wno-lint
@@ -1918,6 +1933,9 @@ Disables the specified lint warning, in the specified filename (or wildcard
with '*' or '?', or all files if omitted) and range of line numbers (or all
lines if omitted).
Using '*' will override any lint_on directives in the source, i.e. the
warning will still not be printed.
If the -msg is omitted, all lint warnings are disabled. This will override
all later lint warning enables for the specified region.
@@ -2237,6 +2255,14 @@ reduce the size of the final executable when a task is used a very large
number of times. For this flag to work, the task and tasks below it must
be pure; they cannot reference any variables outside the task itself.
=item /*verilator public*/ (typedef enum)
Used after an enum typedef declaration to indicate the emitted C code
should have the enum values visible. Due to C++ language restrictions, this
may only be used on 64-bit or narrower integral enumerations.
typedef enum logic [2:0] { ZERO = 3'b0 } pub_t /*verilator public*/;
=item /*verilator public*/ (variable)
Used after an input, output, register, or wire declaration to indicate the
@@ -2324,12 +2350,14 @@ behavior. See the test_regress/t/t_dpi_display.v file for an example.
=item /*verilator tracing_off*/
Disable waveform tracing for all future signals that are declared in this
module. Often this is placed just after a primitive's module statement, so
that the entire module is not traced.
module, or cells below this module. Often this is placed just after a
primitive's module statement, so that the entire module and cells below it
are not traced.
=item /*verilator tracing_on*/
Re-enable waveform tracing for all future signals that are declared.
Re-enable waveform tracing for all future signals or cells that are
declared.
=back
@@ -2958,8 +2986,8 @@ simulators.
Warns that an `include filename specifies an absolute path. This means the
code will not work on any other system with a different file system layout.
Instead of using absolute paths, relative paths (preferably without any
directory specified whatever) should be used, and +include used on the
command line to specify the top include source directory.
directory specified whatever) should be used, and +incdir used on the
command line to specify the top include source directories.
Disabled by default as this is a code style warning; it will simulate
correctly.
@@ -3088,10 +3116,9 @@ simulators.
=item SYMRSVDWORD
Error that a symbol matches a C++ reserved word and using this as a symbol
name would result in odd C compiler errors. You may disable this error
message as you would disable warnings, but the symbol will be renamed by
Verilator to avoid the conflict.
Warning that a symbol matches a C++ reserved word and using this as a symbol
name would result in odd C compiler errors. You may disable this warning,
but the symbol will be renamed by Verilator to avoid the conflict.
=item SYNCASYNCNET
@@ -3380,7 +3407,7 @@ so your simulator shouldn't have to be -- and Verilator is closer to the
synthesis interpretation, so this is a good thing for getting working
silicon.
=item Will Verilator output remain under my own copyright?
=item Will Verilator output remain under my own license?
Yes, it's just like using GCC on your programs; this is why Verilator uses
the "GNU *Lesser* Public License Version 3" instead of the more typical
+15 -1
View File
@@ -118,6 +118,18 @@ sub profcfunc {
$groups{type}{"Common code under $design"} += $pct;
$groups{design}{$design} += $pct;
$groups{module}{$design." common code"} += $pct;
} elsif ($func =~ /^VL_[A-Z0-9_]+/
|| $func =~ /^_?vl_[a-zA-Z0-9_]+/
|| $func =~ /^verilated/i) {
$vfunc = sprintf("VLib %s", $func);
$groups{type}{'VLib'} += $pct;
$groups{design}{'VLib'} += $pct;
$groups{module}{'VLib'} += $pct;
} elsif ($func =~ /^_mcount_private/) {
$vfunc = sprintf("Prof %s", $func);
$groups{type}{'Prof'} += $pct;
$groups{design}{'Prof'} += $pct;
$groups{module}{'Prof'} += $pct;
} else {
$vfunc = sprintf("C++ %s", $func);
$groups{type}{'C++'} += $pct;
@@ -129,7 +141,7 @@ sub profcfunc {
}
foreach my $type qw(type design module) {
foreach my $type (qw(type design module)) {
my $missing = 100;
foreach (sort (keys %{$groups{$type}})) {
$missing -= $groups{$type}{$_};
@@ -150,8 +162,10 @@ sub profcfunc {
print("Verilog code profile:\n");
print(" These are split into three categories:\n");
print(" C++: Time in non-Verilated C++ code\n");
print(" Prof: Time in profile overhead\n");
print(" VBlock: Time attributable to a block in a Verilog file and line\n");
print(" VCommon: Time in a Verilated module, due to all parts of the design\n");
print(" VLib: Time in Verilated common libraries, called by the Verilated code\n");
print("\n");
print(" % cumulative self \n");
+4 -2
View File
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
AC_INIT([Verilator],[3.860 2014-05-11])
AC_INIT([Verilator],[3.866 2014-11-15])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
@@ -122,15 +122,17 @@ AC_DEFUN([_MY_CXX_CHECK_OPT],
# For example, -Wno-div-by-zero isn't in 4.1.2
_MY_CXX_CHECK_OPT(-Wno-char-subscripts)
_MY_CXX_CHECK_OPT(-Wno-parentheses-equality)
# Random code often does / 0. Unfortunately VL_DIV_I(0,0) will warn
# without this flag, even though there's a conditional to prevent the divide.
# We still don't add no-div-by-zero as it throws message to stdout, though doesn't die.
#_MY_CXX_CHECK_OPT(-Wno-div-by-zero)
_MY_CXX_CHECK_OPT(-Wno-sign-compare)
_MY_CXX_CHECK_OPT(-Wno-uninitialized)
_MY_CXX_CHECK_OPT(-Wno-unused-but-set-variable)
_MY_CXX_CHECK_OPT(-Wno-unused-parameter)
_MY_CXX_CHECK_OPT(-Wno-unused-variable)
_MY_CXX_CHECK_OPT(-Wno-unused-but-set-variable)
_MY_CXX_CHECK_OPT(-fbracket-depth=4096)
AC_SUBST(CFG_CXXFLAGS_NO_UNUSED)
# Checks for library functions.
+6 -3
View File
@@ -74,6 +74,9 @@ void vl_fatal (const char* filename, int linenum, const char* hier, const char*
Verilated::gotFinish(true);
VL_PRINTF("%%Error: %s:%d: %s\n", filename, linenum, msg);
Verilated::flushCall();
VL_PRINTF("Aborting...\n");
Verilated::flushCall(); // Second flush in case VL_PRINTF does something needing a flush
abort();
}
#endif
@@ -1250,9 +1253,9 @@ void VerilatedScope::scopeDump() const {
m_callbacksp[i], VerilatedImp::exportName(i));
}
}
if (varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp()->begin();
it != varsp()->end(); ++it) {
if (VerilatedVarNameMap* varsp = this->varsp()) {
for (VerilatedVarNameMap::const_iterator it = varsp->begin();
it != varsp->end(); ++it) {
VL_PRINTF(" VAR %p: %s\n", &(it->second), it->first);
}
}
+5 -5
View File
@@ -1458,7 +1458,7 @@ static inline QData VL_STREAML_QQI(int, int lbits, int, QData ld, IData rd) {
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;
int ssize = (rd < (IData)lbits) ? rd : ((IData)lbits);
for (int istart=0; istart<lbits; istart+=rd) {
int ostart=lbits-rd-istart;
ostart = ostart > 0 ? ostart : 0;
@@ -1558,7 +1558,7 @@ static inline void _VL_SHIFTL_INPLACE_W(int obits,WDataOutP iowp,IData rd/*1 or
static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) {
int word_shift = VL_BITWORD_I(rd);
int bit_shift = VL_BITBIT_I(rd);
if ((int)rd >= obits) {
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (<<0,<<32,<<64 etc)
for (int i=0; i < word_shift; i++) owp[i] = 0;
@@ -1576,7 +1576,7 @@ static inline WDataOutP VL_SHIFTL_WWI(int obits,int,int,WDataOutP owp,WDataInP l
static inline WDataOutP VL_SHIFTR_WWI(int obits,int,int,WDataOutP owp,WDataInP lwp, IData rd) {
int word_shift = VL_BITWORD_I(rd); // Maybe 0
int bit_shift = VL_BITBIT_I(rd);
if ((int)rd >= obits) {
if (rd >= (IData)obits) { // rd may be huge with MSB set
for (int i=0; i < VL_WORDS_I(obits); i++) owp[i] = 0;
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
int copy_words = (VL_WORDS_I(obits)-word_shift);
@@ -1622,7 +1622,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
int bit_shift = VL_BITBIT_I(rd);
int lmsw = VL_WORDS_I(obits)-1;
IData sign = VL_SIGNONES_I(lbits,lwp[lmsw]);
if ((int)rd >= obits) { // Shifting past end, sign in all of lbits
if (rd >= (IData)obits) { // Shifting past end, sign in all of lbits
for (int i=0; i <= lmsw; i++) owp[i] = sign;
owp[lmsw] &= VL_MASK_I(lbits);
} else if (bit_shift==0) { // Aligned word shift (>>0,>>32,>>64 etc)
@@ -1661,7 +1661,7 @@ static inline WDataOutP VL_SHIFTRS_WWI(int obits,int lbits,int,WDataOutP owp,WDa
static inline IData VL_BITSEL_IWII(int, int lbits, int, int, WDataInP lwp, IData rd) {
int word = VL_BITWORD_I(rd);
if (VL_UNLIKELY((int)rd>lbits)) {
if (VL_UNLIKELY(rd>(IData)lbits)) {
return ~0; // Spec says you can go outside the range of a array. Don't coredump if so.
// We return all 1's as that's more likely to find bugs (?) than 0's.
} else {
+3 -2
View File
@@ -43,14 +43,14 @@ VK_CPPFLAGS_ALWAYS += \
-DVL_PRINTF=printf \
-DVM_TRACE=$(VM_TRACE) \
-DVM_COVERAGE=$(VM_COVERAGE) \
$(CFG_CXXFLAGS_NO_UNUSED) \
ifeq ($(CFG_WITH_CCWARN),yes) # Local... Else don't burden users
VK_CPPFLAGS_WALL += -Wall \
$(CFG_CXXFLAGS_NO_UNUSED) \
-Werror
endif
CPPFLAGS += -I. $(VK_CPPFLAGS_ALWAYS) $(VK_CPPFLAGS_WALL)
CPPFLAGS += -I. $(VK_CPPFLAGS_WALL) $(VK_CPPFLAGS_ALWAYS)
VPATH += ..
VPATH += $(VERILATOR_ROOT)/include
@@ -195,6 +195,7 @@ debug-make::
@echo VM_SUPPORT_SLOW: $(VM_SUPPORT_SLOW)
@echo VM_GLOBAL_FAST: $(VM_GLOBAL_FAST)
@echo VM_GLOBAL_SLOW: $(VM_GLOBAL_SLOW)
@echo CPPFLAGS: $(CPPFLAGS)
@echo
######################################################################
+6 -3
View File
@@ -62,8 +62,9 @@ bool VerilatedDeserialize::readDiffers (const void* __restrict datap, size_t siz
VerilatedDeserialize& VerilatedDeserialize::readAssert (const void* __restrict datap, size_t size) {
if (VL_UNLIKELY(readDiffers(datap,size))) {
string fn = filename();
string msg = (string)"Can't deserialize save-restore file as was made from different model";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
return *this; // For function chaining
@@ -82,8 +83,9 @@ void VerilatedSerialize::header() {
void VerilatedDeserialize::header() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_HEADER_STR, strlen(VLTSAVE_HEADER_STR)))) {
string fn = filename();
string msg = (string)"Can't deserialize; file has wrong header signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
os.read(Verilated::serializedPtr(), Verilated::serializedSize());
@@ -98,8 +100,9 @@ void VerilatedSerialize::trailer() {
void VerilatedDeserialize::trailer() {
VerilatedDeserialize& os = *this; // So can cut and paste standard >> code below
if (VL_UNLIKELY(os.readDiffers(VLTSAVE_TRAILER_STR, strlen(VLTSAVE_TRAILER_STR)))) {
string fn = filename();
string msg = (string)"Can't deserialize; file has wrong end-of-file signature";
vl_fatal(filename().c_str(), 0, "", msg.c_str());
vl_fatal(fn.c_str(), 0, "", msg.c_str());
close();
}
}
+28 -9
View File
@@ -172,8 +172,8 @@ void VerilatedVcd::makeNameMap() {
// This comes from user instantiations with no name - IE Vtop("").
bool nullScope = false;
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
const char* hiername = (*it).first.c_str();
if (hiername[0] == '\t') nullScope=true;
const string& hiername = it->first;
if (hiername.size() >= 1 && hiername[0] == '\t') nullScope=true;
}
if (nullScope) {
NameMap* newmapp = new NameMap;
@@ -261,6 +261,20 @@ void VerilatedVcd::printTime (vluint64_t timeui) {
printQuad(timeui);
}
void VerilatedVcd::bufferResize(vluint64_t minsize) {
// minsize is size of largest write. We buffer at least 8 times as much data,
// writing when we are 3/4 full (with thus 2*minsize remaining free)
if (VL_UNLIKELY(minsize > m_wrChunkSize)) {
char* oldbufp = m_wrBufp;
m_wrChunkSize = minsize*2;
m_wrBufp = new char [m_wrChunkSize * 8];
memcpy(m_wrBufp, oldbufp, m_writep - oldbufp);
m_writep = m_wrBufp + (m_writep - oldbufp);
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
delete oldbufp; oldbufp=NULL;
}
}
void VerilatedVcd::bufferFlush () {
// We add output data to m_writep.
// When it gets nearly full we dump it using this routine which calls write()
@@ -352,7 +366,8 @@ void VerilatedVcd::dumpHeader () {
printStr("$date "); printStr(ctime(&time_str)); printStr(" $end\n");
printStr("$timescale ");
printStr(doubleToTimescale(m_timeRes).c_str());
const string& timeResStr = doubleToTimescale(m_timeRes);
printStr(timeResStr.c_str());
printStr(" $end\n");
makeNameMap();
@@ -370,10 +385,11 @@ void VerilatedVcd::dumpHeader () {
// Print the signal names
const char* lastName = "";
for (NameMap::iterator it=m_namemapp->begin(); it!=m_namemapp->end(); ++it) {
const char* hiername = (*it).first.c_str();
const char* decl = (*it).second.c_str();
const string& hiernamestr = it->first;
const string& decl = it->second;
// Determine difference between the old and new names
const char* hiername = hiernamestr.c_str();
const char* lp = lastName;
const char* np = hiername;
lastName = hiername;
@@ -408,7 +424,7 @@ void VerilatedVcd::dumpHeader () {
}
printIndent(0);
printStr(decl);
printStr(decl.c_str());
}
while (m_modDepth>1) {
@@ -442,6 +458,9 @@ void VerilatedVcd::declare (vluint32_t code, const char* name, const char* wirep
m_sigs.reserve(m_nextCode*2); // Power-of-2 allocation speeds things up
}
// Make sure write buffer is large enough (one character per bit), plus header
bufferResize(bits+1024);
// Save declaration info
VerilatedVcdSig sig = VerilatedVcdSig(code, bits);
m_sigs.push_back(sig);
@@ -520,7 +539,7 @@ void VerilatedVcd::declDouble (vluint32_t code, const char* name, int arraynum
void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
(*((double*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
@@ -528,7 +547,7 @@ void VerilatedVcd::fullDouble (vluint32_t code, const double newval) {
}
void VerilatedVcd::fullFloat (vluint32_t code, const float newval) {
(*((float*)&m_sigs_oldvalp[code])) = newval;
// Buffer can't overflow; we have at least bufferInsertSize() bytes (>>>16 bytes)
// Buffer can't overflow before sprintf; we sized during declaration
sprintf(m_writep, "r%.16g", (double)newval);
m_writep += strlen(m_writep);
*m_writep++=' '; printCode(code); *m_writep++='\n';
@@ -701,5 +720,5 @@ main() {
//********************************************************************
// Local Variables:
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && g++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// compile-command: "mkdir -p ../test_dir && cd ../test_dir && c++ -DVERILATED_VCD_TEST ../src/verilated_vcd_c.cpp -o verilated_vcd_c && ./verilated_vcd_c && cat test.vcd"
// End:
+10 -7
View File
@@ -77,7 +77,9 @@ private:
vluint64_t m_timeLastDump; ///< Last time we did a dump
char* m_wrBufp; ///< Output buffer
char* m_wrFlushp; ///< Output buffer flush trigger location
char* m_writep; ///< Write pointer into output buffer
vluint64_t m_wrChunkSize; ///< Output buffer size
vluint64_t m_wroteBytes; ///< Number of bytes written to this file
vluint32_t* m_sigs_oldvalp; ///< Pointer to old signal values
@@ -87,13 +89,12 @@ private:
NameMap* m_namemapp; ///< List of names for the header
static vector<VerilatedVcd*> s_vcdVecp; ///< List of all created traces
inline static size_t bufferSize() { return 256*1024; } // See below for slack calculation
inline static size_t bufferInsertSize() { return 16*1024; }
void bufferResize(vluint64_t minsize);
void bufferFlush();
void bufferCheck() {
inline void bufferCheck() {
// Flush the write buffer if there's not enough space left for new information
// We only call this once per vector, so we need enough slop for a very wide "b###" line
if (VL_UNLIKELY(m_writep > (m_wrBufp+(bufferSize()-bufferInsertSize())))) {
if (VL_UNLIKELY(m_writep > m_wrFlushp)) {
bufferFlush();
}
}
@@ -135,17 +136,19 @@ protected:
public:
// CREATORS
VerilatedVcd () : m_isOpen(false), m_rolloverMB(0), m_modDepth(0), m_nextCode(1) {
m_wrBufp = new char [bufferSize()];
m_writep = m_wrBufp;
m_namemapp = NULL;
m_timeRes = m_timeUnit = 1e-9;
m_timeLastDump = 0;
m_sigs_oldvalp = NULL;
m_evcd = false;
m_scopeEscape = '.'; // Backward compatibility
m_wroteBytes = 0;
m_fd = 0;
m_fullDump = true;
m_wrChunkSize = 8*1024;
m_wrBufp = new char [m_wrChunkSize*8];
m_wrFlushp = m_wrBufp + m_wrChunkSize * 6;
m_writep = m_wrBufp;
m_wroteBytes = 0;
}
~VerilatedVcd();
+19 -26
View File
@@ -97,8 +97,8 @@ public:
virtual const char* fullname() { return "<null>"; }
virtual const char* defname() { return "<null>"; }
virtual const vluint32_t type() { return 0; }
virtual const vluint32_t size() { return 0; }
virtual const VerilatedRange* rangep() { return 0; }
virtual const vluint32_t size() const { return 0; }
virtual const VerilatedRange* rangep() const { return NULL; }
virtual vpiHandle dovpi_scan() { return 0; }
};
@@ -136,7 +136,7 @@ public:
class VerilatedVpioRange : public VerilatedVpio {
const VerilatedRange* m_range;
bool m_iteration;
vlsint32_t m_iteration;
public:
VerilatedVpioRange(const VerilatedRange* range) : m_range(range), m_iteration(0) {}
virtual ~VerilatedVpioRange() {}
@@ -182,7 +182,7 @@ class VerilatedVpioVar : public VerilatedVpio {
protected:
void* m_varDatap; // varp()->datap() adjusted for array entries
vlsint32_t m_index;
const VerilatedRange& get_range() {
const VerilatedRange& get_range() const {
// Determine number of dimensions and return outermost
return (m_varp->dims()>1) ? m_varp->array() : m_varp->range();
}
@@ -208,8 +208,8 @@ public:
if (varp()->vldir() != vpiNoDirection) return vpiPort;
return (varp()->dims()>1) ? vpiMemory : vpiReg; /* but might be wire, logic */
}
virtual const vluint32_t size() { return get_range().elements(); }
virtual const VerilatedRange* rangep() { return &get_range(); }
virtual const vluint32_t size() const { return get_range().elements(); }
virtual const VerilatedRange* rangep() const { return &get_range(); }
virtual const char* name() { return m_varp->name(); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
@@ -237,8 +237,8 @@ public:
virtual ~VerilatedVpioMemoryWord() {}
static inline VerilatedVpioMemoryWord* castp(vpiHandle h) { return dynamic_cast<VerilatedVpioMemoryWord*>((VerilatedVpio*)h); }
virtual const vluint32_t type() { return vpiMemoryWord; }
virtual const vluint32_t size() { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() { return &(varp()->range()); }
virtual const vluint32_t size() const { return varp()->range().elements(); }
virtual const VerilatedRange* rangep() const { return &(varp()->range()); }
virtual const char* fullname() {
VL_STATIC_OR_THREAD string out;
char num[20]; sprintf(num,"%d",m_index);
@@ -259,10 +259,11 @@ public:
virtual const vluint32_t type() { return vpiIterator; }
virtual vpiHandle dovpi_scan() {
if (VL_LIKELY(m_scopep->varsp())) {
if (VL_UNLIKELY(!m_started)) { m_it = m_scopep->varsp()->begin(); m_started=true; }
else if (VL_UNLIKELY(m_it == m_scopep->varsp()->end())) return 0;
VerilatedVarNameMap* varsp = m_scopep->varsp();
if (VL_UNLIKELY(!m_started)) { m_it = varsp->begin(); m_started=true; }
else if (VL_UNLIKELY(m_it == varsp->end())) return 0;
else ++m_it;
if (m_it == m_scopep->varsp()->end()) return 0;
if (m_it == varsp->end()) return 0;
return ((new VerilatedVpioVar(&(m_it->second), m_scopep))
->castVpiHandle());
} else {
@@ -430,15 +431,10 @@ class VerilatedVpiError {
t_vpi_error_info m_errorInfo;
bool m_flag;
char m_buff[VL_VPI_LINE_SIZE];
void setError(PLI_BYTE8 *message, PLI_BYTE8 *file, PLI_INT32 line) {
void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) {
m_errorInfo.message = message;
m_errorInfo.file = file;
m_errorInfo.line = line;
m_errorInfo.code = NULL;
do_callbacks();
}
void setError(PLI_BYTE8 *message, PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line) {
setError( message, file, line);
m_errorInfo.code = code;
do_callbacks();
}
@@ -464,14 +460,11 @@ public:
return this;
}
void setMessage(string file, PLI_INT32 line, string message, ...) {
static VL_THREAD string filehold;
_VL_VPI_ERROR_SET;
m_errorInfo.state = vpiPLI;
setError((PLI_BYTE8*)m_buff, (PLI_BYTE8*)file.c_str(), line);
}
void setMessage(PLI_BYTE8 *code, PLI_BYTE8 *file, PLI_INT32 line, string message, ...) {
_VL_VPI_ERROR_SET;
m_errorInfo.state = vpiPLI;
setError((PLI_BYTE8*)message.c_str(), code, file, line);
filehold = file;
setError((PLI_BYTE8*)m_buff, NULL, (PLI_BYTE8*)filehold.c_str(), line);
}
p_vpi_error_info getError() {
if (m_flag) return &m_errorInfo;
@@ -926,9 +919,9 @@ void vpi_get_value(vpiHandle object, p_vpi_value value_p) {
value_p->value.str = outStr;
switch (vop->varp()->vltype()) {
// outStrSz does not include NULL termination so add one
case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned int)*((CData*)(vop->varDatap()))); return;
case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned int)*((SData*)(vop->varDatap()))); return;
case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int)*((IData*)(vop->varDatap()))); return;
case VLVT_UINT8 : snprintf(outStr, outStrSz+1, "%hhu", (unsigned char )*((CData*)(vop->varDatap()))); return;
case VLVT_UINT16: snprintf(outStr, outStrSz+1, "%hu", (unsigned short)*((SData*)(vop->varDatap()))); return;
case VLVT_UINT32: snprintf(outStr, outStrSz+1, "%u", (unsigned int )*((IData*)(vop->varDatap()))); return;
case VLVT_UINT64: snprintf(outStr, outStrSz+1, "%llu", (unsigned long long)*((QData*)(vop->varDatap()))); return;
default:
strcpy(outStr, "-1");
+6 -3
View File
@@ -61,10 +61,13 @@ private:
void replaceDisplay(AstDisplay* nodep, const string& prefix) {
nodep->displayType(AstDisplayType::DT_WRITE);
nodep->fmtp()->text(assertDisplayMessage(nodep, prefix, nodep->fmtp()->text()));
AstNode* timesp = nodep->fmtp()->exprsp(); if (timesp) timesp->unlinkFrBack();
// cppcheck-suppress nullPointer
timesp = timesp->addNext(new AstTime(nodep->fileline()));
nodep->fmtp()->exprsp(timesp);
AstNode* timenewp = new AstTime(nodep->fileline());
if (AstNode* timesp = nodep->fmtp()->exprsp()) {
timesp->unlinkFrBackWithNext();
timenewp->addNext(timesp);
}
nodep->fmtp()->exprsp(timenewp);
if (!nodep->fmtp()->scopeNamep() && nodep->fmtp()->formatScopeTracking()) {
nodep->fmtp()->scopeNamep(new AstScopeName(nodep->fileline()));
}
+10 -13
View File
@@ -884,24 +884,21 @@ void AstNode::cloneRelinkTree() {
//======================================================================
// Comparison
bool AstNode::sameTree(AstNode* node2p) {
return sameTreeIter(node2p, true);
}
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext) {
bool AstNode::sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly) {
// Return true if the two trees are identical
if (this==NULL && node2p==NULL) return true;
if (this==NULL || node2p==NULL) return false;
if (this->type() != node2p->type()
|| this->dtypep() != node2p->dtypep()
|| !this->same(node2p)) {
|| !this->same(node2p)
|| (gateOnly && !this->isGateOptimizable())) {
return false;
}
return (this->op1p()->sameTreeIter(node2p->op1p(),false)
&& this->op2p()->sameTreeIter(node2p->op2p(),false)
&& this->op3p()->sameTreeIter(node2p->op3p(),false)
&& this->op4p()->sameTreeIter(node2p->op4p(),false)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false))
return (this->op1p()->sameTreeIter(node2p->op1p(),false,gateOnly)
&& this->op2p()->sameTreeIter(node2p->op2p(),false,gateOnly)
&& this->op3p()->sameTreeIter(node2p->op3p(),false,gateOnly)
&& this->op4p()->sameTreeIter(node2p->op4p(),false,gateOnly)
&& (ignNext || this->nextp()->sameTreeIter(node2p->nextp(),false,gateOnly))
);
}
@@ -915,8 +912,8 @@ ostream& operator<<(ostream& os, V3Hash rhs) {
V3Hash::V3Hash(const string& name) {
uint32_t val = 0;
for (const char* c=name.c_str(); *c; c++) {
val = val*31 + *c;
for (string::const_iterator it = name.begin(); it!=name.end(); ++it) {
val = val*31 + *it;
}
setBoth(1,val);
}
+55 -28
View File
@@ -236,6 +236,8 @@ public:
DIM_SIZE, // V3Width processes
DIM_UNPK_DIMENSIONS, // V3Width converts to constant
//
DT_PUBLIC, // V3LinkParse moves to AstTypedef::attrPublic
//
MEMBER_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
@@ -255,6 +257,7 @@ public:
"%E-AT",
"DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
"DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
"DT_PUBLIC",
"MEMBER_BASE",
"VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
"VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
@@ -932,7 +935,7 @@ class AstNode {
AstNode* cloneTreeIterList();
void checkTreeIter(AstNode* backp);
void checkTreeIterList(AstNode* backp);
bool sameTreeIter(AstNode* node2p, bool ignNext);
bool sameTreeIter(AstNode* node2p, bool ignNext, bool gateOnly);
void deleteTreeIter();
void deleteNode();
static void relinkOneLink(AstNode*& pointpr, AstNode* newp);
@@ -1158,6 +1161,7 @@ public:
// METHODS - Iterate on a tree
AstNode* cloneTree(bool cloneNextLink);
bool sameTree(AstNode* node2p); // Does tree of this == node2p?
bool sameGateTree(AstNode* node2p); // Does tree of this == node2p?, not allowing non-isGateOptimizable
void deleteTree(); // Always deletes the next link
void checkTree(); // User Interface version
void checkIter() const;
@@ -1216,8 +1220,9 @@ inline void AstNRelinker::relink(AstNode* newp) { newp->AstNode::relink(this); }
virtual ~Ast ##name() {} \
Ast ##name * cloneTree(bool cloneNext) { return AstNode::cloneTree(cloneNext)->cast ##name(); }
struct AstNodeMath : public AstNode {
class AstNodeMath : public AstNode {
// Math -- anything that's part of an expression tree
public:
AstNodeMath(FileLine* fl)
: AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeMath)
@@ -1232,8 +1237,9 @@ struct AstNodeMath : public AstNode {
bool isOpaque() { return castCvtPackString()!=NULL; }
};
struct AstNodeTermop : public AstNodeMath {
class AstNodeTermop : public AstNodeMath {
// Terminal operator -- a operator with no "inputs"
public:
AstNodeTermop(FileLine* fl)
: AstNodeMath(fl) {}
ASTNODE_BASE_FUNCS(NodeTermop)
@@ -1243,8 +1249,9 @@ struct AstNodeTermop : public AstNodeMath {
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
};
struct AstNodeUniop : public AstNodeMath {
class AstNodeUniop : public AstNodeMath {
// Unary math
public:
AstNodeUniop(FileLine* fl, AstNode* lhsp)
: AstNodeMath(fl) {
dtypeFrom(lhsp);
@@ -1263,8 +1270,9 @@ struct AstNodeUniop : public AstNodeMath {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeBiop : public AstNodeMath {
class AstNodeBiop : public AstNodeMath {
// Binary math
public:
AstNodeBiop(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeMath(fl) {
setOp1p(lhs); setOp2p(rhs); }
@@ -1286,8 +1294,9 @@ struct AstNodeBiop : public AstNodeMath {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeTriop : public AstNodeMath {
class AstNodeTriop : public AstNodeMath {
// Trinary math
public:
AstNodeTriop(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNodeMath(fl) {
setOp1p(lhs); setOp2p(rhs); setOp3p(ths); }
@@ -1311,20 +1320,23 @@ struct AstNodeTriop : public AstNodeMath {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeBiCom : public AstNodeBiop {
class AstNodeBiCom : public AstNodeBiop {
// Binary math with commutative properties
public:
AstNodeBiCom(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiop(fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiCom)
};
struct AstNodeBiComAsv : public AstNodeBiCom {
class AstNodeBiComAsv : public AstNodeBiCom {
// Binary math with commutative & associative properties
public:
AstNodeBiComAsv(FileLine* fl, AstNode* lhs, AstNode* rhs)
: AstNodeBiCom(fl, lhs, rhs) {}
ASTNODE_BASE_FUNCS(NodeBiComAsv)
};
struct AstNodeCond : public AstNodeTriop {
class AstNodeCond : public AstNodeTriop {
public:
AstNodeCond(FileLine* fl, AstNode* condp, AstNode* expr1p, AstNode* expr2p)
: AstNodeTriop(fl, condp, expr1p, expr2p) {
if (expr1p) dtypeFrom(expr1p);
@@ -1346,8 +1358,9 @@ struct AstNodeCond : public AstNodeTriop {
virtual int instrCount() const { return instrCountBranch(); }
};
struct AstNodePreSel : public AstNode {
class AstNodePreSel : public AstNode {
// Something that becomes an AstSel
public:
AstNodePreSel(FileLine* fl, AstNode* lhs, AstNode* rhs, AstNode* ths)
: AstNode(fl) {
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
@@ -1366,8 +1379,9 @@ struct AstNodePreSel : public AstNode {
virtual bool same(AstNode*) const { return true; }
};
struct AstNodeStmt : public AstNode {
class AstNodeStmt : public AstNode {
// Statement -- anything that's directly under a function
public:
AstNodeStmt(FileLine* fl)
: AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeStmt)
@@ -1376,7 +1390,8 @@ struct AstNodeStmt : public AstNode {
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
};
struct AstNodeAssign : public AstNodeStmt {
class AstNodeAssign : public AstNodeStmt {
public:
AstNodeAssign(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
: AstNodeStmt(fl) {
setOp1p(rhsp); setOp2p(lhsp);
@@ -1397,7 +1412,8 @@ struct AstNodeAssign : public AstNodeStmt {
virtual string verilogKwd() const { return "="; }
};
struct AstNodeFor : public AstNodeStmt {
class AstNodeFor : public AstNodeStmt {
public:
AstNodeFor(FileLine* fileline, AstNode* initsp, AstNode* condp,
AstNode* incsp, AstNode* bodysp)
: AstNodeStmt(fileline) {
@@ -1414,7 +1430,7 @@ struct AstNodeFor : public AstNodeStmt {
virtual bool same(AstNode* samep) const { return true; }
};
struct AstNodeIf : public AstNodeStmt {
class AstNodeIf : public AstNodeStmt {
private:
AstBranchPred m_branchPred; // Branch prediction as taken/untaken?
public:
@@ -1438,7 +1454,8 @@ public:
AstBranchPred branchPred() const { return m_branchPred; }
};
struct AstNodeCase : public AstNodeStmt {
class AstNodeCase : public AstNodeStmt {
public:
AstNodeCase(FileLine* fl, AstNode* exprp, AstNode* casesp)
: AstNodeStmt(fl) {
setOp1p(exprp); addNOp2p(casesp);
@@ -1452,8 +1469,9 @@ struct AstNodeCase : public AstNodeStmt {
void addNotParallelp(AstNode* nodep) { setOp3p(nodep); }
};
struct AstNodeSenItem : public AstNode {
class AstNodeSenItem : public AstNode {
// An AstSenItem or AstSenGate
public:
AstNodeSenItem(FileLine* fl) : AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeSenItem)
virtual bool isClocked() const = 0;
@@ -1511,7 +1529,7 @@ public:
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL) { }
};
struct AstNodeText : public AstNode {
class AstNodeText : public AstNode {
private:
string m_text;
public:
@@ -1528,11 +1546,11 @@ public:
const string& text() const { return m_text; }
};
struct AstNodeDType : public AstNode {
private:
class AstNodeDType : public AstNode {
// Ideally width() would migrate to BasicDType as that's where it makes sense,
// but it's currently so prevalent in the code we leave it here.
// Note the below members are included in AstTypeTable::Key lookups
private:
int m_width; // (also in AstTypeTable::Key) Bit width of operation
int m_widthMin; // (also in AstTypeTable::Key) If unsized, bitwidth of minimum implementation
AstNumeric m_numeric; // (also in AstTypeTable::Key) Node is signed
@@ -1550,8 +1568,9 @@ public:
virtual void dumpSmall(ostream& str);
virtual bool hasDType() const { return true; }
virtual AstBasicDType* basicp() const = 0; // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs to next non-typeref type
virtual AstNodeDType* skipRefp() const = 0; // recurses over typedefs/const/enum to next non-typeref type
virtual AstNodeDType* skipRefToConstp() const = 0; // recurses over typedefs to next non-typeref-or-const type
virtual AstNodeDType* skipRefToEnump() const = 0; // recurses over typedefs/const to next non-typeref-or-enum/struct type
virtual int widthAlignBytes() const = 0; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const = 0; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
virtual bool maybePointedTo() const { return true; }
@@ -1581,7 +1600,7 @@ public:
static int uniqueNumInc() { return ++s_uniqueNum; }
};
struct AstNodeClassDType : public AstNodeDType {
class AstNodeClassDType : public AstNodeDType {
private:
// TYPES
typedef map<string,AstMemberDType*> MemberNameMap;
@@ -1602,6 +1621,7 @@ public:
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const; // (Slow) recurses - Structure alignment 1,2,4 or 8 bytes (arrays affect this)
virtual int widthTotalBytes() const; // (Slow) recurses - Width in bytes rounding up 1,2,4,8,12,...
// op1 = members
@@ -1620,7 +1640,7 @@ public:
VNumRange declRange() const { return VNumRange(msb(), lsb(), false); }
};
struct AstNodeArrayDType : public AstNodeDType {
class AstNodeArrayDType : public AstNodeDType {
// Array data type, ie "some_dtype var_name [2:0]"
// Children: DTYPE (moved to refDTypep() in V3Width)
// Children: RANGE (array bounds)
@@ -1658,6 +1678,7 @@ public:
virtual AstBasicDType* basicp() const { return subDTypep()->basicp(); } // (Slow) recurse down to find basic data type
virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToConstp() const { return (AstNodeDType*)this; }
virtual AstNodeDType* skipRefToEnump() const { return (AstNodeDType*)this; }
virtual int widthAlignBytes() const { return subDTypep()->widthAlignBytes(); }
virtual int widthTotalBytes() const { return elementsConst() * subDTypep()->widthTotalBytes(); }
int msb() const;
@@ -1666,8 +1687,9 @@ public:
VNumRange declRange() const;
};
struct AstNodeSel : public AstNodeBiop {
class AstNodeSel : public AstNodeBiop {
// Single bit range extraction, perhaps with non-constant selection or array selection
public:
AstNodeSel(FileLine* fl, AstNode* fromp, AstNode* bitp)
:AstNodeBiop(fl, fromp, bitp) {}
ASTNODE_BASE_FUNCS(NodeSel)
@@ -1679,8 +1701,9 @@ struct AstNodeSel : public AstNodeBiop {
virtual bool hasDType() const { return true; }
};
struct AstNodeStream : public AstNodeBiop {
class AstNodeStream : public AstNodeBiop {
// Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
public:
AstNodeStream(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
if (lhsp->dtypep()) {
dtypeSetLogicSized(lhsp->dtypep()->width(), lhsp->dtypep()->width(), AstNumeric::UNSIGNED);
@@ -1692,7 +1715,7 @@ struct AstNodeStream : public AstNodeBiop {
//######################################################################
// Tasks/functions common handling
struct AstNodeFTask : public AstNode {
class AstNodeFTask : public AstNode {
private:
string m_name; // Name of task
string m_cname; // Name of task if DPI import
@@ -1750,7 +1773,7 @@ public:
bool pure() const { return m_pure; }
};
struct AstNodeFTaskRef : public AstNode {
class AstNodeFTaskRef : public AstNode {
// A reference to a task (or function)
private:
AstNodeFTask* m_taskp; // [AfterLink] Pointer to task referenced
@@ -1796,7 +1819,7 @@ public:
void scopeNamep(AstNode* nodep) { setNOp3p(nodep); }
};
struct AstNodeModule : public AstNode {
class AstNodeModule : public AstNode {
// A module, package, program or interface declaration;
// something that can live directly under the TOP,
// excluding $unit package stuff
@@ -1810,12 +1833,13 @@ private:
bool m_internal:1; // Internally created
int m_level; // 1=top module, 2=cell off top module, ...
int m_varNum; // Incrementing variable number
int m_typeNum; // Incrementing implicit type number
public:
AstNodeModule(FileLine* fl, const string& name)
: AstNode (fl)
,m_name(name), m_origName(name)
,m_modPublic(false), m_modTrace(false), m_inLibrary(false), m_dead(false), m_internal(false)
,m_level(0), m_varNum(0) { }
,m_level(0), m_varNum(0), m_typeNum(0) { }
ASTNODE_BASE_FUNCS(NodeModule)
virtual void dump(ostream& str);
virtual bool maybePointedTo() const { return true; }
@@ -1835,6 +1859,7 @@ public:
int level() const { return m_level; }
bool isTop() const { return level()==1; }
int varNumGetInc() { return ++m_varNum; }
int typeNumGetInc() { return ++m_typeNum; }
void modPublic(bool flag) { m_modPublic = flag; }
bool modPublic() const { return m_modPublic; }
void modTrace(bool flag) { m_modTrace = flag; }
@@ -1868,6 +1893,8 @@ inline bool AstNode::isNeqZero() { return (this->castConst() && this->castConst
inline bool AstNode::isOne() { return (this->castConst() && this->castConst()->num().isEqOne()); }
inline bool AstNode::isAllOnes() { return (this->castConst() && this->castConst()->isEqAllOnes()); }
inline bool AstNode::isAllOnesV() { return (this->castConst() && this->castConst()->isEqAllOnesV()); }
inline bool AstNode::sameTree(AstNode* node2p) { return sameTreeIter(node2p, true, false); }
inline bool AstNode::sameGateTree(AstNode* node2p) { return sameTreeIter(node2p, true, true); }
inline void AstNodeVarRef::init() { if (m_varp) dtypep(m_varp->dtypep()); }
+22
View File
@@ -515,6 +515,24 @@ string AstScopeName::scopeSymName() const {
return out;
}
string AstScopeName::scopeDpiName() const {
string out;
for (AstText* textp=scopeEntrp(); textp; textp=textp->nextp()->castText()) {
out += textp->text();
}
if (out.substr(0,10) == "__DOT__TOP") out.replace(0,10,"");
if (out.substr(0,7) == "__DOT__") out.replace(0,7,"");
if (out.substr(0,1) == ".") out.replace(0,1,"");
string::size_type pos;
while ((pos=out.find(".")) != string::npos) {
out.replace(pos, 1, "__");
}
while ((pos=out.find("__DOT__")) != string::npos) {
out.replace(pos, 7, "__");
}
return out;
}
bool AstSenTree::hasClocked() {
if (!sensesp()) this->v3fatalSrc("SENTREE without any SENITEMs under it");
for (AstNodeSenItem* senp = sensesp(); senp; senp=senp->nextp()->castNodeSenItem()) {
@@ -801,6 +819,10 @@ void AstPin::dump(ostream& str) {
else { str<<" ->UNLINKED"; }
if (svImplicit()) str<<" [.SV]";
}
void AstTypedef::dump(ostream& str) {
this->AstNode::dump(str);
if (attrPublic()) str<<" [PUBLIC]";
}
void AstRange::dump(ostream& str) {
this->AstNode::dump(str);
if (littleEndian()) str<<" [LITTLE]";
+457 -249
View File
File diff suppressed because it is too large Load Diff
+11 -9
View File
@@ -83,17 +83,19 @@ private:
void genChangeDet(AstVarScope* vscp) {
AstVar* varp = vscp->varp();
vscp->v3warn(IMPERFECTSCH,"Imperfect scheduling of variable: "<<vscp);
AstUnpackArrayDType* arrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstUnpackArrayDType* uarrayp = varp->dtypeSkipRefp()->castUnpackArrayDType();
AstPackArrayDType* parrayp = varp->dtypeSkipRefp()->castPackArrayDType();
AstNodeClassDType *classp = varp->dtypeSkipRefp()->castNodeClassDType();
bool isArray = arrayp;
bool isUnpackArray = uarrayp;
bool isPackArray = parrayp;
bool isClass = classp && classp->packedUnsup();
int elements = isArray ? arrayp->elementsConst() : 1;
if (isArray && (elements > DETECTARRAY_MAX_INDEXES)) {
int elements = isUnpackArray ? uarrayp->elementsConst() : 1;
if (isUnpackArray && (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 && !isClass
} else if (!isUnpackArray && !isClass && !isPackArray
&& !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());
@@ -110,17 +112,17 @@ private:
for (int index=0; index<elements; ++index) {
AstChangeDet* changep
= new AstChangeDet (vscp->fileline(),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), vscp, false)),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), newvscp, false)),
false);
m_chgFuncp->addStmtsp(changep);
AstAssign* initp
= new AstAssign (vscp->fileline(),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), newvscp, true)),
aselIfNeeded(isArray, index,
aselIfNeeded(isUnpackArray, index,
new AstVarRef(vscp->fileline(), vscp, false)));
m_chgFuncp->addFinalsp(initp);
}
+4
View File
@@ -238,6 +238,10 @@ private:
nodep->iterateChildren(*this);
insureCleanAndNext (nodep->valuep());
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
// No cleaning, or would loose pointer to enum
nodep->iterateChildren(*this);
}
// Control flow operators
virtual void visit(AstNodeCond* nodep, AstNUser*) {
+148 -9
View File
@@ -173,6 +173,16 @@ private:
if (rnodep->width() != bnodep->width()) return false;
return rnodep->lhsp()->castConst();
}
static bool operandSubAdd(AstNode* nodep) {
// SUB( ADD(CONSTx,y), CONSTz) -> ADD(SUB(CONSTx,CONSTz), y)
AstNodeBiop* np = nodep->castNodeBiop();
AstNodeBiop* lp = np->lhsp()->castNodeBiop();
return (lp
&& lp->lhsp()->castConst()
&& np->rhsp()->castConst()
&& lp->width()==np->width());
}
static bool operandAndOrSame(AstNode* nodep) {
// OR( AND(VAL,x), AND(VAL,y)) -> AND(VAL,OR(x,y))
// OR( AND(x,VAL), AND(y,VAL)) -> AND(OR(x,y),VAL)
@@ -274,6 +284,8 @@ private:
// We can only get rid of a<<b>>c or a<<b<<c, with constant b & c
// because bits may be masked in that process, or (b+c) may exceed the word width.
if (!(nodep->rhsp()->castConst() && lhsp->rhsp()->castConst())) return false;
if (nodep->rhsp()->castConst()->num().isFourState()
|| lhsp->rhsp()->castConst()->num().isFourState()) return false;
if (nodep->width()!=lhsp->width()) return false;
if (nodep->width()!=lhsp->lhsp()->width()) return false;
return true;
@@ -416,12 +428,12 @@ private:
static bool operandsSame(AstNode* node1p, AstNode* node2p) {
// For now we just detect constants & simple vars, though it could be more generic
if (node1p->castConst() && node2p->castConst()) {
return node1p->sameTree(node2p);
return node1p->sameGateTree(node2p);
}
else if (node1p->castVarRef() && node2p->castVarRef()) {
// Avoid comparing widthMin's, which results in lost optimization attempts
// If cleanup sameTree to be smarter, this can be restored.
//return node1p->sameTree(node2p);
// If cleanup sameGateTree to be smarter, this can be restored.
//return node1p->sameGateTree(node2p);
return node1p->same(node2p);
} else {
return false;
@@ -437,7 +449,7 @@ private:
AstVarRef* elsevarp = elsep->lhsp()->castVarRef();
if (!ifvarp || !elsevarp) return false;
if (ifvarp->isWide()) return false; // Would need temporaries, so not worth it
if (!ifvarp->sameTree(elsevarp)) return false;
if (!ifvarp->sameGateTree(elsevarp)) return false;
return true;
}
bool operandIfIf(AstNodeIf* nodep) {
@@ -448,6 +460,89 @@ private:
if (afterComment(lowerIfp->elsesp())) return false;
return true;
}
bool ifConcatMergeableBiop(AstNode* nodep) {
return (nodep->castAnd()
|| nodep->castOr()
|| nodep->castXor()
|| nodep->castXnor());
}
bool ifAdjacentSel(AstSel* lhsp, AstSel* rhsp) {
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (!lhsp || !rhsp) return false;
AstNode* lfromp = lhsp->fromp();
AstNode* rfromp = rhsp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lhsp->lsbp()->castConst();
AstConst* rstart = rhsp->lsbp()->castConst();
AstConst* lwidth = lhsp->widthp()->castConst();
AstConst* rwidth = rhsp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
if (rend == lstart->toSInt()) return true;
return false;
}
bool ifMergeAdjacent(AstNode* lhsp, AstNode* rhsp) {
// called by concatmergeable to determine if {lhsp, rhsp} make sense
if (!v3Global.opt.oAssemble()) return false; // opt disabled
// two same varref
if (operandsSame(lhsp, rhsp)) return true;
AstSel* lselp = lhsp->castSel();
AstSel* rselp = rhsp->castSel();
// a[i:0] a
if (lselp && !rselp && rhsp->sameGateTree(lselp->fromp()))
rselp = new AstSel(rhsp->fileline(), rhsp->cloneTree(false), 0, rhsp->width());
// a[i:j] {a[j-1:k], b}
if (lselp && !rselp && rhsp->castConcat())
return ifMergeAdjacent(lhsp, rhsp->castConcat()->lhsp());
// a a[msb:j]
if (rselp && !lselp && lhsp->sameGateTree(rselp->fromp()))
lselp = new AstSel(lhsp->fileline(), lhsp->cloneTree(false), 0, lhsp->width());
// {b, a[j:k]} a[k-1:i]
if (rselp && !lselp && lhsp->castConcat())
return ifMergeAdjacent(lhsp->castConcat()->rhsp(), rhsp);
if (!lselp || !rselp) return false;
// a[a:b] a[b-1:c] are adjacent
AstNode* lfromp = lselp->fromp();
AstNode* rfromp = rselp->fromp();
if (!lfromp || !rfromp || !lfromp->sameGateTree(rfromp)) return false;
AstConst* lstart = lselp->lsbp()->castConst();
AstConst* rstart = rselp->lsbp()->castConst();
AstConst* lwidth = lselp->widthp()->castConst();
AstConst* rwidth = rselp->widthp()->castConst();
if (!lstart || !rstart || !lwidth || !rwidth) return false; // too complicated
int rend = (rstart->toSInt() + rwidth->toSInt());
// a[i:j] a[j-1:k]
if (rend == lstart->toSInt()) return true;
// a[i:0] a[msb:j]
if (rend == rfromp->width() && lstart->toSInt() == 0) return true;
return false;
}
bool concatMergeable(AstNode* lhsp, AstNode* rhsp) {
// determine if {a OP b, c OP d} => {a, c} OP {b, d} is advantagous
if (!v3Global.opt.oAssemble()) return false; // opt disabled
if (lhsp->type() != rhsp->type()) return false;
if (!ifConcatMergeableBiop(lhsp)) return false;
AstNodeBiop* lp = lhsp->castNodeBiop();
AstNodeBiop* rp = rhsp->castNodeBiop();
if (!lp || !rp) return false;
// {a[]&b[], a[]&b[]}
bool lad = ifMergeAdjacent(lp->lhsp(), rp->lhsp());
bool rad = ifMergeAdjacent(lp->rhsp(), rp->rhsp());
if (lad && rad) return true;
// {a[] & b[]&c[], a[] & b[]&c[]}
else if (lad && concatMergeable(lp->rhsp(), rp->rhsp())) return true;
// {a[]&b[] & c[], a[]&b[] & c[]}
else if (rad && concatMergeable(lp->lhsp(), rp->lhsp())) return true;
else {
// {(a[]&b[])&(c[]&d[]), (a[]&b[])&(c[]&d[])}
if (concatMergeable(lp->lhsp(), rp->lhsp())
&& concatMergeable(lp->rhsp(), rp->rhsp()))
return true;
}
return false;
}
//----------------------------------------
// Constant Replacement functions.
@@ -666,6 +761,45 @@ private:
rrp->deleteTree();
//nodep->dumpTree(cout, " repShiftSame_new: ");
}
void replaceConcatSel(AstConcat* nodep) {
// {a[1], a[0]} -> a[1:0]
AstSel* lselp = nodep->lhsp()->unlinkFrBack()->castSel();
AstSel* rselp = nodep->rhsp()->unlinkFrBack()->castSel();
int lstart = lselp->lsbConst();
int lwidth = lselp->widthConst();
int rstart = rselp->lsbConst();
int rwidth = rselp->widthConst();
if ((rstart + rwidth) != lstart) nodep->v3fatalSrc("tried to merge two selects which are not adjacent");
AstSel* newselp = new AstSel(lselp->fromp()->fileline(), rselp->fromp()->cloneTree(false), rstart, lwidth+rwidth);
UINFO(5, "merged two adjacent sel "<<lselp <<" and "<<rselp<< " to one "<<newselp<<endl);
nodep->replaceWith(newselp);
lselp->deleteTree(); lselp = NULL;
rselp->deleteTree(); rselp = NULL;
nodep->deleteTree(); nodep = NULL;
}
void replaceConcatMerge(AstConcat* nodep) {
AstNodeBiop* lp = nodep->lhsp()->castNodeBiop();
AstNodeBiop* rp = nodep->rhsp()->castNodeBiop();
AstNode* llp = lp->lhsp()->cloneTree(false);
AstNode* lrp = lp->rhsp()->cloneTree(false);
AstNode* rlp = rp->lhsp()->cloneTree(false);
AstNode* rrp = rp->rhsp()->cloneTree(false);
if (concatMergeable(lp, rp)) {
AstConcat* newlp = new AstConcat(rlp->fileline(), llp, rlp);
AstConcat* newrp = new AstConcat(rrp->fileline(), lrp, rrp);
// use the lhs to replace the parent concat
lp->lhsp()->replaceWith(newlp);
lp->rhsp()->replaceWith(newrp);
lp->dtypeChgWidthSigned(newlp->width(), newlp->width(), AstNumeric::fromBool(true));
UINFO(5, "merged "<< nodep <<endl);
rp->unlinkFrBack()->deleteTree(); rp = NULL;
nodep->replaceWith(lp->unlinkFrBack()); nodep->deleteTree(); nodep = NULL;
lp->lhsp()->accept(*this);
lp->rhsp()->accept(*this);
} else nodep->v3fatalSrc("tried to merge two Concat which are not adjacent");
}
void replaceExtend (AstNode* nodep, AstNode* arg0p) {
// -> EXTEND(nodep)
// like a AstExtend{$rhsp}, but we need to set the width correctly from base node
@@ -790,7 +924,7 @@ private:
AstSel* sel2p = nextp->lhsp()->castSel(); if (!sel2p) return false;
AstVarRef* varref1p = sel1p->fromp()->castVarRef(); if (!varref1p) return false;
AstVarRef* varref2p = sel2p->fromp()->castVarRef(); if (!varref2p) return false;
if (!varref1p->sameTree(varref2p)) return false;
if (!varref1p->sameGateTree(varref2p)) return false;
AstConst* con1p = sel1p->lsbp()->castConst(); if (!con1p) return false;
AstConst* con2p = sel2p->lsbp()->castConst(); if (!con2p) return false;
// We need to make sure there's no self-references involved in either
@@ -1537,7 +1671,7 @@ private:
AstSenItem* litemp = senp->castSenItem();
AstSenItem* ritemp = cmpp->castSenItem();
if (litemp && ritemp) {
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameTree(ritemp->varrefp()))
if ((litemp->varrefp() && ritemp->varrefp() && litemp->varrefp()->sameGateTree(ritemp->varrefp()))
|| (!litemp->varrefp() && !ritemp->varrefp())) {
// We've sorted in the order ANY, BOTH, POS, NEG, so we don't need to try opposite orders
if (( litemp->edgeType()==AstEdgeType::ET_ANYEDGE) // ANY or {BOTH|POS|NEG} -> ANY
@@ -1694,8 +1828,9 @@ private:
string fmt = "";
bool inPct = false;
AstNode* argp = nodep->exprsp();
for (const char* inp = nodep->text().c_str(); *inp; inp++) {
char ch = *inp; // Breaks with iterators...
string text = nodep->text();
for (string::const_iterator it = text.begin(); it!=text.end(); ++it) {
char ch = *it;
if (!inPct && ch=='%') {
inPct = true;
fmt = ch;
@@ -1907,6 +2042,7 @@ 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 ("AstSub {$lhsp.castAdd, operandSubAdd(nodep)}", "AstAdd{AstSub{$lhsp->castAdd()->lhsp(),$rhsp}, $lhsp->castAdd()->rhsp()}"); // ((a+x)-y) -> (a+(x-y))
// 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)");
@@ -2061,6 +2197,9 @@ private:
// CONCAT({const},CONCAT({const},{c})) -> CONCAT((constifiedCONC{const|const},{c}))
TREEOPV("AstConcat{operandConcatMove(nodep)}", "moveConcat(nodep)");
TREEOPV("AstConcat{$lhsp.isZero, $rhsp}", "replaceExtend(nodep, nodep->rhsp())");
// CONCAT(a[1],a[0]) -> a[1:0]
TREEOPV("AstConcat{$lhsp->castSel(), $rhsp->castSel(), ifAdjacentSel($lhsp->castSel(),,$rhsp->castSel())}", "replaceConcatSel(nodep)");
TREEOPV("AstConcat{ifConcatMergeableBiop($lhsp), concatMergeable($lhsp,,$rhsp)}", "replaceConcatMerge(nodep)");
// Common two-level operations that can be simplified
TREEOP ("AstAnd {$lhsp.castOr, $rhsp.castOr, operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
TREEOP ("AstOr {$lhsp.castAnd,$rhsp.castAnd,operandAndOrSame(nodep)}", "replaceAndOr(nodep)");
@@ -2068,7 +2207,7 @@ private:
TREEOP ("AstAnd {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstOr {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstXor {operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
TREEOP ("AstXnor{operandShiftSame(nodep)}", "replaceShiftSame(nodep)");
// "AstXnor{operandShiftSame(nodep)}", // Cannot ShiftSame as the shifted-in zeros might create a one
// Note can't simplify a extend{extends}, extends{extend}, as the sign bits end up in the wrong places
TREEOPV("AstExtend {$lhsp.castExtend}", "replaceExtend(nodep, nodep->lhsp()->castExtend()->lhsp())");
TREEOPV("AstExtendS{$lhsp.castExtendS}", "replaceExtend(nodep, nodep->lhsp()->castExtendS()->lhsp())");
+16
View File
@@ -81,6 +81,7 @@ private:
typedef multimap<AstVarScope*,AstNodeAssign*> AssignMap;
// STATE
AstNodeModule* m_modp; // Current module
vector<AstNode*> m_varEtcsp; // List of all encountered to avoid another loop through tree
vector<AstVarScope*> m_vscsp; // List of all encountered to avoid another loop through tree
AssignMap m_assignMap; // List of all simple assignments for each variable
@@ -112,6 +113,12 @@ private:
}
// VISITORS
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
nodep->iterateChildren(*this);
checkAll(nodep);
m_modp = NULL;
}
virtual void visit(AstCell* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -158,6 +165,13 @@ private:
nodep->packagep()->user1Inc();
}
}
virtual void visit(AstTypedef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
// Don't let packages with only public variables disappear
// Normal modules may disappear, e.g. if they are parameterized then removed
if (nodep->attrPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
@@ -168,6 +182,7 @@ private:
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
checkAll(nodep);
if (nodep->isSigPublic() && m_modp && m_modp->castPackage()) m_modp->user1Inc();
if (mightElim(nodep)) {
m_varEtcsp.push_back(nodep);
}
@@ -253,6 +268,7 @@ private:
public:
// CONSTRUCTORS
DeadVisitor(AstNetlist* nodep, bool elimUserVars, bool elimDTypes) {
m_modp = NULL;
m_elimUserVars = elimUserVars;
m_elimDTypes = elimDTypes;
m_sideEffect = false;
+55 -14
View File
@@ -96,6 +96,38 @@ public:
}
}
void emitTypedefs(AstNode* firstp) {
bool first = true;
for (AstNode* loopp=firstp; loopp; loopp = loopp->nextp()) {
if (AstTypedef* nodep = loopp->castTypedef()) {
if (nodep->attrPublic()) {
if (first) {
first = false;
puts("\n// TYPEDEFS\n");
puts("// That were declared public\n");
} else {
puts("\n");
}
if (AstEnumDType* adtypep = nodep->dtypep()->skipRefToEnump()->castEnumDType()) {
if (adtypep->width()>64) {
puts("// enum "+nodep->name()+" // Ignored: Too wide for C++\n");
} else {
puts("enum "+nodep->name()+" {\n");
for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp=itemp->nextp()->castEnumItem()) {
puts(itemp->name());
puts(" = ");
itemp->valuep()->iterateAndNext(*this);
if (nodep->nextp()) puts(",");
puts("\n");
}
puts("};\n");
}
}
}
}
}
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
bool paren = true; bool decind = false;
@@ -226,7 +258,9 @@ public:
virtual void visit(AstScopeName* nodep, AstNUser*) {
// For use under AstCCalls for dpiImports. ScopeNames under displays are handled in AstDisplay
if (!nodep->dpiExport()) {
putbs("(&(vlSymsp->__Vscope_"+nodep->scopeSymName()+"))");
// this is where the DPI import context scope is set
string scope = nodep->scopeDpiName();
putbs("(&(vlSymsp->__Vscope_"+scope+"))");
}
}
virtual void visit(AstSFormat* nodep, AstNUser*) {
@@ -246,12 +280,14 @@ public:
char format = '?';
bool pct=false;
int got=0;
for (const char* cp = nodep->text().c_str(); *cp; cp++) {
string txt = nodep->text();
for (string::const_iterator it=txt.begin(); it!=txt.end(); ++it) {
char ch = *it;
if (pct) {
pct = false;
switch (tolower(*cp)) {
switch (tolower(ch)) {
case '%':
prefix += *cp;
prefix += ch;
break;
case 'd': // FALLTHRU
case 'o': // FALLTHRU
@@ -259,22 +295,22 @@ public:
case 'x': // FALLTHRU
case 'b': // FALLTHRU
case 's':
got++; format = tolower(*cp);
got++; format = tolower(ch);
break;
case 'e': // FALLTHRU
case 'f': // FALLTHRU
case 'g':
got++; format = tolower(*cp);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<*cp<<"'"<<endl);
got++; format = tolower(ch);
nodep->v3error("Unsupported $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
default:
got++;
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<*cp<<"'"<<endl);
nodep->v3error("Illegal $value$plusargs format qualifier: '"<<ch<<"'"<<endl);
break;
}
}
else if (*cp == '%') pct = true;
else prefix += *cp;
else if (ch == '%') pct = true;
else prefix += ch;
}
if (got!=1) nodep->v3error("Missing or extra $value$plusargs format qualifier: '"<<nodep->text()<<"'"<<endl);
puts("VL_VALUEPLUSARGS_I");
@@ -622,8 +658,9 @@ public:
// Only 32 bits - llx + long long here just to appease CPP format warning
if (num<10) puts(cvtToStr(num));
else ofp()->printf("0x%" VL_PRI64 "x", (vluint64_t)num);
//Unneeded-Causes %lx format warnings:
// if (!nodep->num().isSigned() && (num & (1UL<<31))) puts("U");
// If signed, we'll do our own functions
// But must be here, or <= comparisons etc may end up signed
puts("U");
}
}
void emitSetVarConstant(const string& assignString, AstConst* constp) {
@@ -658,6 +695,7 @@ public:
nodep->iterateChildren(*this);
}
// NOPs
virtual void visit(AstTypedef*, AstNUser*) {}
virtual void visit(AstPragma*, AstNUser*) {}
virtual void visit(AstCell*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstVar*, AstNUser*) {} // Handled outside the Visit class
@@ -665,7 +703,6 @@ public:
virtual void visit(AstTraceDecl*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTraceInc*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstCFile*, AstNUser*) {} // Handled outside the Visit class
virtual void visit(AstTypedef*, AstNUser*) {} // Nothing needed presently
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
@@ -780,6 +817,7 @@ class EmitCImp : EmitCStmts {
//---------------------------------------
// VISITORS
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warnng
virtual void visit(AstCFunc* nodep, AstNUser*) {
// TRACE_* and DPI handled elsewhere
if (nodep->funcType().isTrace()) return;
@@ -1381,7 +1419,7 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
}
bool zeroit = (varp->attrFileDescr() // Zero it out, so we don't core dump if never call $fopen
|| (varp->basicp() && varp->basicp()->isZeroInit())
|| (varp->name().c_str()[0]=='_' && v3Global.opt.underlineZero()));
|| (varp->name().size()>=1 && varp->name()[0]=='_' && v3Global.opt.underlineZero()));
if (varp->isWide()) {
// DOCUMENT: We randomize everything. If the user wants a _var to be zero,
// there should be a initial statement. (Different from verilator2.)
@@ -1839,6 +1877,8 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
}
}
emitTypedefs(modp->stmtsp());
puts("\n// PORTS\n");
if (modp->isTop()) puts("// The application code writes and reads these signals to\n");
if (modp->isTop()) puts("// propagate new values into/out from the Verilated model.\n");
@@ -2300,6 +2340,7 @@ class EmitCTrace : EmitCStmts {
}
// VISITORS
using EmitCStmts::visit; // Suppress hidden overloaded virtual function warnng
virtual void visit(AstNetlist* nodep, AstNUser*) {
// Top module only
nodep->topModulep()->accept(*this);
+2 -1
View File
@@ -383,7 +383,8 @@ void EmitCSyms::emitSymImp() {
AstScope* scopep = it->first; AstNodeModule* modp = it->second;
if (modp->isTop()) {
} else {
ofp()->printf("\t%c %-30s ", comma, scopep->nameDotless().c_str());
string nameDl = scopep->nameDotless();
ofp()->printf("\t%c %-30s ", comma, nameDl.c_str());
puts("(Verilated::catName(topp->name(),");
// The "." is added by catName
putsQuoted(scopep->prettyName());
+7 -8
View File
@@ -164,16 +164,16 @@ public:
of.puts("# User CFLAGS (from -CFLAGS on Verilator command line)\n");
of.puts("VM_USER_CFLAGS = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.cFlags().begin();
it != v3Global.opt.cFlags().end(); ++it) {
const V3StringSet& cFlags = v3Global.opt.cFlags();
for (V3StringSet::const_iterator it = cFlags.begin(); it != cFlags.end(); ++it) {
of.puts("\t"+*it+" \\\n");
}
of.puts("\n");
of.puts("# User LDLIBS (from -LDFLAGS on Verilator command line)\n");
of.puts("VM_USER_LDLIBS = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.ldLibs().begin();
it != v3Global.opt.ldLibs().end(); ++it) {
const V3StringSet& ldLibs = v3Global.opt.ldLibs();
for (V3StringSet::const_iterator it = ldLibs.begin(); it != ldLibs.end(); ++it) {
of.puts("\t"+*it+" \\\n");
}
of.puts("\n");
@@ -181,8 +181,8 @@ public:
V3StringSet dirs;
of.puts("# User .cpp files (from .cpp's on Verilator command line)\n");
of.puts("VM_USER_CLASSES = \\\n");
for (V3StringSet::const_iterator it = v3Global.opt.cppFiles().begin();
it != v3Global.opt.cppFiles().end(); ++it) {
const V3StringSet& cppFiles = v3Global.opt.cppFiles();
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
of.puts("\t"+V3Options::filenameNonExt(cppfile)+" \\\n");
string dir = V3Options::filenameDir(cppfile);
@@ -207,8 +207,7 @@ public:
of.puts("\n### Executable rules... (from --exe)\n");
of.puts("VPATH += $(VM_USER_DIR)\n");
of.puts("\n");
for (V3StringSet::const_iterator it = v3Global.opt.cppFiles().begin();
it != v3Global.opt.cppFiles().end(); ++it) {
for (V3StringSet::const_iterator it = cppFiles.begin(); it != cppFiles.end(); ++it) {
string cppfile = *it;
string basename = V3Options::filenameNonExt(cppfile);
of.puts(basename+".o: "+cppfile+"\n");
+1 -2
View File
@@ -685,7 +685,6 @@ public:
class EmitVPrefixedVisitor : public EmitVBaseVisitor {
// MEMBERS
EmitVPrefixedFormatter m_formatter; // Special verilog formatter (Way down the inheritance is another unused V3OutFormatter)
bool m_user3mark; // nodep->user3() if set means mark with %%
// METHODS
virtual void putsNoTracking(const string& str) { m_formatter.putsNoTracking(str); }
virtual void puts(const string& str) { m_formatter.puts(str); }
@@ -706,7 +705,7 @@ class EmitVPrefixedVisitor : public EmitVBaseVisitor {
public:
EmitVPrefixedVisitor(AstNode* nodep, ostream& os, const string& prefix, int flWidth,
AstSenTree* domainp, bool user3mark)
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth), m_user3mark(user3mark) {
: EmitVBaseVisitor(domainp), m_formatter(os, prefix, flWidth) {
if (user3mark) { AstUser3InUse::check(); }
nodep->accept(*this);
}
+1
View File
@@ -253,6 +253,7 @@ void FileLine::warnStyleOff(bool flag) {
bool FileLine::warnIsOff(V3ErrorCode code) const {
if (!m_warnOn.test(code)) return true;
if (!defaultFileLine().m_warnOn.test(code)) return true; // Global overrides local
// UNOPTFLAT implies UNOPT
if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
+3 -2
View File
@@ -144,9 +144,10 @@ public:
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const { return ( m_e==ASSIGNIN || m_e==BLKANDNBLK
|| m_e==IMPURE || m_e==MODDUP || m_e==SYMRSVDWORD); }
|| m_e==IMPURE || m_e==MODDUP); }
// Warnings to mention manual
bool mentionManual() const { return ( m_e==EC_FATALSRC || pretendError() ); }
bool mentionManual() const { return ( m_e==EC_FATALSRC || m_e==SYMRSVDWORD
|| pretendError() ); }
// Warnings that are lint only
bool lintError() const { return ( m_e==ALWCOMBORDER
+7 -3
View File
@@ -448,8 +448,8 @@ private:
AstNode* newp = new AstShiftR (nodep->fileline(),
fromp,
dropCondBound(lsbp),
nodep->width());
newp->dtypeFrom(nodep);
fromp->width()); // {large}>>32 requires 64-bit shift operation; then cast
newp->dtypeFrom(fromp);
if (!nodep->isQuad() && fromp->isQuad()) {
newp = new AstCCast (newp->fileline(), newp, nodep);
}
@@ -583,11 +583,15 @@ private:
newSelBitBit(lhsp->lsbp()),
VL_WORDSIZE)),
oldvalp);
// Restrict the shift amount to 0-31, see bug804.
AstNode* shiftp = new AstAnd(nodep->fileline(), lhsp->lsbp()->cloneTree(true),
new AstConst(nodep->fileline(), VL_WORDSIZE-1));
AstNode* newp = new AstOr (lhsp->fileline(),
oldvalp,
new AstShiftL (lhsp->fileline(),
rhsp,
lhsp->lsbp()->cloneTree(true),
shiftp,
VL_WORDSIZE));
newp = new AstAssign (nodep->fileline(),
new AstWordSel (nodep->fileline(),
+12 -7
View File
@@ -71,7 +71,8 @@ class V3FileDependImp {
time_t mtime() const { return m_stat.st_mtime; }
void loadStats() {
if (!m_stat.st_mtime) {
int err = stat(filename().c_str(), &m_stat);
string fn = filename();
int err = stat(fn.c_str(), &m_stat);
if (err!=0) {
m_stat.st_mtime = 1;
// Not a error... This can occur due to `line directives in the .vpp files
@@ -258,15 +259,19 @@ bool V3File::checkTimes(const string& filename, const string& cmdline) {
return dependImp.checkTimes(filename, cmdline);
}
void V3File::createDir(const string& dirname) {
#ifndef _WIN32
mkdir(dirname.c_str(), 0777);
#else
mkdir(dirname.c_str());
#endif
}
void V3File::createMakeDir() {
static bool created = false;
if (!created) {
created = true;
#ifndef _WIN32
mkdir(v3Global.opt.makeDir().c_str(), 0777);
#else
mkdir(v3Global.opt.makeDir().c_str());
#endif
createDir(v3Global.opt.makeDir());
}
}
@@ -562,7 +567,7 @@ const char* V3OutFormatter::indentStr(int num) {
static char str[MAXSPACE+20];
char* cp = str;
if (num>MAXSPACE) num=MAXSPACE;
if (!m_lang==LA_VERILOG) { // verilogPrefixedTree doesn't want tabs
if (m_lang!=LA_VERILOG) { // verilogPrefixedTree doesn't want tabs
while (num>=8) {
*cp++ = '\t';
num -= 8;
+3 -2
View File
@@ -67,6 +67,7 @@ public:
static bool checkTimes(const string& filename, const string& cmdline);
// Directory utilities
static void createDir(const string& dirname);
static void createMakeDir();
};
@@ -188,8 +189,8 @@ public:
}
virtual ~V3OutCFile() {}
virtual void putsCellDecl(const string& classname, const string& cellname) {
this->printf("%-19s\t%s;\n",
(classname + "*").c_str(),cellname.c_str());
string classStar = classname + "*";
this->printf("%-19s\t%s;\n", classStar.c_str(), cellname.c_str());
}
virtual void putsHeader() { puts("// Verilated -*- C++ -*-\n"); }
virtual void putsIntTopInclude() { }
+135 -5
View File
@@ -258,8 +258,8 @@ public:
if (!m_substTreep) {
clearSimple("No assignment found\n");
}
for (GateVarRefList::const_iterator it = rhsVarRefs().begin();
it != rhsVarRefs().end(); ++it) {
for (GateVarRefList::const_iterator it = m_rhsVarRefs.begin();
it != m_rhsVarRefs.end(); ++it) {
if (m_lhsVarRef && m_lhsVarRef->varScopep() == (*it)->varScopep()) {
clearSimple("Circular logic\n"); // Oh my, we'll get a UNOPTFLAT much later.
}
@@ -303,6 +303,7 @@ private:
V3Double0 m_statSigs; // Statistic tracking
V3Double0 m_statRefs; // Statistic tracking
V3Double0 m_statDedupLogic; // Statistic tracking
V3Double0 m_statAssignMerged; // Statistic tracking
// METHODS
void iterateNewStmt(AstNode* nodep, const char* nonReducibleReason, const char* consumeReason) {
@@ -352,6 +353,7 @@ private:
void consumedMove();
void replaceAssigns();
void dedupe();
void mergeAssigns();
// VISITORS
virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -368,6 +370,7 @@ private:
optimizeSignals(true);
// Remove redundant logic
if (v3Global.opt.oDedupe()) dedupe();
if (v3Global.opt.oAssemble()) mergeAssigns();
// Warn
warnSignals();
consumedMark();
@@ -506,6 +509,7 @@ public:
V3Stats::addStat("Optimizations, Gate sigs deleted", m_statSigs);
V3Stats::addStat("Optimizations, Gate inputs replaced", m_statRefs);
V3Stats::addStat("Optimizations, Gate sigs deduped", m_statDedupLogic);
V3Stats::addStat("Optimizations, Gate assign merged", m_statAssignMerged);
}
};
@@ -593,8 +597,9 @@ void GateVisitor::optimizeSignals(bool allowMultiIn) {
optimizeElimVar(vvertexp->varScp(), substp, consumerp);
// If the new replacement referred to a signal,
// Correct the graph to point to this new generating variable
for (GateVarRefList::const_iterator it = okVisitor.rhsVarRefs().begin();
it != okVisitor.rhsVarRefs().end(); ++it) {
const GateVarRefList& rhsVarRefs = okVisitor.rhsVarRefs();
for (GateVarRefList::const_iterator it = rhsVarRefs.begin();
it != rhsVarRefs.end(); ++it) {
AstVarScope* newvarscp = (*it)->varScopep();
UINFO(9," Point-to-new vertex "<<newvarscp<<endl);
GateVarVertex* varvertexp = makeVarVertex(newvarscp);
@@ -1008,7 +1013,6 @@ private:
lvertexp->user(true);
}
}
return NULL;
}
@@ -1062,6 +1066,132 @@ void GateVisitor::dedupe() {
m_statDedupLogic += deduper.numDeduped();
}
//######################################################################
// Recurse through the graph, try to merge assigns
class GateMergeAssignsGraphVisitor : public GateGraphBaseVisitor {
private:
// NODE STATE
AstNodeAssign* m_assignp;
AstActive* m_activep;
GateLogicVertex* m_logicvp;
V3Graph* m_graphp;
V3Double0 m_numMergedAssigns; // Statistic tracking
// assemble two Sel into one if possible
AstSel* merge(AstSel* pre, AstSel* cur) {
AstVarRef* preVarRefp = pre->fromp()->castVarRef();
AstVarRef* curVarRefp = cur->fromp()->castVarRef();
if (!preVarRefp || !curVarRefp || !curVarRefp->same(preVarRefp)) return NULL; // not the same var
AstConst* pstart = pre->lsbp()->castConst();
AstConst* pwidth = pre->widthp()->castConst();
AstConst* cstart = cur->lsbp()->castConst();
AstConst* cwidth = cur->widthp()->castConst();
if (!pstart || !pwidth || !cstart || !cwidth) return NULL; // too complicated
if (cur->lsbConst()+cur->widthConst() == pre->lsbConst())
return new AstSel(curVarRefp->fileline(), curVarRefp->cloneTree(false), cur->lsbConst(), pre->widthConst()+cur->widthConst());
else return NULL;
}
virtual AstNUser* visit(GateVarVertex *vvertexp, AstNUser*) {
for (V3GraphEdge* edgep = vvertexp->inBeginp(); edgep; ) {
V3GraphEdge* oldedgep = edgep;
edgep = edgep->inNextp(); // for recursive since the edge could be deleted
if (GateLogicVertex* lvertexp = dynamic_cast<GateLogicVertex*>(oldedgep->fromp())) {
if (AstNodeAssign* assignp = lvertexp->nodep()->castNodeAssign()) {
//if (lvertexp->outSize1() && assignp->lhsp()->castSel()) {
if (assignp->lhsp()->castSel() && lvertexp->outSize1()) {
UINFO(9, "assing to the nodep["<<assignp->lhsp()->castSel()->lsbConst()<<"]"<<endl);
// first assign with Sel-lhs
if (!m_activep) m_activep = lvertexp->activep();
if (!m_logicvp) m_logicvp = lvertexp;
if (!m_assignp) m_assignp = assignp;
// not under the same active
if (m_activep != lvertexp->activep()) {
m_activep = lvertexp->activep();
m_logicvp = lvertexp;
m_assignp = assignp;
continue;
}
AstSel* preselp = m_assignp->lhsp()->castSel();
AstSel* curselp = assignp->lhsp()->castSel();
if (!preselp || !curselp) continue;
if (AstSel* newselp = merge(preselp, curselp)) {
UINFO(5, "assemble to new sel: "<<newselp<<endl);
// replace preSel with newSel
preselp->replaceWith(newselp); preselp->deleteTree(); preselp = NULL;
// create new rhs for pre assignment
AstNode* newrhsp = new AstConcat(m_assignp->rhsp()->fileline(), m_assignp->rhsp()->cloneTree(false), assignp->rhsp()->cloneTree(false));
AstNode* oldrhsp = m_assignp->rhsp();
oldrhsp->replaceWith(newrhsp); oldrhsp->deleteTree(); oldrhsp = NULL;
m_assignp->dtypeChgWidthSigned(m_assignp->width()+assignp->width(), m_assignp->width()+assignp->width(), AstNumeric::fromBool(true));
// don't need to delete, will be handled
//assignp->unlinkFrBack(); assignp->deleteTree(); assignp = NULL;
// update the graph
{
// delete all inedges to lvertexp
if (!lvertexp->inEmpty()) {
for (V3GraphEdge* ledgep = lvertexp->inBeginp(); ledgep; ) {
V3GraphEdge* oedgep = ledgep;
ledgep = ledgep->inNextp();
GateEitherVertex* fromvp = dynamic_cast<GateEitherVertex*>(oedgep->fromp());
new V3GraphEdge(m_graphp, fromvp, m_logicvp, 1);
oedgep->unlinkDelete(); oedgep = NULL;
}
}
// delete all outedges to lvertexp, only one
oldedgep->unlinkDelete(); oldedgep = NULL;
}
++m_numMergedAssigns;
} else {
m_assignp = assignp;
m_logicvp = lvertexp;
}
}
}
}
}
return NULL;
}
virtual AstNUser* visit(GateLogicVertex* lvertexp, AstNUser* vup) {
return NULL;
}
public:
GateMergeAssignsGraphVisitor(V3Graph* graphp) {
m_assignp = NULL;
m_activep = NULL;
m_logicvp = NULL;
m_numMergedAssigns = 0;
m_graphp = graphp;
}
void mergeAssignsTree(GateVarVertex* vvertexp) {
vvertexp->accept(*this);
}
V3Double0 numMergedAssigns() { return m_numMergedAssigns; }
};
//----------------------------------------------------------------------
void GateVisitor::mergeAssigns() {
GateMergeAssignsGraphVisitor merger(&m_graph);
for (V3GraphVertex* itp = m_graph.verticesBeginp(); itp; itp=itp->verticesNextp()) {
if (GateVarVertex* vvertexp = dynamic_cast<GateVarVertex*>(itp)) {
merger.mergeAssignsTree(vvertexp);
}
}
m_statAssignMerged += merger.numMergedAssigns();
}
//######################################################################
// Convert VARSCOPE(ASSIGN(default, VARREF)) to just VARSCOPE(default)
+4
View File
@@ -44,6 +44,7 @@ class V3Global {
int m_debugFileNumber; // Number to append to debug files created
bool m_assertDTypesResolved; // Tree should have dtypep()'s
bool m_assertWidthsMatch; // Tree should have width()==widthMin()
bool m_constRemoveXs; // Const needs to strip any Xs
bool m_needHInlines; // Need __Inlines file
bool m_needHeavy; // Need verilated_heavy.h include
bool m_dpi; // Need __Dpi include files
@@ -58,6 +59,7 @@ public:
m_debugFileNumber = 0;
m_assertDTypesResolved = false;
m_assertWidthsMatch = false;
m_constRemoveXs = false;
m_needHInlines = false;
m_needHeavy = false;
m_dpi = false;
@@ -77,6 +79,8 @@ public:
static void dumpCheckGlobalTree(const string& filename, int newNumber=0, bool doDump=true);
void assertDTypesResolved(bool flag) { m_assertDTypesResolved = flag; }
void assertWidthsMatch(bool flag) { m_assertWidthsMatch = flag; }
bool constRemoveXs() const { return m_constRemoveXs; }
void constRemoveXs(bool flag) { m_constRemoveXs = flag; }
string debugFilename(const string& nameComment, int newNumber=0) {
++m_debugFileNumber;
if (newNumber) m_debugFileNumber = newNumber;
+1
View File
@@ -96,6 +96,7 @@ public:
DfaVertex(DfaGraph* graphp, bool start=false, bool accepting=false)
: V3GraphVertex(graphp)
, m_start(start), m_accepting(accepting) {}
using V3GraphVertex::clone; // We are overriding, not overloading clone(V3Graph*)
virtual DfaVertex* clone(DfaGraph* graphp) {
return new DfaVertex(graphp, start(), accepting()); }
virtual ~DfaVertex() {}
+5
View File
@@ -314,6 +314,7 @@ private:
// Also clear I/O bits, as it is now local.
string name = m_cellp->name() + "__DOT__" + nodep->name();
if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
if (!m_cellp->isTrace()) nodep->trace(false);
if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
// Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
@@ -387,6 +388,10 @@ private:
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeAttrp(afterp);
afterp = nodep->scopeEntrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeEntrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
if (afterp) nodep->scopeEntrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstCoverDecl* nodep, AstNUser*) {
+3 -3
View File
@@ -266,8 +266,8 @@ public:
if (nodep->modp()) nodep->modp()->user1p(symp);
checkDuplicate(abovep, nodep, nodep->origName());
abovep->reinsert(nodep->origName(), symp);
if (abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
// If it's foo_DOT_bar, we need to be able to find it under that too.
if (forScopeCreation() && abovep != modSymp && !modSymp->findIdFlat(nodep->name())) {
// If it's foo_DOT_bar, we need to be able to find it under "foo_DOT_bar" too.
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
modSymp->reinsert(nodep->name(), symp);
}
@@ -1451,6 +1451,7 @@ private:
virtual void visit(AstPin* nodep, AstNUser*) {
// Pin: Link to submodule's port
checkNoDot(nodep);
nodep->iterateChildren(*this);
if (!nodep->modVarp()) {
if (!m_pinSymp) nodep->v3fatalSrc("Pin not under cell?\n");
VSymEnt* foundp = m_pinSymp->findIdFlat(nodep->name());
@@ -1475,7 +1476,6 @@ private:
refp->user5p(nodep);
}
}
nodep->iterateChildren(*this);
}
// Early return() above when deleted
}
+19 -2
View File
@@ -62,6 +62,7 @@ private:
AstNodeModule* m_valueModp; // If set, move AstVar->valuep() initial values to this module
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current task
AstNodeDType* m_dtypep; // Current data type
// METHODS
static int debug() {
@@ -104,6 +105,15 @@ private:
m_valueModp = upperValueModp;
}
}
virtual void visit(AstNodeDType* nodep, AstNUser*) {
if (!nodep->user1SetOnce()) { // Process only once.
cleanFileline(nodep);
AstNodeDType* upperDtypep = m_dtypep;
m_dtypep = nodep;
nodep->iterateChildren(*this);
m_dtypep = upperDtypep;
}
}
virtual void visit(AstEnumItem* nodep, AstNUser*) {
// Expand ranges
cleanFileline(nodep);
@@ -176,7 +186,13 @@ private:
virtual void visit(AstAttrOf* nodep, AstNUser*) {
cleanFileline(nodep);
nodep->iterateChildren(*this);
if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (nodep->attrType() == AstAttrType::DT_PUBLIC) {
AstTypedef* typep = nodep->backp()->castTypedef();
if (!typep) nodep->v3fatalSrc("Attribute not attached to typedef");
typep->attrPublic(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
}
else if (nodep->attrType() == AstAttrType::VAR_CLOCK) {
if (!m_varp) nodep->v3fatalSrc("Attribute not attached to variable");
m_varp->attrScClocked(true);
nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
@@ -265,7 +281,7 @@ private:
nodep->deleteTree(); nodep=NULL;
return;
} else {
defp = new AstTypedef(nodep->fileline(), nodep->name(), VFlagChildDType(), dtypep);
defp = new AstTypedef(nodep->fileline(), nodep->name(), NULL, VFlagChildDType(), dtypep);
m_implTypedef.insert(make_pair(make_pair(nodep->containerp(), defp->name()), defp));
backp->addNextHere(defp);
}
@@ -327,6 +343,7 @@ public:
m_varp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
m_dtypep = NULL;
m_inAlways = false;
m_inGenerate = false;
m_needStart = false;
+2 -2
View File
@@ -250,8 +250,8 @@ private:
void expectFormat(AstNode* nodep, const string& format, AstNode* argp, bool isScan) {
// Check display arguments
bool inPct = false;
for (const char* inp = format.c_str(); *inp; inp++) {
char ch = tolower(*inp); // Breaks with iterators...
for (string::const_iterator it = format.begin(); it != format.end(); ++it) {
char ch = tolower(*it);
if (!inPct && ch=='%') {
inPct = true;
} else if (inPct) {
+37 -13
View File
@@ -25,6 +25,7 @@
#include <cstdarg>
#include <algorithm>
#include <iomanip>
#include "V3Global.h"
#include "V3Number.h"
#define MAX_SPRINTF_DOUBLE_SIZE 100 // Maximum characters with a sprintf %e/%f/%g (probably < 30)
@@ -103,7 +104,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
}
// Otherwise...
else if (!m_sized) {
width(32, false); // Says the spec.
width(32, false); // Says IEEE 1800-2012 5.7.1
if (unbased) isSigned(true); // Also says the spec.
}
@@ -323,6 +324,7 @@ V3Number& V3Number::setAllBits1() {
return *this;
}
V3Number& V3Number::setAllBitsX() {
// Use setAllBitsXRemoved if calling this based on a non-X/Z input value such as divide by zero
for (int i=0; i<words(); i++) { m_value[i]=m_valueX[i] = ~0; }
opCleanThis();
return *this;
@@ -332,6 +334,20 @@ V3Number& V3Number::setAllBitsZ() {
opCleanThis();
return *this;
}
V3Number& V3Number::setAllBitsXRemoved() {
if (!v3Global.constRemoveXs()) {
return setAllBitsX();
} else {
// If we get a divide by zero we get Xs.
// But after V3Unknown we have removed Xs, so use --x-assign to direct-insert 0/1
if (v3Global.opt.xAssign() == "1") {
return setAllBits1();
} else {
return setAllBits0();
}
}
}
V3Number& V3Number::setMask(int nbits) {
setZero();
for (int bit=0; bit<nbits; bit++) { setBit(bit,1); }
@@ -1125,21 +1141,29 @@ V3Number& V3Number::opShiftR (const V3Number& lhs, const V3Number& rhs) {
if (rhs.isFourState()) return setAllBitsX();
setZero();
uint32_t rhsval = rhs.toUInt();
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(bit + rhsval));
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(bit + rhsval));
}
}
return *this;
}
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits) {
// L(lhs) bit return
// The spec says a unsigned >>> still acts as a normal >>.
// We presume it is signed; as that's V3Width's job to convert to opShiftR
if (rhs.isFourState()) return setAllBitsX();
setZero();
uint32_t rhsval = rhs.toUInt();
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit + rhsval));
if (rhsval < (uint32_t)lhs.width()) {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit + rhsval, lbits));
}
} else {
for (int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIs(lbits-1));
}
}
return *this;
}
@@ -1240,7 +1264,7 @@ V3Number& V3Number::opDiv (const V3Number& lhs, const V3Number& rhs) {
UINFO(9, "opdiv "<<lhs<<" "<<rhs<<endl);
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() / rhs.toUQuad());
return *this;
@@ -1253,7 +1277,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed divide
//UINFO(9, ">>divs-start "<<lhs<<" "<<rhs<<endl);
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
@@ -1270,7 +1294,7 @@ V3Number& V3Number::opDivS (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
// i op j, max(L(lhs),L(rhs)) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() % rhs.toUQuad());
return *this;
@@ -1282,7 +1306,7 @@ V3Number& V3Number::opModDiv (const V3Number& lhs, const V3Number& rhs) {
V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed moddiv
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsX();
if (rhs.isEqZero()) return setAllBitsXRemoved();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opNegate(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opNegate(rhs);
V3Number qNoSign = opModDiv(lhsNoSign,rhsNoSign);
@@ -1420,7 +1444,7 @@ V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs, bool lsign,
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();
if (lhs.isEqZero()) return setAllBitsXRemoved();
else if (lhs.isEqOne()) return setQuad(1);
else if (lsign && lhs.isEqAllOnes()) {
if (rhs.bitIs1(0)) return setAllBits1(); // -1^odd=-1
@@ -1473,11 +1497,11 @@ V3Number& V3Number::opAssign (const V3Number& lhs) {
return *this;
}
V3Number& V3Number::opExtendS (const V3Number& lhs) {
V3Number& V3Number::opExtendS (const V3Number& lhs, uint32_t lbits) {
// Note may be a width change during the sign extension
setZero();
for(int bit=0; bit<this->width(); bit++) {
setBit(bit,lhs.bitIsExtend(bit));
setBit(bit,lhs.bitIsExtend(bit, lbits));
}
return *this;
}
+17 -7
View File
@@ -60,15 +60,18 @@ public:
}
private:
char bitIs (int bit) const {
if (bit>=m_width) {
if (bit>=m_width || bit<0) {
// We never sign extend
return '0';
}
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
char bitIsExtend (int bit) const {
if (bit>=m_width) {
bit = m_width-1;
char bitIsExtend (int bit, int lbits) const {
// lbits usually = width, but for C optimizations width=32_bits, lbits = 32_or_less
if (bit<0) return '0';
UASSERT(lbits<=m_width, "Extend of wrong size");
if (bit>=lbits) {
bit = lbits ? lbits-1 : 0;
// We do sign extend
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] );
@@ -76,22 +79,28 @@ private:
return ( "01zx"[(((m_value[bit/32] & (1UL<<(bit&31)))?1:0)
| ((m_valueX[bit/32] & (1UL<<(bit&31)))?2:0))] ); }
bool bitIs0 (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return !bitIsXZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31)))==0 && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIs1 (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return false;
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIs1Extend (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIs1Extend(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31))) && !(m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIsX (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
bool bitIsXZ(int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsXZ(m_width-1);
return ( (m_valueX[bit/32] & (1UL<<(bit&31))) && 1);
return ( (m_valueX[bit/32] & (1UL<<(bit&31))));
}
bool bitIsZ (int bit) const {
if (bit<0) return false;
if (bit>=m_width) return bitIsZ(m_width-1);
return ( (~m_value[bit/32] & (1UL<<(bit&31))) && (m_valueX[bit/32] & (1UL<<(bit&31))) ); }
uint32_t bitsValue(int lsb, int nbits) const {
@@ -136,6 +145,7 @@ public:
}
// SETTERS
V3Number& setAllBitsXRemoved();
V3Number& setAllBitsX();
V3Number& setAllBitsZ();
V3Number& setAllBits0();
@@ -198,7 +208,7 @@ public:
V3Number& opBitsNonZ(const V3Number& lhs); // Z->0, 0/1/X->1
//
V3Number& opAssign (const V3Number& lhs);
V3Number& opExtendS (const V3Number& lhs); // Sign extension
V3Number& opExtendS (const V3Number& lhs, uint32_t lbits); // Sign extension
V3Number& opRedOr (const V3Number& lhs);
V3Number& opRedAnd (const V3Number& lhs);
V3Number& opRedXor (const V3Number& lhs);
@@ -250,7 +260,7 @@ public:
V3Number& opRotR (const V3Number& lhs, const V3Number& rhs);
V3Number& opRotL (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftR (const V3Number& lhs, const V3Number& rhs);
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs); // Arithmetic w/carry
V3Number& opShiftRS (const V3Number& lhs, const V3Number& rhs, uint32_t lbits); // Arithmetic w/carry
V3Number& opShiftL (const V3Number& lhs, const V3Number& rhs);
// Comparisons
V3Number& opEq (const V3Number& lhs, const V3Number& rhs);
+28 -13
View File
@@ -107,17 +107,27 @@ void V3Options::addLangExt(const string& langext, const V3LangCode& lc) {
void V3Options::addLibExtV(const string& libext) {
m_impp->addLibExtV(libext);
}
void V3Options::addDefine(const string& defline) {
void V3Options::addDefine(const string& defline, bool allowPlus) {
// Split +define+foo=value into the appropriate parts and parse
string def = defline;
string value;
string::size_type pos;
if ( ((pos=defline.find("+")) != string::npos)
|| ((pos=defline.find("=")) != string::npos)) {
value = def.substr(pos+1);
def.erase(pos);
// Optional + says to allow multiple defines on the line
// + is not quotable, as other simulators do not allow that
string left = defline;
while (left != "") {
string def = left;
string::size_type pos;
if (allowPlus && ((pos=left.find("+")) != string::npos)) {
left = left.substr(pos+1);
def.erase(pos);
} else {
left = "";
}
string value;
if ((pos=def.find("=")) != string::npos) {
value = def.substr(pos+1);
def.erase(pos);
}
V3PreShell::defineCmdLine(def,value);
}
V3PreShell::defineCmdLine(def,value);
}
void V3Options::addCppFile(const string& filename) {
@@ -622,13 +632,14 @@ void V3Options::parseOpts (FileLine* fl, int argc, char** argv) {
// Default certain options and error check
// Detailed error, since this is what we often get when run with minimal arguments
if (vFiles().empty()) {
const V3StringList& vFilesList = vFiles();
if (vFilesList.empty()) {
v3fatal("verilator: No Input Verilog file specified on command line, see verilator --help for more information\n");
}
// Default prefix to the filename
if (prefix()=="" && topModule()!="") m_prefix = string("V")+topModule();
if (prefix()=="") m_prefix = string("V")+filenameNonExt(*(vFiles().begin()));
if (prefix()=="" && vFilesList.size()>=1) m_prefix = string("V")+filenameNonExt(*(vFilesList.begin()));
if (modPrefix()=="") m_modPrefix = prefix();
// Find files in makedir
@@ -667,7 +678,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
if (argv[i][0]=='+') {
char *sw = argv[i];
if ( !strncmp (sw, "+define+", 8)) {
addDefine (string (sw+strlen("+define+")));
addDefine (string (sw+strlen("+define+")), true);
}
else if ( !strncmp (sw, "+incdir+", 8)) {
addIncDirUser (parseFileArg(optdir, string (sw+strlen("+incdir+"))));
@@ -712,6 +723,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 ( !strcmp (sw, "-P") ) { m_preprocNoLine = true; }
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; }
@@ -772,6 +784,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
case 'b': m_oCombine = flag; break;
case 'c': m_oConst = flag; break;
case 'd': m_oDedupe = flag; break;
case 'm': m_oAssemble = flag; break;
case 'e': m_oCase = flag; break;
case 'f': m_oFlopGater = flag; break;
case 'g': m_oGate = flag; break;
@@ -800,7 +813,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
m_convergeLimit = atoi(argv[i]);
}
else if ( !strncmp (sw, "-D", 2)) {
addDefine (string (sw+strlen("-D")));
addDefine (string (sw+strlen("-D")), false);
}
else if ( !strcmp (sw, "-debug") ) {
setDebugMode(3);
@@ -1212,6 +1225,7 @@ V3Options::V3Options() {
m_pinsBv = 65;
m_profileCFuncs = false;
m_preprocOnly = false;
m_preprocNoLine = false;
m_psl = false;
m_public = false;
m_savable = false;
@@ -1316,6 +1330,7 @@ void V3Options::optimize(int level) {
m_oSubstConst = flag;
m_oTable = flag;
m_oDedupe = flag;
m_oAssemble = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
+5 -1
View File
@@ -59,6 +59,7 @@ class V3Options {
bool m_preprocOnly; // main switch: -E
bool m_makeDepend; // main switch: -MMD
bool m_makePhony; // main switch: -MP
bool m_preprocNoLine;// main switch: -P
bool m_assert; // main switch: --assert
bool m_autoflush; // main switch: --autoflush
bool m_bboxSys; // main switch: --bbox-sys
@@ -138,6 +139,7 @@ class V3Options {
bool m_oCombine; // main switch: -Ob: common icode packing
bool m_oConst; // main switch: -Oc: constant folding
bool m_oDedupe; // main switch: -Od: logic deduplication
bool m_oAssemble; // main switch: -Om: assign assemble
bool m_oExpand; // main switch: -Ox: expansion of C macros
bool m_oFlopGater; // main switch: -Of: flop gater detection
bool m_oGate; // main switch: -Og: gate wire elimination
@@ -154,7 +156,7 @@ class V3Options {
private:
// METHODS
void addArg(const string& flag);
void addDefine(const string& defline);
void addDefine(const string& defline, bool allowPlus);
void addFuture(const string& flag);
void addIncDirUser(const string& incdir); // User requested
void addIncDirFallback(const string& incdir); // Low priority if not found otherwise
@@ -192,6 +194,7 @@ class V3Options {
bool preprocOnly() const { return m_preprocOnly; }
bool makeDepend() const { return m_makeDepend; }
bool makePhony() const { return m_makePhony; }
bool preprocNoLine() const { return m_preprocNoLine; }
bool underlineZero() const { return m_underlineZero; }
string bin() const { return m_bin; }
string flags() const { return m_flags; }
@@ -280,6 +283,7 @@ class V3Options {
bool oCombine() const { return m_oCombine; }
bool oConst() const { return m_oConst; }
bool oDedupe() const { return m_oDedupe; }
bool oAssemble() const { return m_oAssemble; }
bool oExpand() const { return m_oExpand; }
bool oFlopGater() const { return m_oFlopGater; }
bool oGate() const { return m_oGate; }
+2 -2
View File
@@ -1191,14 +1191,14 @@ void OrderVisitor::processMove() {
while (!m_pomReadyDomScope.empty()) {
// Start with top node on ready list's domain & scope
OrderMoveDomScope* domScopep = m_pomReadyDomScope.begin();
OrderMoveVertex* topVertexp = domScopep->readyVertices().begin();
OrderMoveVertex* topVertexp = domScopep->readyVertices().begin(); // lintok-begin-on-ref
UASSERT(topVertexp, "domScope on ready list without any nodes ready under it");
// Work on all scopes ready inside this domain
while (domScopep) {
UINFO(6," MoveDomain l="<<domScopep->domainp()<<endl);
// Process all nodes ready under same domain & scope
m_pomNewFuncp = NULL;
while (OrderMoveVertex* vertexp = domScopep->readyVertices().begin()) {
while (OrderMoveVertex* vertexp = domScopep->readyVertices().begin()) { // lintok-begin-on-ref
processMoveOne(vertexp, domScopep, 1);
}
// Done with scope/domain pair, pick new scope under same domain, or NULL if none left
+2 -1
View File
@@ -210,7 +210,8 @@ private:
virtual void visit(AstNodeModule* nodep, AstNUser*) {
if (nodep->dead()) {
UINFO(4," MOD-dead. "<<nodep<<endl); // Marked by LinkDot
} else if (nodep->level() <= 2) { // Haven't added top yet, so level 2 is the top
} else if (nodep->level() <= 2 // Haven't added top yet, so level 2 is the top
|| nodep->castPackage()) { // Likewise haven't done wrapTopPackages yet
// Add request to END of modules left to process
m_todoModps.insert(make_pair(nodep->level(),nodep));
visitModules();
+8
View File
@@ -123,6 +123,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
string vppfilename = v3Global.opt.makeDir()+"/"+v3Global.opt.prefix()+"_"+modname+".vpp";
ofstream* ofp = NULL;
ostream* osp;
bool noblanks = v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine();
if (v3Global.opt.preprocOnly()) {
osp = &cout;
} else {
@@ -133,6 +134,13 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
return;
} else {
for (deque<string>::iterator it = m_ppBuffers.begin(); it!=m_ppBuffers.end(); ++it) {
if (noblanks) {
bool blank = true;
for (string::iterator its = it->begin(); its != it->end(); ++its) {
if (!isspace(*its) && *its!='\n') { blank=false; break; }
}
if (blank) continue;
}
*osp << *it;
}
if (ofp) {
+2
View File
@@ -169,6 +169,7 @@ class V3PreLex {
int m_pslParenLevel;// PSL Parenthesis (){} counting, so we can find final ;
bool m_pslMoreNeeded;// Next // comment is really psl
bool m_defCmtSlash; // /*...*/ comment in define had \ ending
bool m_defQuote; // Definition value inside quote
string m_defValue; // Definition value being built.
int m_enterExit; // For VL_LINE, the enter/exit level
@@ -181,6 +182,7 @@ class V3PreLex {
m_pedantic = false;
m_formalLevel = 0;
m_parenLevel = 0;
m_defQuote = false;
m_defCmtSlash = false;
m_tokFilelinep = filelinep;
m_enterExit = 0;
+5 -4
View File
@@ -107,7 +107,7 @@ psl [p]sl
/* Optional directives we recognize */
<INITIAL>"`__FILE__" { static string rtnfile;
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename().c_str();
rtnfile = '"'; rtnfile += LEXP->curFilelinep()->filename();
rtnfile += '"'; yytext=(char*)rtnfile.c_str(); yyleng = rtnfile.length();
return (VP_STRING); }
<INITIAL>"`__LINE__" { static char buf[10];
@@ -125,7 +125,7 @@ psl [p]sl
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
<STRMODE>{backslash}. { yymore(); }
<STRMODE>{quote} { yy_pop_state();
if (LEXP->m_parenLevel || LEXP->m_formalLevel) { appendDefValue(yytext,yyleng); yyleng=0; }
if (LEXP->m_parenLevel || LEXP->m_defQuote) { LEXP->m_defQuote=false; appendDefValue(yytext,yyleng); yyleng=0; }
else return (VP_STRING); }
/* Stringification */
@@ -162,7 +162,7 @@ psl [p]sl
<DEFFORM><<EOF>> { linenoInc(); yy_pop_state(); yyerrorf("Unterminated ( in define formal arguments."); yyleng=0; return VP_DEFFORM; }
<DEFFORM>{crnl} { linenoInc(); appendDefValue((char*)"\n",1); } /* Include return so can maintain output line count */
<DEFFORM>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Include return so can maintain output line count */
<DEFFORM>{quote} { yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); } /* Legal only in default values */
<DEFFORM>"`\\`\"" { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>{tickquote} { appendDefValue(yytext,yyleng); } /* Maybe illegal, otherwise in default value */
<DEFFORM>[{\[] { LEXP->m_formalLevel++; appendDefValue(yytext,yyleng); }
@@ -179,7 +179,8 @@ psl [p]sl
<DEFVAL><<EOF>> { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); } /* Technically illegal, but people complained */
<DEFVAL>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return (VP_DEFVALUE); }
<DEFVAL>[\\]{crnl} { linenoInc(); appendDefValue((char*)"\\\n",2); } /* Return, AND \ is part of define value */
<DEFVAL>[^\/\*\n\r\\]+ |
<DEFVAL>{quote} { LEXP->m_defQuote=true; yy_push_state(STRMODE); yymore(); }
<DEFVAL>[^\/\*\n\r\\\"]+ |
<DEFVAL>[\\][^\n\r] |
<DEFVAL>. { appendDefValue(yytext,yyleng); }
+15 -9
View File
@@ -566,7 +566,8 @@ string V3PreProcImp::defineSubst(V3DefineRef* refp) {
bool quote = false;
bool haveDefault = false;
// Note there's a leading ( and trailing ), so parens==1 is the base parsing level
const char* cp=refp->params().c_str();
string params = refp->params(); // Must keep in scope
const char* cp=params.c_str();
if (*cp == '(') cp++;
for (; *cp; cp++) {
//UINFO(4," Parse Paren="<<paren<<" Arg="<<numArgs<<" token='"<<token<<"' Parse="<<cp<<endl);
@@ -1367,9 +1368,11 @@ int V3PreProcImp::getFinalToken(string& buf) {
}
int tok = m_finToken;
buf = m_finBuf;
if (0 && debug()>=5) fprintf (stderr,"%d: FIN: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(),
tokenName(tok), V3PreLex::cleanDbgStrg(buf).c_str());
if (0 && debug()>=5) {
string bufcln = V3PreLex::cleanDbgStrg(buf);
fprintf (stderr,"%d: FIN: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), bufcln.c_str());
}
// Track `line
const char* bufp = buf.c_str();
while (*bufp == '\n') bufp++;
@@ -1400,7 +1403,7 @@ int V3PreProcImp::getFinalToken(string& buf) {
}
}
// Track newlines in prep for next token
for (const char* cp = buf.c_str(); *cp; cp++) {
for (string::iterator cp=buf.begin(); cp!=buf.end(); ++cp) {
if (*cp == '\n') {
m_finAtBol = true;
m_finFilelinep->linenoIncInPlace(); // Increment in place to avoid new/delete calls. It's private data.
@@ -1422,8 +1425,9 @@ string V3PreProcImp::getline() {
string buf;
int tok = getFinalToken(buf/*ref*/);
if (debug()>=5) {
string bufcln = V3PreLex::cleanDbgStrg(buf);
fprintf (stderr,"%d: GETFETC: %-10s: %s\n",
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), V3PreLex::cleanDbgStrg(buf).c_str());
m_lexp->m_tokFilelinep->lineno(), tokenName(tok), bufcln.c_str());
}
if (tok==VP_EOF) {
// Add a final newline, if the user forgot the final \n.
@@ -1444,8 +1448,10 @@ string V3PreProcImp::getline() {
int len = rtnp-m_lineChars.c_str()+1;
string theLine(m_lineChars, 0, len);
m_lineChars = m_lineChars.erase(0,len); // Remove returned characters
if (debug()>=4) fprintf (stderr,"%d: GETLINE: %s\n",
m_lexp->m_tokFilelinep->lineno(),
V3PreLex::cleanDbgStrg(theLine).c_str());
if (debug()>=4) {
string lncln = V3PreLex::cleanDbgStrg(theLine);
fprintf (stderr,"%d: GETLINE: %s\n",
m_lexp->m_tokFilelinep->lineno(), lncln.c_str());
}
return theLine;
}
+3 -1
View File
@@ -71,7 +71,9 @@ public:
// These options control how the parsing proceeds
static int keepComments() { return 2; } // Return comments, 0=no, 1=yes, 2=callback
static bool keepWhitespace() { return false; }
static bool lineDirectives() { return true; } // Insert `line directives
static bool lineDirectives() { // Insert `line directives
return !(v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine());
}
static bool pedantic() { return false; } // Obey standard; Don't substitute `error
static bool optPsl();
+67 -2
View File
@@ -40,6 +40,60 @@
#include "V3Premit.h"
#include "V3Ast.h"
//######################################################################
// Structure for global state
class PremitAssignVisitor : public AstNVisitor {
private:
// NODE STATE
// AstVar::user4() // bool; occurs on LHS of current assignment
AstUser4InUse m_inuser4;
// STATE
bool m_noopt; // Disable optimization of variables in this block
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
//AstNode::user4ClearTree(); // Implied by AstUser4InUse
// LHS first as fewer varrefs
nodep->lhsp()->iterateAndNext(*this);
// Now find vars marked as lhs
nodep->rhsp()->iterateAndNext(*this);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
// it's LHS var is used so need a deep temporary
if (nodep->lvalue()) {
nodep->varp()->user4(true);
} else {
if (nodep->varp()->user4()) {
if (!m_noopt) UINFO(4, "Block has LHS+RHS var: "<<nodep<<endl);
m_noopt = true;
}
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
public:
// CONSTRUCTORS
PremitAssignVisitor(AstNodeAssign* nodep) {
UINFO(4," PremitAssignVisitor on "<<nodep<<endl);
m_noopt = false;
nodep->accept(*this);
}
virtual ~PremitAssignVisitor() {}
bool noOpt() const { return m_noopt; }
};
//######################################################################
// Premit state, as a visitor of each AstNode
@@ -49,6 +103,7 @@ private:
// AstNodeMath::user() -> bool. True if iterated already
// AstShiftL::user2() -> bool. True if converted to conditional
// AstShiftR::user2() -> bool. True if converted to conditional
// *::user4() -> See PremitAssignVisitor
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
@@ -115,11 +170,13 @@ private:
m_inWhilep->addPrecondsp(newp);
} else if (m_inTracep) {
m_inTracep->addPrecondsp(newp);
} else {
} else if (m_stmtp) {
AstNRelinker linker;
m_stmtp->unlinkFrBack(&linker);
newp->addNext(m_stmtp);
linker.relink(newp);
} else {
newp->v3fatalSrc("No statement insertion point.");
}
}
@@ -174,6 +231,14 @@ private:
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
startStatement(nodep);
{
bool noopt = PremitAssignVisitor(nodep).noOpt();
if (noopt && !nodep->user1()) {
// Need to do this even if not wide, as e.g. a select may be on a wide operator
UINFO(4,"Deep temp for LHS/RHS\n");
createDeepTemp(nodep->rhsp());
}
}
nodep->rhsp()->iterateAndNext(*this);
m_assignLhs = true;
nodep->lhsp()->iterateAndNext(*this);
@@ -287,7 +352,7 @@ private:
while (searchp && searchp->castComment()) searchp = searchp->nextp();
if (searchp
&& searchp->castDisplay()
&& nodep->filep()->sameTree(searchp->castDisplay()->filep())) {
&& nodep->filep()->sameGateTree(searchp->castDisplay()->filep())) {
// There's another display next; we can just wait to flush
} else {
UINFO(4,"Autoflush "<<nodep<<endl);
+7 -2
View File
@@ -241,6 +241,7 @@ private:
if (!nodep->user1p()) {
AstVarScope* varscp = new AstVarScope(nodep->fileline(), m_scopep, nodep);
UINFO(6," New scope "<<varscp<<endl);
if (m_aboveCellp && !m_aboveCellp->isTrace()) varscp->trace(false);
nodep->user1p(varscp);
if (!m_scopep) nodep->v3fatalSrc("No scope for var");
m_varScopes.insert(make_pair(make_pair(nodep, m_scopep), varscp));
@@ -258,8 +259,8 @@ private:
// 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*) {
// If there's a %m in the display text, we add a special node that will contain the name()
string prefix = (string)("__DOT__")+m_scopep->name();
@@ -270,6 +271,10 @@ private:
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), prefix));
if (afterp) nodep->scopeAttrp(afterp);
afterp = nodep->scopeEntrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeEntrp(new AstText(nodep->fileline(), prefix));
if (afterp) nodep->scopeEntrp(afterp);
nodep->iterateChildren(*this);
}
virtual void visit(AstScope* nodep, AstNUser*) {
-1
View File
@@ -233,7 +233,6 @@ private:
SplitPliVertex* m_pliVertexp; // Element specifying PLI ordering
V3Graph m_graph; // Scoreboard of var usages/dependencies
bool m_inDly; // Inside ASSIGNDLY
uint32_t m_stepNum; // Step number we need to ignore a edge in
V3Double0 m_statSplits; // Statistic tracking
// METHODS
+1 -1
View File
@@ -353,7 +353,7 @@ private:
== var2p->dtypep()->arrayUnpackedElements())) {
AstNode* init1p = var1p->valuep()->castInitArray();
AstNode* init2p = var2p->valuep()->castInitArray();
if (init1p->sameTree(init2p)) {
if (init1p->sameGateTree(init2p)) {
UINFO(8," Duplicate table var "<<vsc2p<<" == "<<vsc1p<<endl);
vsc1p->unlinkFrBack()->deleteTree();
return vsc2p;
+10 -7
View File
@@ -43,7 +43,6 @@ private:
// NODE STATE
// STATE
AstNodeModule* m_modp; // Current module
AstScope* m_scopetopp; // Current top scope
AstCFunc* m_initFuncp; // Trace function being built
AstCFunc* m_initSubFuncp; // Trace function being built (under m_init)
@@ -65,15 +64,19 @@ private:
return level;
}
const char* varIgnoreTrace(AstVar* nodep) {
const char* vscIgnoreTrace(AstVarScope* nodep) {
// Return true if this shouldn't be traced
// See also similar rule in V3Coverage::varIgnoreToggle
string prettyName = nodep->prettyName();
if (!nodep->isTrace()) {
AstVar* varp = nodep->varp();
string prettyName = varp->prettyName();
if (!varp->isTrace()) {
return "Verilator trace_off";
}
else if (!nodep->isTrace()) {
return "Verilator cell trace_off";
}
else if (!v3Global.opt.traceUnderscore()) {
if (prettyName.c_str()[0] == '_')
if (prettyName.size()>=1 && prettyName[0] == '_')
return "Leading underscore";
if (prettyName.find("._") != string::npos)
return "Inlined leading underscore";
@@ -164,8 +167,8 @@ private:
m_traVscp = nodep;
m_traValuep = NULL;
if (varIgnoreTrace(varp)) {
addIgnore(varIgnoreTrace(varp));
if (vscIgnoreTrace(nodep)) {
addIgnore(vscIgnoreTrace(nodep));
} else {
++m_statSigs;
if (nodep->valuep()) m_traValuep = nodep->valuep()->cloneTree(true);
+12 -12
View File
@@ -579,29 +579,29 @@ class TristateVisitor : public TristateBaseVisitor {
nodep->addStmtp(enassp);
// now append this driver to the driver logic.
AstNode* ref1p = new AstVarRef(nodep->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(nodep->fileline(), newenp, false);
andp = new AstAnd(nodep->fileline(), ref1p, ref2p);
AstNode* ref1p = new AstVarRef(refp->fileline(), newlhsp,false);
AstNode* ref2p = new AstVarRef(refp->fileline(), newenp, false);
andp = new AstAnd(refp->fileline(), ref1p, ref2p);
// or this to the others
orp = (!orp) ? andp : new AstOr(nodep->fileline(), orp, andp);
orp = (!orp) ? andp : new AstOr(refp->fileline(), orp, andp);
if (envarp) {
AstNode* ref3p = new AstVarRef(nodep->fileline(), newenp, false);
AstNode* ref3p = new AstVarRef(refp->fileline(), newenp, false);
enp = (!enp) ? ref3p : new AstOr(ref3p->fileline(), enp, ref3p);
}
AstNode* tmp = new AstNot(newenp->fileline(), new AstVarRef(newenp->fileline(), newenp, false));
undrivenp = ((!undrivenp) ? tmp
: new AstAnd(nodep->fileline(), tmp, undrivenp));
: new AstAnd(refp->fileline(), tmp, undrivenp));
}
if (!undrivenp) { // No drivers on the bus
V3Number ones(nodep->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(nodep->fileline(), ones);
V3Number ones(invarp->fileline(), lhsp->width()); ones.setAllBits1();
undrivenp = new AstConst(invarp->fileline(), ones);
}
if (!outvarp) {
// This is the final resolution of the tristate, so we apply
// the pull direction to any undriven pins.
V3Number pull(nodep->fileline(), lhsp->width());
V3Number pull(invarp->fileline(), lhsp->width());
AstPull* pullp = (AstPull*)lhsp->user3p();
if (pullp && pullp->direction() == 1) {
pull.setAllBits1();
@@ -609,9 +609,9 @@ class TristateVisitor : public TristateBaseVisitor {
} else {
pull.setAllBits0(); // default pull direction is down.
}
undrivenp = new AstAnd(nodep->fileline(), undrivenp,
new AstConst(nodep->fileline(), pull));
orp = new AstOr(nodep->fileline(), orp, undrivenp);
undrivenp = new AstAnd(invarp->fileline(), undrivenp,
new AstConst(invarp->fileline(), pull));
orp = new AstOr(invarp->fileline(), orp, undrivenp);
} else {
undrivenp->deleteTree(); undrivenp=NULL;
}
+4 -3
View File
@@ -145,9 +145,10 @@ public:
return isUsedNotDrivenBit(0, m_flags.size()/FLAGS_PER_BIT);
}
bool unusedMatch(AstVar* nodep) {
const char* regexpp = v3Global.opt.unusedRegexp().c_str();
if (!regexpp || !*regexpp) return false;
return VString::wildmatch(nodep->prettyName().c_str(), regexpp);
string regexp = v3Global.opt.unusedRegexp();
if (regexp == "") return false;
string prettyName = nodep->prettyName();
return VString::wildmatch(prettyName.c_str(), regexp.c_str());
}
void reportViolations() {
// Combine bits into overall state
+5 -5
View File
@@ -337,14 +337,14 @@ private:
// Find range of dtype we are selecting from
// Similar code in V3Const::warnSelect
int maxmsb = nodep->fromp()->dtypep()->width()-1;
int maxlsb = maxmsb - nodep->width() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
V3Number maxmsbnum (nodep->fileline(), nodep->lsbp()->width(), maxmsb);
// See if the condition is constant true
// If (maxmsb >= selected), we're in bound
AstNode* condp = new AstGte (nodep->fileline(),
new AstConst(nodep->fileline(), maxlsbnum),
new AstConst(nodep->fileline(), maxmsbnum),
nodep->lsbp()->cloneTree(false));
// See if the condition is constant true (e.g. always in bound due to constant select)
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
@@ -352,7 +352,7 @@ private:
condp->deleteTree();
}
else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
// SEL(...) -> COND(LTE(bit<=maxmsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
+28 -12
View File
@@ -164,15 +164,27 @@ private:
bool gt = condp->castGt() || condp->castGtS();
bool gte = condp->castGte() || condp->castGteS();
if (!lt && !lte && !gt && !gte)
return cantUnroll(nodep, "condition not <= or <");
AstNodeBiop* condBip = condp->castNodeBiop();
if (!condBip->rhsp()->castVarRef())
return cantUnroll(nodep, "condition not <=, <, >= or >");
AstNodeBiop* cmpInstrp = condp->castNodeBiop();
bool cmpVarLhs;
if (cmpInstrp->lhsp()->castVarRef()
&& cmpInstrp->lhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->lhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = true;
} else if (cmpInstrp->rhsp()->castVarRef()
&& cmpInstrp->rhsp()->castVarRef()->varp() == m_forVarp
&& cmpInstrp->rhsp()->castVarRef()->varScopep() == m_forVscp) {
cmpVarLhs = false;
} else if (!cmpInstrp->rhsp()->castVarRef()) {
return cantUnroll(nodep, "no variable on rhs of condition");
if (condBip->rhsp()->castVarRef()->varp() != m_forVarp
|| condBip->rhsp()->castVarRef()->varScopep() != m_forVscp)
} else {
return cantUnroll(nodep, "different variable in condition");
if (m_generate) V3Const::constifyParamsEdit(condBip->lhsp()); // rhsp may change
AstConst* constStopp = condBip->lhsp()->castConst();
}
if (m_generate) V3Const::constifyParamsEdit(cmpVarLhs ? cmpInstrp->rhsp()
: cmpInstrp->lhsp()); // rhsp/lhsp may change
AstConst* constStopp = (cmpVarLhs ? cmpInstrp->rhsp()->castConst()
: cmpInstrp->lhsp()->castConst());
if (!constStopp) return cantUnroll(nodep, "non-constant final value");
UINFO(8, " Stop expr ok: "<<constStopp<<endl);
//
@@ -217,9 +229,9 @@ private:
if (m_varAssignHit) return cantUnroll(nodep, "genvar assigned *inside* loop");
//
// Finally, we can do it
forUnroller(nodep, initp, precondsp, condp, incp, bodysp,
forUnroller(nodep, initp, precondsp, incp, bodysp,
constInitp->num(),
condBip, constStopp->num(),
cmpInstrp, constStopp->num(), cmpVarLhs,
incInstrp, constIncp->num()); nodep = NULL;
// Cleanup
return true;
@@ -227,10 +239,10 @@ private:
void forUnroller(AstNode* nodep,
AstNode* initp,
AstNode* precondsp, AstNode* condp,
AstNode* precondsp,
AstNode* incp, AstNode* bodysp,
const V3Number& numInit,
AstNodeBiop* cmpInstrp, const V3Number& numStop,
AstNodeBiop* cmpInstrp, const V3Number& numStop, bool cmpVarLhs,
AstNodeBiop* incInstrp, const V3Number& numInc) {
UINFO(4, " Unroll for var="<<numInit<<"; var<"<<numStop<<"; var+="<<numInc<<endl);
UINFO(6, " cmpI "<<cmpInstrp<<endl);
@@ -270,7 +282,11 @@ private:
UINFO(8," Looping "<<loopValue<<endl);
// if loopValue<valStop
V3Number contin (nodep->fileline(), 1);
cmpInstrp->numberOperate(contin, numStop, loopValue);
if (cmpVarLhs) {
cmpInstrp->numberOperate(contin, loopValue, numStop);
} else {
cmpInstrp->numberOperate(contin, numStop, loopValue);
}
if (contin.isEqZero()) {
break; // Done with the loop
} else {
+187 -80
View File
@@ -163,6 +163,9 @@ private:
bool m_doGenerate; // Do errors later inside generate statement
int m_dtTables; // Number of created data type tables
// TYPES
typedef map<int,AstPatMember*> PatVecMap;
// ENUMS
enum ExtendRule {
EXTEND_EXP, // Extend if expect sign and node signed, e.g. node=y in ADD(x,y), "x + y"
@@ -311,8 +314,9 @@ private:
// Just once, do the conditional, expect one bit out.
iterateCheckBool(nodep,"Conditional Test",nodep->condp(),BOTH);
// Determine sub expression widths only relying on what's in the subops
nodep->expr1p()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p());
nodep->expr2p()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p());
// CONTEXT determined, but need data type for pattern assignments
nodep->expr1p()->iterateAndNext(*this,WidthVP(vup->c()->dtypeNullp(),PRELIM).p());
nodep->expr2p()->iterateAndNext(*this,WidthVP(vup->c()->dtypeNullp(),PRELIM).p());
// Calculate width of this expression.
// First call (prelim()) vup->c()->width() is probably zero, so we'll return
// the size of this subexpression only.
@@ -686,15 +690,21 @@ private:
// Pow is special, output sign only depends on LHS sign, but function result depends on both signs
// RHS is self-determined (IEEE)
// Real if either side is real (as with AstAdd)
iterate_shift_prelim(nodep, vup); // Iterate rhsp() as self-determined
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p());
if (nodep->lhsp()->isDouble() || nodep->rhsp()->isDouble()) {
spliceCvtD(nodep->lhsp());
spliceCvtD(nodep->rhsp());
replaceWithDVersion(nodep); nodep=NULL;
return;
}
checkCvtUS(nodep->lhsp());
iterateCheckSizedSelf(nodep,"RHS",nodep->rhsp(),SELF,BOTH);
nodep->dtypeFrom(nodep->lhsp());
}
if (vup->c()->final()) {
AstNodeDType* expDTypep = vup->c()->dtypeOverridep(nodep->dtypep());
nodep->dtypeFrom(expDTypep);
@@ -898,7 +908,7 @@ private:
} else if (!basicp->isSigned() && newp->isSigned()) {
newp = new AstUnsigned(nodep->fileline(), newp);
} else {
newp = newp; // Can just remove cast
//newp = newp; // Can just remove cast
}
nodep->replaceWith(newp);
pushDeletep(nodep); nodep=NULL;
@@ -921,7 +931,7 @@ private:
: nodep->findBitDType(width, width, underDtp->numeric()));
nodep->dtypep(newDtp);
// We ignore warnings as that is sort of the point of a cast
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),SELF,FINAL,newDtp,EXTEND_EXP,false);
iterateCheck(nodep,"Cast LHS",nodep->lhsp(),CONTEXT,FINAL,newDtp,EXTEND_EXP,false);
}
if (vup->c()->final()) {
// CastSize not needed once sizes determined
@@ -1366,31 +1376,35 @@ private:
patp = newpatp;
}
else {
patp->v3error("Assignment pattern missed initializing elements: "<<memp->prettyTypeName());
if (!classp->castUnionDType()) {
patp->v3error("Assignment pattern missed initializing elements: "<<memp->prettyTypeName());
}
}
} else {
patp = it->second;
}
// Determine initial values
vdtypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (valuep->castConst()) {
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
pushDeletep(valuep); valuep=NULL;
valuep = newp;
if (patp) {
// Determine initial values
vdtypep = memp;
patp->dtypep(memp);
patp->accept(*this,WidthVP(memp,BOTH).p());
// Convert to concat for now
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (valuep->castConst()) {
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
pushDeletep(valuep); valuep=NULL;
valuep = newp;
}
}
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
}
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
if (newpatp) { pushDeletep(newpatp); newpatp=NULL; }
}
@@ -1398,34 +1412,16 @@ private:
else nodep->v3error("Assignment pattern with no members");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
}
else if (AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType()) {
typedef map<int,AstPatMember*> PatMap;
PatMap patmap;
{
int element = arrayp->declRange().left();
for (AstPatMember* patp = nodep->itemsp()->castPatMember();
patp; patp = patp->nextp()->castPatMember()) {
if (patp->keyp()) {
if (AstConst* constp = patp->keyp()->castConst()) {
element = constp->toSInt();
} else {
patp->keyp()->v3error("Assignment pattern key not supported/understood: "<<patp->keyp()->prettyTypeName());
}
}
if (patmap.find(element) != patmap.end()) {
patp->v3error("Assignment pattern key used multiple times: "<<element);
} else {
patmap.insert(make_pair(element, patp));
}
element += arrayp->declRange().leftToRightInc();
}
}
UINFO(9,"ent "<<arrayp->declRange().hi()<<" to "<<arrayp->declRange().lo()<<endl);
else if (vdtypep->castNodeArrayDType()) {
AstNodeArrayDType* arrayp = vdtypep->castNodeArrayDType();
VNumRange range = arrayp->declRange();
PatVecMap patmap = patVectorMap(nodep, range);
UINFO(9,"ent "<<range.hi()<<" to "<<range.lo()<<endl);
AstNode* newp = NULL;
for (int ent=arrayp->declRange().hi(); ent>=arrayp->declRange().lo(); --ent) {
for (int ent=range.hi(); ent>=range.lo(); --ent) {
AstPatMember* newpatp = NULL;
AstPatMember* patp = NULL;
PatMap::iterator it=patmap.find(ent);
PatVecMap::iterator it=patmap.find(ent);
if (it == patmap.end()) {
if (defaultp) {
newpatp = defaultp->cloneTree(false);
@@ -1439,37 +1435,97 @@ private:
patmap.erase(it);
}
// Determine initial values
vdtypep = arrayp->subDTypep();
// Don't want the RHS an array
patp->dtypep(arrayp->subDTypep());
if (patp) {
// Determine initial values
vdtypep = arrayp->subDTypep();
// Don't want the RHS an array
patp->dtypep(vdtypep);
// Determine values - might be another InitArray
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
// Convert to InitArray or constify immediately
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (valuep->castConst()) {
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
pushDeletep(valuep); valuep=NULL;
valuep = newp;
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
// Convert to InitArray or constify immediately
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (valuep->castConst()) {
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
pushDeletep(valuep); valuep=NULL;
valuep = newp;
}
}
if (arrayp->castUnpackArrayDType()) {
if (!newp) {
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
} else {
// We iterate hi()..lo() as that is what packed needs,
// but INITARRAY needs lo() first
newp->castInitArray()->initsp()->addHereThisAsNext(valuep);
}
} else { // Packed. Convert to concat for now.
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
}
}
if (arrayp->castUnpackArrayDType()) {
if (!newp) {
newp = new AstInitArray(nodep->fileline(), arrayp, valuep);
} else {
// We iterate hi()..lo() as that is what packed needs,
// but INITARRAY needs lo() first
newp->castInitArray()->initsp()->addHereThisAsNext(valuep);
if (newpatp) { pushDeletep(newpatp); newpatp=NULL; }
}
if (!patmap.empty()) nodep->v3error("Assignment pattern with too many elements");
if (newp) nodep->replaceWith(newp);
else nodep->v3error("Assignment pattern with no members");
//if (debug()>=9) newp->dumpTree("-apat-out: ");
pushDeletep(nodep); nodep = NULL; // Deletes defaultp also, if present
}
else if (vdtypep->castBasicDType()
&& vdtypep->castBasicDType()->isRanged()) {
AstBasicDType* bdtypep = vdtypep->castBasicDType();
VNumRange range = bdtypep->declRange();
PatVecMap patmap = patVectorMap(nodep, range);
UINFO(9,"ent "<<range.hi()<<" to "<<range.lo()<<endl);
AstNode* newp = NULL;
for (int ent=range.hi(); ent>=range.lo(); --ent) {
AstPatMember* newpatp = NULL;
AstPatMember* patp = NULL;
PatVecMap::iterator it=patmap.find(ent);
if (it == patmap.end()) {
if (defaultp) {
newpatp = defaultp->cloneTree(false);
patp = newpatp;
}
} else { // Packed. Convert to concat for now.
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
nodep->v3error("Assignment pattern missed initializing elements: "<<ent);
}
} else {
patp = it->second;
patmap.erase(it);
}
if (patp) {
// Determine initial values
vdtypep = nodep->findLogicBoolDType();
// Don't want the RHS an array
patp->dtypep(vdtypep);
// Determine values - might be another InitArray
patp->accept(*this,WidthVP(patp->dtypep(),BOTH).p());
// Convert to InitArray or constify immediately
AstNode* valuep = patp->lhssp()->unlinkFrBack();
if (valuep->castConst()) {
// Forming a AstConcat will cause problems with unsized (uncommitted sized) constants
if (AstNode* newp = WidthCommitVisitor::newIfConstCommitSize(valuep->castConst())) {
pushDeletep(valuep); valuep=NULL;
valuep = newp;
}
}
{ // Packed. Convert to concat for now.
if (!newp) newp = valuep;
else {
AstConcat* concatp = new AstConcat(patp->fileline(), newp, valuep);
newp = concatp;
newp->dtypeSetLogicSized(concatp->lhsp()->width()+concatp->rhsp()->width(),
concatp->lhsp()->width()+concatp->rhsp()->width(),
nodep->dtypep()->numeric());
}
}
}
if (newpatp) { pushDeletep(newpatp); newpatp=NULL; }
@@ -1628,8 +1684,9 @@ private:
string dispout = "";
bool inPct = false;
AstNode* argp = nodep->exprsp();
for (const char* inp = nodep->text().c_str(); *inp; inp++) {
char ch = *inp; // Breaks with iterators...
string txt = nodep->text();
for (string::const_iterator it = txt.begin(); it!=txt.end(); ++it) {
char ch = *it;
if (!inPct && ch=='%') {
inPct = true;
} else if (inPct && isdigit(ch)) {
@@ -1849,6 +1906,32 @@ private:
nodep->paramsp()->iterateAndNext(*this);
m_cellRangep = NULL;
}
virtual void visit(AstGatePin* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
nodep->rangep()->iterateAndNext(*this,WidthVP(SELF,BOTH).p());
nodep->exprp()->iterateAndNext(*this,WidthVP(CONTEXT,PRELIM).p());
nodep->dtypeFrom(nodep->rangep());
// Very much like like an pin
AstNodeDType* conDTypep = nodep->exprp()->dtypep();
int numInsts = nodep->rangep()->elementsConst();
int pinwidth = numInsts;
int conwidth = conDTypep->width();
if (conwidth == 1 && pinwidth > 1) { // Multiple connections
AstNodeDType* subDTypep = nodep->findLogicDType(1,1, conDTypep->numeric());
nodep->exprp()->iterateAndNext(*this,WidthVP(subDTypep,FINAL).p());
AstNode* newp = new AstReplicate(nodep->fileline(),
nodep->exprp()->unlinkFrBack(),
numInsts);
nodep->replaceWith(newp);
}
else {
// Eliminating so pass down all of vup
nodep->exprp()->iterateAndNext(*this,vup);
nodep->replaceWith(nodep->exprp()->unlinkFrBack());
}
pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNodeFTask* nodep, AstNUser* vup) {
// Grab width from the output variable (if it's a function)
if (nodep->didWidth()) return;
@@ -2220,7 +2303,7 @@ private:
if (newp) {} // Ununused
}
void iterate_shift_prelim(AstNodeBiop* nodep, AstNUser* vup) {
// Shifts, Pow
// Shifts
// See IEEE-2012 11.4.10 and Table 11-21.
// RHS is self-determined. RHS is always treated as unsigned, has no effect on result.
if (vup->c()->prelim()) {
@@ -2808,6 +2891,7 @@ private:
switch (nodep->type()) {
case AstType::atADD: newp = new AstAddD (fl,lhsp,rhsp); break;
case AstType::atSUB: newp = new AstSubD (fl,lhsp,rhsp); break;
case AstType::atPOW: newp = new AstPowD (fl,lhsp,rhsp); break;
case AstType::atEQ: case AstType::atEQCASE: newp = new AstEqD (fl,lhsp,rhsp); break;
case AstType::atNEQ: case AstType::atNEQCASE: newp = new AstNeqD (fl,lhsp,rhsp); break;
case AstType::atGT: case AstType::atGTS: newp = new AstGtD (fl,lhsp,rhsp); break;
@@ -2969,6 +3053,29 @@ private:
return varp;
}
PatVecMap patVectorMap(AstPattern* nodep, const VNumRange& range) {
PatVecMap patmap;
int element = range.left();
for (AstPatMember* patp = nodep->itemsp()->castPatMember();
patp; patp = patp->nextp()->castPatMember()) {
if (patp->keyp()) {
if (AstConst* constp = patp->keyp()->castConst()) {
element = constp->toSInt();
} else {
patp->keyp()->v3error("Assignment pattern key not supported/understood: "<<patp->keyp()->prettyTypeName());
}
}
if (patmap.find(element) != patmap.end()) {
patp->v3error("Assignment pattern key used multiple times: "<<element);
} else {
patmap.insert(make_pair(element, patp));
}
element += range.leftToRightInc();
}
return patmap;
}
//----------------------------------------------------------------------
// METHODS - special type detection
void assertAtStatement(AstNode* nodep, AstNUser* vup) {
+5 -4
View File
@@ -116,8 +116,8 @@ void V3Global::readFiles() {
V3Parse parser (v3Global.rootp(), &filter, &parseSyms);
// Read top module
for (V3StringList::const_iterator it = v3Global.opt.vFiles().begin();
it != v3Global.opt.vFiles().end(); ++it) {
const V3StringList& vFiles = v3Global.opt.vFiles();
for (V3StringList::const_iterator it = vFiles.begin(); it != vFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine("COMMAND_LINE",0), filename, false,
"Cannot find file containing module: ");
@@ -126,8 +126,8 @@ void V3Global::readFiles() {
// Read libraries
// To be compatible with other simulators,
// this needs to be done after the top file is read
for (V3StringSet::const_iterator it = v3Global.opt.libraryFiles().begin();
it != v3Global.opt.libraryFiles().end(); ++it) {
const V3StringSet& libraryFiles = v3Global.opt.libraryFiles();
for (V3StringSet::const_iterator it = libraryFiles.begin(); it != libraryFiles.end(); ++it) {
string filename = *it;
parser.parseFile(new FileLine("COMMAND_LINE",0), filename, true,
"Cannot find file containing library module: ");
@@ -256,6 +256,7 @@ void process () {
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
v3Global.constRemoveXs(true);
V3Global::dumpCheckGlobalTree("unknown.tree");
// Module inlining
+106 -57
View File
@@ -55,14 +55,16 @@ public:
AstVarType m_varDecl; // Type for next signal declaration (reg/wire/etc)
AstVarType m_varIO; // Type for next signal declaration (input/output/etc)
AstVar* m_varAttrp; // Current variable for attribute adding
AstRange* m_gateRangep; // Current range for gate declarations
AstCase* m_caseAttrp; // Current case statement for attribute adding
AstNodeDType* m_varDTypep; // Pointer to data type for next signal declaration
AstNodeDType* m_memDTypep; // Pointer to data type for next member declaration
int m_pinNum; // Pin number currently parsing
string m_instModule; // Name of module referenced for instantiations
AstPin* m_instParamp; // Parameters for instantiations
AstNodeModule* m_modp; // Module
int m_modTypeImpNum; // Implicit type number, incremented each module
bool m_tracingParse; // Tracing disable for parser
static int s_modTypeImpNum; // Implicit type number, incremented each module
// CONSTRUCTORS
V3ParseGrammar() {
@@ -70,14 +72,14 @@ public:
m_varDecl = AstVarType::UNKNOWN;
m_varIO = AstVarType::UNKNOWN;
m_varDTypep = NULL;
m_gateRangep = NULL;
m_memDTypep = NULL;
m_pinNum = -1;
m_instModule = "";
m_instParamp = NULL;
m_modp = NULL;
m_modTypeImpNum = 0;
m_varAttrp = NULL;
m_caseAttrp = NULL;
m_tracingParse = true;
}
static V3ParseGrammar* singletonp() {
static V3ParseGrammar singleton;
@@ -86,6 +88,9 @@ public:
// METHODS
void argWrapList(AstNodeFTaskRef* nodep);
bool allTracingOn(FileLine* fl) {
return v3Global.opt.trace() && m_tracingParse && fl->tracingOn();
}
AstNodeDType* createArray(AstNodeDType* basep, AstRange* rangep, bool isPacked);
AstVar* createVariable(FileLine* fileline, string name, AstRange* arrayp, AstNode* attrsp);
AstNode* createSupplyExpr(FileLine* fileline, string name, int value);
@@ -98,9 +103,15 @@ public:
nodep->addNext(new AstStop(fileline));
return nodep;
}
AstNode* createGatePin(AstNode* exprp) {
AstRange* rangep = m_gateRangep;
if (!rangep) return exprp;
else return new AstGatePin(rangep->fileline(), exprp, rangep->cloneTree(true));
}
void endLabel(FileLine* fl, AstNode* nodep, string* endnamep) { endLabel(fl, nodep->prettyName(), endnamep); }
void endLabel(FileLine* fl, string name, string* endnamep) {
if (fl && endnamep && *endnamep != "" && name != *endnamep) {
if (fl && endnamep && *endnamep != "" && name != *endnamep
&& name != AstNode::prettyName(*endnamep)) {
fl->v3warn(ENDLABEL,"End label '"<<*endnamep<<"' does not match begin label '"<<name<<"'");
}
}
@@ -113,7 +124,6 @@ public:
AstPackage* pkgp = SYMP->symRootp()->findIdFlat(AstPackage::dollarUnitName())->nodep()->castPackage();
if (!pkgp) {
pkgp = PARSEP->rootp()->dollarUnitPkgAddp();
GRAMMARP->m_modp = pkgp; GRAMMARP->m_modTypeImpNum = 0;
SYMP->reinsert(pkgp, SYMP->symRootp()); // Don't push/pop scope as they're global
}
return pkgp;
@@ -159,6 +169,8 @@ public:
const AstBasicDTypeKwd LOGIC = AstBasicDTypeKwd::LOGIC; // Shorthand "LOGIC"
const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT;
int V3ParseGrammar::s_modTypeImpNum = 0;
//======================================================================
// Macro functions
@@ -175,6 +187,8 @@ const AstBasicDTypeKwd LOGIC_IMPLICIT = AstBasicDTypeKwd::LOGIC_IMPLICIT;
#define VARDONEP(portp,array,attrs) GRAMMARP->createVariable((portp)->fileline(),(portp)->name(),(array),(attrs))
#define PINNUMINC() (GRAMMARP->m_pinNum++)
#define GATERANGE(rangep) { GRAMMARP->m_gateRangep = rangep; }
#define INSTPREP(modname,paramsp) { GRAMMARP->m_impliedDecl = true; GRAMMARP->m_instModule = modname; GRAMMARP->m_instParamp = paramsp; }
#define DEL(nodep) { if (nodep) nodep->deleteTree(); }
@@ -676,7 +690,7 @@ timeunits_declaration<nodep>: // ==IEEE: timeunits_declaration
package_declaration: // ==IEEE: package_declaration
packageFront package_itemListE yENDPACKAGE endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2);
SYMP->popScope($1);
GRAMMARP->endLabel($<fl>4,$1,$4); }
@@ -686,8 +700,7 @@ packageFront<modulep>:
yPACKAGE idAny ';'
{ $$ = new AstPackage($1,*$2);
$$->inLibrary(true); // packages are always libraries; don't want to make them a "top"
$$->modTrace(v3Global.opt.trace());
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -727,6 +740,11 @@ package_or_generate_item_declaration<nodep>: // ==IEEE: package_or_generate_item
| ';' { $$ = NULL; }
;
package_import_declarationList<nodep>:
package_import_declaration { $$ = $1; }
| package_import_declarationList package_import_declaration { $$ = $1->addNextNull($2); }
;
package_import_declaration<nodep>: // ==IEEE: package_import_declaration
yIMPORT package_import_itemList ';' { $$ = $2; }
;
@@ -753,9 +771,9 @@ package_import_itemObj<strp>: // IEEE: part of package_import_item
module_declaration: // ==IEEE: module_declaration
// // timeunits_declaration instead in module_item
// // IEEE: module_nonansi_header + module_ansi_header
modFront parameter_port_listE portsStarE ';'
modFront importsAndParametersE portsStarE ';'
module_itemListE yENDMODULE endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1);
@@ -765,6 +783,7 @@ module_declaration: // ==IEEE: module_declaration
{ $1->modTrace(false); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
GRAMMARP->m_tracingParse = true;
SYMP->popScope($1);
GRAMMARP->endLabel($<fl>7,$1,$7); }
//
@@ -777,19 +796,23 @@ modFront<modulep>:
// // any formal arguments, as the arguments must land in the new scope.
yMODULE lifetimeE idAny
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
$$->modTrace(v3Global.opt.trace());
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
importsAndParametersE<nodep>: // IEEE: common part of module_declaration, interface_declaration, program_declaration
// // { package_import_declaration } [ parameter_port_list ]
parameter_port_listE { $$ = $1; }
| package_import_declarationList parameter_port_listE { $$ = $1->addNextNull($2); }
;
udpFront<modulep>:
yPRIMITIVE lifetimeE idAny
{ $$ = new AstPrimitive($1,*$3); $$->inLibrary(true);
$$->modTrace(false);
$$->addStmtp(new AstPragma($1,AstPragmaType::INLINE_MODULE));
PARSEP->fileline()->tracingOn(false);
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
GRAMMARP->m_tracingParse = false;
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -824,8 +847,7 @@ paramPortDeclOrArgList<nodep>: // IEEE: list_of_param_assignments + { parameter_
paramPortDeclOrArg<nodep>: // IEEE: param_assignment + parameter_port_declaration
// // We combine the two as we can't tell which follows a comma
param_assignment { $$ = $1; }
| parameter_port_declarationFront param_assignment { $$ = $2; }
parameter_port_declarationFrontE param_assignment { $$ = $2; }
;
portsStarE<nodep>: // IEEE: .* + list_of_ports + list_of_port_declarations + empty
@@ -995,7 +1017,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
// // timeunits_delcarationE is instead in program_item
pgmFront parameter_port_listE portsStarE ';'
program_itemListE yENDPROGRAM endLabelE
{ $1->modTrace(v3Global.opt.trace() && $1->fileline()->tracingOn()); // Stash for implicit wires, etc
{ $1->modTrace(GRAMMARP->allTracingOn($1->fileline())); // Stash for implicit wires, etc
if ($2) $1->addStmtp($2); if ($3) $1->addStmtp($3);
if ($5) $1->addStmtp($5);
SYMP->popScope($1);
@@ -1007,8 +1029,7 @@ program_declaration: // IEEE: program_declaration + program_nonansi_header + pr
pgmFront<modulep>:
yPROGRAM lifetimeE idAny/*new_program*/
{ $$ = new AstModule($1,*$3); $$->inLibrary(PARSEP->inLibrary()||PARSEP->inCellDefine());
$$->modTrace(v3Global.opt.trace());
GRAMMARP->m_modp = $$; GRAMMARP->m_modTypeImpNum = 0;
$$->modTrace(GRAMMARP->allTracingOn($$->fileline()));
PARSEP->rootp()->addModulep($$);
SYMP->pushNew($$); }
;
@@ -1133,10 +1154,13 @@ parameter_declarationFront: // IEEE: parameter_declaration w/o assignment
//UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
;
parameter_port_declarationFront: // IEEE: parameter_port_declaration w/o assignment
parameter_port_declarationFrontE: // IEEE: parameter_port_declaration w/o assignment
// // IEEE: parameter_declaration (minus assignment)
parameter_declarationFront { }
//
varGParamReset implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
| varGParamReset data_type { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
| implicit_typeE { /*VARRESET-in-varGParam*/ VARDTYPE($1); }
| data_type { /*VARRESET-in-varGParam*/ VARDTYPE($1); }
//UNSUP varGParamReset yTYPE { /*VARRESET-in-varGParam*/ VARDTYPE($2); }
//UNSUP data_type { VARDTYPE($1); }
//UNSUP yTYPE { VARDTYPE($1); }
;
@@ -1323,10 +1347,10 @@ data_typeBasic<dtypep>: // IEEE: part of data_type
data_typeNoRef<dtypep>: // ==IEEE: data_type, excluding class_type etc references
data_typeBasic { $$ = $1; }
| struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
GRAMMARP->m_modp,VFlagChildDType(),$1),$2,true); }
| enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->m_modTypeImpNum++),
GRAMMARP->m_modp,VFlagChildDType(),$1); }
| struct_unionDecl packed_dimensionListE { $$ = GRAMMARP->createArray(new AstDefImplicitDType($1->fileline(),"__typeimpsu"+cvtToStr(GRAMMARP->s_modTypeImpNum++),
SYMP,VFlagChildDType(),$1),$2,true); }
| enumDecl { $$ = new AstDefImplicitDType($1->fileline(),"__typeimpenum"+cvtToStr(GRAMMARP->s_modTypeImpNum++),
SYMP,VFlagChildDType(),$1); }
| ySTRING { $$ = new AstBasicDType($1,AstBasicDTypeKwd::STRING); }
| yCHANDLE { $$ = new AstBasicDType($1,AstBasicDTypeKwd::CHANDLE); }
//UNSUP yEVENT { UNSUP }
@@ -1576,8 +1600,9 @@ implicit_typeE<dtypep>: // IEEE: part of *data_type_or_implicit
type_declaration<nodep>: // ==IEEE: type_declaration
// // Use idAny, as we can redeclare a typedef on an existing typedef
yTYPEDEF data_type idAny variable_dimensionListE ';' { $$ = new AstTypedef($<fl>1, *$3, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
SYMP->reinsert($$); }
yTYPEDEF data_type idAny variable_dimensionListE dtypeAttrListE ';'
/**/ { $$ = new AstTypedef($<fl>1, *$3, $5, VFlagChildDType(), GRAMMARP->createArray($2,$4,false));
SYMP->reinsert($$); }
//UNSUP yTYPEDEF id/*interface*/ '.' idAny/*type*/ idAny/*type*/ ';' { $$ = NULL; $1->v3error("Unsupported: SystemVerilog 2005 typedef in this context"); } //UNSUP
// // Combines into above "data_type id" rule
// // Verilator: Not important what it is in the AST, just need to make sure the yaID__aTYPE gets returned
@@ -1588,6 +1613,20 @@ type_declaration<nodep>: // ==IEEE: type_declaration
//UNSUP yTYPEDEF yCLASS idAny ';' { $$ = NULL; $$ = new AstTypedefFwd($<fl>1, *$3); SYMP->reinsert($$); }
;
dtypeAttrListE<nodep>:
/* empty */ { $$ = NULL; }
| dtypeAttrList { $$ = $1; }
;
dtypeAttrList<nodep>:
dtypeAttr { $$ = $1; }
| dtypeAttrList dtypeAttr { $$ = $1->addNextNull($2); }
;
dtypeAttr<nodep>:
yVL_PUBLIC { $$ = new AstAttrOf($1,AstAttrType::DT_PUBLIC); }
;
//************************************************
// Module Items
@@ -1909,7 +1948,7 @@ sigAttr<nodep>:
| yVL_PUBLIC_FLAT { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT); v3Global.dpi(true); }
| yVL_PUBLIC_FLAT_RD { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RD); v3Global.dpi(true); }
| yVL_PUBLIC_FLAT_RW { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true); }
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true);
| yVL_PUBLIC_FLAT_RW attr_event_control { $$ = new AstAttrOf($1,AstAttrType::VAR_PUBLIC_FLAT_RW); v3Global.dpi(true);
$$ = $$->addNext(new AstAlwaysPublic($1,$2,NULL)); }
| yVL_ISOLATE_ASSIGNMENTS { $$ = new AstAttrOf($1,AstAttrType::VAR_ISOLATE_ASSIGNMENTS); }
| yVL_SC_BV { $$ = new AstAttrOf($1,AstAttrType::VAR_SC_BV); }
@@ -1999,9 +2038,11 @@ instnameList<nodep>:
| instnameList ',' instnameParen { $$ = $1->addNext($3); }
;
instnameParen<nodep>:
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2); }
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2); }
instnameParen<cellp>:
id instRangeE '(' cellpinList ')' { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,$4, GRAMMARP->m_instParamp,$2);
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
| id instRangeE { $$ = new AstCell($<fl>1,*$1,GRAMMARP->m_instModule,NULL,GRAMMARP->m_instParamp,$2);
$$->trace(GRAMMARP->allTracingOn($<fl>1)); }
//UNSUP instRangeE '(' cellpinList ')' { UNSUP } // UDP
// // Adding above and switching to the Verilog-Perl syntax
// // causes a shift conflict due to use of idClassSel inside exprScope.
@@ -3243,62 +3284,66 @@ gateUnsupList<nodep>:
| gateUnsupList ',' gateUnsup { $$ = $1->addNext($3); }
;
gateRangeE<nodep>:
instRangeE { $$ = $1; GATERANGE($1); }
;
gateBuf<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
;
gateBufif0<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8),$6)); DEL($2); }
;
gateBufif1<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8,$6)); DEL($2); }
;
gateNot<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
;
gateNotif0<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,new AstNot($3,$8), new AstNot($3, $6))); DEL($2); }
;
gateNotif1<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' expr ',' expr ')'
gateIdE gateRangeE '(' variable_lvalue ',' gatePinExpr ',' gatePinExpr ')'
{ $$ = new AstAssignW ($3,$4,new AstBufIf1($3,$8, new AstNot($3,$6))); DEL($2); }
;
gateAnd<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateAndPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
;
gateNand<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateAndPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateAndPinList ')'
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
;
gateOr<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateOrPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
;
gateNor<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateOrPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateOrPinList ')'
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
;
gateXor<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateXorPinList ')'
{ $$ = new AstAssignW ($3,$4,$6); DEL($2); }
;
gateXnor<nodep>:
gateIdE instRangeE '(' variable_lvalue ',' gateXorPinList ')'
gateIdE gateRangeE '(' variable_lvalue ',' gateXorPinList ')'
{ $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); DEL($2); }
;
gatePullup<nodep>:
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); DEL($2); }
gateIdE gateRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, true); DEL($2); }
;
gatePulldown<nodep>:
gateIdE instRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); DEL($2); }
gateIdE gateRangeE '(' variable_lvalue ')' { $$ = new AstPull ($3, $4, false); DEL($2); }
;
gateUnsup<nodep>:
gateIdE instRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); DEL($2); }
gateIdE gateRangeE '(' gateUnsupPinList ')' { $$ = new AstImplicit ($3,$4); DEL($2); }
;
gateIdE:
@@ -3307,20 +3352,24 @@ gateIdE:
;
gateAndPinList<nodep>:
expr { $$ = $1; }
| gateAndPinList ',' expr { $$ = new AstAnd($2,$1,$3); }
gatePinExpr { $$ = $1; }
| gateAndPinList ',' gatePinExpr { $$ = new AstAnd($2,$1,$3); }
;
gateOrPinList<nodep>:
expr { $$ = $1; }
| gateOrPinList ',' expr { $$ = new AstOr($2,$1,$3); }
gatePinExpr { $$ = $1; }
| gateOrPinList ',' gatePinExpr { $$ = new AstOr($2,$1,$3); }
;
gateXorPinList<nodep>:
expr { $$ = $1; }
| gateXorPinList ',' expr { $$ = new AstXor($2,$1,$3); }
gatePinExpr { $$ = $1; }
| gateXorPinList ',' gatePinExpr { $$ = new AstXor($2,$1,$3); }
;
gateUnsupPinList<nodep>:
expr { $$ = $1; }
| gateUnsupPinList ',' expr { $$ = $1->addNext($3); }
gatePinExpr { $$ = $1; }
| gateUnsupPinList ',' gatePinExpr { $$ = $1->addNext($3); }
;
gatePinExpr<nodep>:
expr { $$ = GRAMMARP ->createGatePin($1); }
;
strengthSpecE: // IEEE: drive_strength + pullup_strength + pulldown_strength + charge_strength - plus empty
@@ -3757,7 +3806,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());
else nodep->trace(allTracingOn(nodep->fileline()));
// Remember the last variable created, so we can attach attributes to it in later parsing
GRAMMARP->m_varAttrp = nodep;
+1 -1
View File
@@ -673,7 +673,7 @@ sub compile {
if ($param{make_pli}) {
$self->oprint("Compile vpi\n");
my @cmd = ('g++', @{$param{pli_flags}}, "-DIS_VPI", "$self->{t_dir}/$self->{name}.cpp");
my @cmd = ('c++', @{$param{pli_flags}}, "-DIS_VPI", "$self->{t_dir}/$self->{name}.cpp");
$self->_run(logfile=>"$self->{obj_dir}/pli_compile.log",
fails=>$param{fails},
+2 -2
View File
@@ -54,10 +54,10 @@ module t (/*AUTOARG*/
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
sum <= '0;
end
else if (cyc<10) begin
sum <= 64'h0;
sum <= '0;
end
else if (cyc<90) begin
end
+5
View File
@@ -12,7 +12,12 @@ module t (/*AUTOARG*/
logic [1:0] [3:0] [3:0] array_simp; // big endian array
logic [3:0] array_oned;
initial begin
array_oned = '{2:1'b1, 0:1'b1, default:1'b0};
if (array_oned != 4'b0101) $stop;
array_simp[0] = '{ 4'd3, 4'd2, 4'd1, 4'd0};
if (array_simp[0] !== 16'h3210) $stop;
+1 -1
View File
@@ -33,7 +33,7 @@ module t (/*AUTOARG*/
assert (0) else $info;
assert (0) else $info("Info message");
assert (0) else $info("Info message, cyc=%d", cyc);
InWarningBlock: assert (0) else $warning("Warning....");
InWarningBlock: assert (0) else $warning("Warning.... 1.0=%f 2.0=%f", 1.0, 2.0);
InErrorBlock: assert (0) else $error("Error....");
assert (0) else $fatal(1,"Fatal....");
`endif
+5 -5
View File
@@ -8,17 +8,17 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
verilator_flags2 => ["--stats --profile-cfuncs"],
);
verilator_flags2 => ["--stats"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 9);
}
execute (
check_finished=>1,
);
check_finished=>1,
);
ok(1);
1;
+44
View File
@@ -0,0 +1,44 @@
#!/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.
$Self->{vlt} or $Self->skip("Verilator only test");
top_filename("t/t_case_huge.v");
compile (
verilator_flags2 => ["--stats --profile-cfuncs -CFLAGS '-pg' -LDFLAGS '-pg'"],
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Tables created\s+(\d+)/i, 10);
file_grep ($Self->{stats}, qr/Optimizations, Combined CFuncs\s+(\d+)/i, 10);
}
unlink $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
$ENV{GMON_OUT_PREFIX} = "$Self->{obj_dir}/gmon.out";
execute (
check_finished=>1,
);
my $gmon_path;
$gmon_path = $_ foreach (glob "$Self->{obj_dir}/gmon.out.*");
$gmon_path or $Self->error("Profiler did not create a gmon.out");
(my $gmon_base = $gmon_path) =~ s!.*[/\\]!!;
$Self->_run(cmd=>["cd $Self->{obj_dir} && gprof $Self->{VM_PREFIX} $gmon_base > gprof.out"],
check_finished=>0);
$Self->_run(cmd=>["cd $Self->{obj_dir} && $ENV{VERILATOR_ROOT}/bin/verilator_profcfunc gprof.out > cfuncs.out"],
check_finished=>0);
file_grep ("$Self->{obj_dir}/cfuncs.out", qr/Overall summary by/);
ok(1);
1;
+23
View File
@@ -0,0 +1,23 @@
#!/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 (
v_flags2 => ["--stats"],
);
execute (
check_finished=>1,
);
if ($Self->{vlt}) {
file_grep ($Self->{stats}, qr/Optimizations, Gate assign merged\s+(\d+)/i, 28);
};
ok(1);
1;
+100
View File
@@ -0,0 +1,100 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Jie Xu.
//
// change these two parameters to see the speed differences
`define DATA_WIDTH 8
`define REP_COUNT4 `DATA_WIDTH/4
`define REP_COUNT2 `DATA_WIDTH/2
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
reg [3:0] count4 = 0;
reg [1:0] count2 = 0;
reg [`DATA_WIDTH-1:0] a = {`REP_COUNT4{4'b0000}};
reg [`DATA_WIDTH-1:0] b = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] c = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] d = {`REP_COUNT4{4'b1111}};
reg [`DATA_WIDTH-1:0] res1;
reg [`DATA_WIDTH-1:0] res2;
reg [`DATA_WIDTH-1:0] res3;
reg [`DATA_WIDTH-1:0] res4;
drv1 t_drv1 [`DATA_WIDTH-1:0] (.colSelA(a), .datao(res1));
drv2 t_drv2 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .datao(res2));
drv3 t_drv3 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .datao(res3));
drv4 t_drv4 [`DATA_WIDTH-1:0] (.colSelA(a), .colSelB(b), .colSelC(c), .colSelD(d), .datao(res4));
always@(posedge clk)
begin
count2 <= count2 + 1;
count4 <= count4 + 1;
a <= {`REP_COUNT4{count4}};
b <= {`REP_COUNT4{count4}};
c <= {`REP_COUNT2{count2}};
d <= {`REP_COUNT2{count2}};
if (res1 != (a)) begin
$stop;
end
if (res2 != (a&b)) begin
$stop;
end
if (res3 != (a&b&c)) begin
$stop;
end
if (res4 != (a&b&c&d)) begin
$stop;
end
if (count4 > 10) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module drv1
(input colSelA,
output datao
);
assign datao = colSelA;
endmodule
module drv2
(input colSelA,
input colSelB,
output datao
);
assign datao = colSelB & colSelA;
endmodule
module drv3
(input colSelA,
input colSelB,
input colSelC,
output datao
);
assign datao = colSelB & colSelA & colSelC;
endmodule
module drv4
(input colSelA,
input colSelB,
input colSelC,
input colSelD,
output datao
);
assign datao = colSelB & colSelA & colSelC & colSelD;
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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;
+71
View File
@@ -0,0 +1,71 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2004 by Jie Xu.
//
// The test was added together with the concat optimization.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc; initial cyc=1;
reg [31:0] in_a;
reg [31:0] in_b;
reg [31:0] in_c;
reg [31:0] in_d;
reg [31:0] in_e;
reg [15:0] in_f;
wire [31:0] in_g;
assign in_g = in_a << 4;
reg [31:0] out_x;
reg [31:0] out_y;
reg [31:0] out_z;
reg [31:0] out_o;
reg [31:0] out_p;
reg [31:0] out_q;
assign out_x = {in_a[31:16] & in_f, in_a[15:0] & in_f};
assign out_y = {in_a[31:18] & in_b[31:18], in_a[17:0] & in_b[17:0]};
assign out_z = {in_c[31:14] & in_d[31:14] & in_e[31:14], in_c[13:0] & in_d[13:0] & in_e[13:0]};
assign out_o = out_z | out_y;
assign out_p = {in_a[31:16] & in_f | in_e[31:16], in_a[15:0] & in_f | in_e[15:0]};
assign out_q = {{in_a[31:25] ^ in_g[31:25], in_a[24:16] ^ in_g[24:16]}, {in_a[15:5] ^ in_g[15:5], in_a[4:0] ^ in_g[4:0]}};
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
in_a <= cyc;
in_b <= cyc + 1;
in_c <= cyc + 3;
in_d <= cyc + 8;
in_e <= cyc;
in_f <= cyc[15:0];
if (out_x != (in_a & {2{in_f}}))
$stop;
if (out_y != (in_a&in_b))
$stop;
if (out_z != (in_e&in_d&in_c))
$stop;
if (out_o != (((in_a&in_b)|(in_c&in_e&in_d))))
$stop;
if (out_p != (in_a & {2{in_f}} | in_e))
$stop;
if (out_q != (in_a ^ in_g))
$stop;
if (cyc==100) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["-Wno-UNOPTFLAT -Wno-WIDTH"]
);
execute (
check_finished=>1,
);
ok(1);
1;
+39
View File
@@ -0,0 +1,39 @@
// DESCRIPTION: Verilator: Simple test of unoptflat
//
// Trigger the DETECTARRAY error on packed structure.
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Jie Xu.
localparam ID_MSB = 1;
module t (/*AUTOARG*/
// Inputs
clk,
res
);
input clk;
output [8:0][8:0] res;
logic a = 1'b1;
logic [8:0] b [8:0]; // where the error is reported
logic [8:0][8:0] c; // where the error is reported
// following just to make c as circular
assign c[0] = c[0] | a << 1;
assign b[0] = b[0] | a << 2;
assign res[0] = c[0];
assign res[1] = b[0];
always @(posedge clk or negedge clk) begin
if (res != 0) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+19
View File
@@ -17,6 +17,7 @@ if (!-r "$root/.git") {
} else {
uint();
printfll();
cstr();
}
ok(1);
@@ -67,4 +68,22 @@ sub printfll {
}
}
sub cstr {
my $files = "src/*.c* src/*.h include/*.c* include/*.h test_c/*.c* test_regress/t/*.c* test_regress/t/*.h";
my $cmd = "cd $root && grep -n -P 'c_str|begin|end' $files | sort";
print "C $cmd\n";
my $grep = `$cmd`;
my %names;
foreach my $line (split /\n/, $grep) {
if ($line =~ /^([^:]+).*\(\)[a-z0-9_().->]*[.->]+(c_str|r?begin|r?end)\(\)/) {
next if $line =~ /lintok-begin-on-ref/;
print "$line\n";
$names{$1} = 1;
}
}
if (keys %names) {
$Self->error("Files with potential c_str() lifetime issue: ",join(' ',sort keys %names));
}
}
1;
+14
View File
@@ -27,6 +27,7 @@ module sub (input integer inst);
import "DPI-C" context function int dpic_line();
import "DPI-C" context function int dpic_save(int value);
import "DPI-C" context function int dpic_restore();
import "DPI-C" context function int unsigned dpic_getcontext();
int result;
@@ -49,4 +50,17 @@ module sub (input integer inst);
if (dpic_restore() != 23+inst) $stop;
endtask
int unsigned cntxt1;
int unsigned cntxt2;
initial begin
cntxt1 = dpic_getcontext();
begin : caller_context
// call from a different scope - should still get the context of the function declaration
cntxt2 = dpic_getcontext();
end
// svContext should be the context of the function declaration, not the context of the function call
if (cntxt1 != cntxt2) $stop;
end
endmodule
+7
View File
@@ -42,6 +42,7 @@ extern "C" {
extern int dpic_line();
extern int dpic_save(int value);
extern int dpic_restore();
extern unsigned dpic_getcontext();
}
#endif
@@ -126,3 +127,9 @@ int dpic_restore() {
return 0;
}
}
unsigned dpic_getcontext() {
svScope scope = svGetScope();
printf("%%Info: svGetScope returned scope (%p) with name %s\n", scope, svGetNameFromScope(scope));
return (unsigned) (uintptr_t) scope;
}
+26
View File
@@ -0,0 +1,26 @@
// -*- 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, 2006 by Wilson Snyder.
#include <verilated.h>
#include "Vt_enum_public.h"
#include "Vt_enum_public_p3.h"
#include "Vt_enum_public_p62.h"
int main (int argc, char *argv[]) {
Vt_enum_public *topp = new Vt_enum_public;
Verilated::debug(0);
// Make sure public tag worked
if (Vt_enum_public_p3::ZERO || Vt_enum_public_p3::ONE) {}
if (Vt_enum_public_p62::ZERO || Vt_enum_public_p62::ALLONE) {}
for (int i = 0; i < 10; i++) {
topp->eval();
}
}
+26
View File
@@ -0,0 +1,26 @@
#!/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.
if ($Self->{vlt}) {
compile (
verilator_flags2 => ["--exe $Self->{t_dir}/$Self->{name}.cpp"],
make_top_shell => 0,
make_main => 0,
);
} else {
compile (
);
}
execute (
check_finished=>1,
);
ok(1);
1;
+33
View File
@@ -0,0 +1,33 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
package p3;
typedef enum logic [2:0] {
ZERO = 3'b0,
ONE = 3'b1 } e3_t /*verilator public*/;
endpackage
package p62;
typedef enum logic [62:0] {
ZERO = '0,
ALLONE = '1 } e62_t /*verilator public*/;
endpackage
module t (/*AUTOARG*/);
enum integer {
EI_A,
EI_B,
EI_C
} m_state;
initial begin
m_state = EI_A;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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 (
v_flags2 => ["-f t/t_flag_define.vc"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+61
View File
@@ -0,0 +1,61 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder
`define STRINGIFY(x) `"x`"
module t;
initial begin
`ifdef D1A
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D2A
if (`STRINGIFY(`D2A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D3A
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D3B
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D4A
if (`STRINGIFY(`D4A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D4B
if (`STRINGIFY(`D4B) !== "") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D5A
if (`STRINGIFY(`D5A) !== "VALA") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
`ifdef D5A
if (`STRINGIFY(`D5B) !== "VALB") $stop;
`else
$write("%%Error: Missing define\n"); $stop;
`endif
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+7
View File
@@ -0,0 +1,7 @@
+define+D1A
+define+D2A=VALA
+define+D3A+D3B
+define+D4A=VALA+D4B
+define+D5A=VALA+D5B=VALB
// Quotes do NOT escape the plus
//+define+D5A="VALA+D5B"+D5C
+3 -3
View File
@@ -10,13 +10,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{vlt} or $Self->skip("Verilator only test");
$Self->_run (cmd=>["cd $Self->{obj_dir}"
." && g++ -c ../../t/t_flag_ldflags_a.cpp"
." && c++ -c ../../t/t_flag_ldflags_a.cpp"
." && ar r t_flag_ldflags_a.a t_flag_ldflags_a.o"
." && ranlib t_flag_ldflags_a.a "],
check_finished=>0);
$Self->_run (cmd=>["cd $Self->{obj_dir}"
." && g++ -fPIC -c ../../t/t_flag_ldflags_so.cpp"
." && g++ -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"],
." && c++ -fPIC -c ../../t/t_flag_ldflags_so.cpp"
." && c++ -shared -o t_flag_ldflags_so.so -lc t_flag_ldflags_so.o"],
check_finished=>0);
compile (
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 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.
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
v_flags2 => ["--lint-only -Wno-WIDTH"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
);
ok(1);
1;
+20
View File
@@ -0,0 +1,20 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module t;
// width warnings off due to command line
wire A = 15'd1234;
// width warnings off due to command line + manual switch
// verilator lint_off WIDTH
wire B = 15'd1234;
// this turnon does nothing as off on command line
// verilator lint_on WIDTH
wire C = 15'd1234;
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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;
+88
View File
@@ -0,0 +1,88 @@
// 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;
// Take CRC data and apply to testblock inputs
wire [7:0] a = crc[7:0];
wire [7:0] b = crc[15:8];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [63:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[63:0]),
// Inputs
.clk (clk),
.a (a[7:0]),
.b (b[7:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {out};
// 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'h0908a1f2194d24ee
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
clk, a, b
);
input clk;
input [7:0] a;
input [7:0] b;
output reg [63:0] out;
and u0[7:0] (out[7:0], a[7:0], b[7:0]);
and u1[7:0] (out[15:8], a[0], b[7:0]);
and u2[7:0] (out[23:16], a[0], b[0]);
nand u3[7:0] (out[31:24], a[0], b[7:0]);
or u4[7:0] (out[39:32], a[0], b[7:0]);
nor u5[7:0] (out[47:40], a[0], b[7:0]);
xor u6[7:0] (out[55:48], a[0], b[7:0]);
xnor u7[7:0] (out[63:56], a[0], b[7:0]);
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+49
View File
@@ -0,0 +1,49 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Wilson Snyder.
// bug749
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
genvar g;
for (g=1; g<3; ++g) begin : gblk
sub2 #(.IN(g)) u ();
//sub #(.IN(g)) u2 ();
end
sub1 #(.IN(0)) u ();
always @ (posedge clk) begin
if (t.u.IN != 0) $stop;
if (t.u.FLAVOR != 1) $stop;
//if (t.u2.IN != 0) $stop; // This should be not found
if (t.gblk[1].u.IN != 1) $stop;
if (t.gblk[2].u.IN != 2) $stop;
if (t.gblk[1].u.FLAVOR != 2) $stop;
if (t.gblk[2].u.FLAVOR != 2) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
module sub1 (/*AUTOARG*/);
parameter [31:0] IN = 99;
parameter FLAVOR = 1;
`ifdef TEST_VERBOSE
initial $display("%m");
`endif
endmodule
module sub2 (/*AUTOARG*/);
parameter [31:0] IN = 99;
parameter FLAVOR = 2;
`ifdef TEST_VERBOSE
initial $display("%m");
`endif
endmodule
+2 -2
View File
@@ -27,10 +27,10 @@ module t (/*AUTOARG*/
// finish report
always @ (posedge clk)
if (cnt==SIZE) begin : if_cnt_finish
if (cnt==SIZE) begin : \0escaped___name
$write("*-* All Finished *-*\n");
$finish;
end : if_cnt_finish
end : \0escaped___name
generate
for (i=0; i<SIZE; i=i+1) begin : generate_for
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--lint-only"],
verilator_make_gcc => 0,
make_top_shell => 0,
make_main => 0,
);
ok(1);
1;
+51
View File
@@ -0,0 +1,51 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2014 by Jie Xu.
//bug692
module t (/*AUTOARG*/
// Inputs
clk
);
input wire clk;
wire [31:0] result;
test_if #(.id(3)) s();
sub_test U_SUB_TEST(s.a.b, result); // the line causing error
endmodule : t
// ---------------------------------------------------------------------------
module sub_test
(
input [31:0] b,
output [31:0] c
);
assign c = b;
endmodule
// ---------------------------------------------------------------------------
interface test_if
#(parameter id = 0)
();
typedef struct packed {
logic a;
logic [31:0] b;
} aType;
aType a;
typedef struct packed {
logic c;
logic [31:0] d;
} bType;
bType b;
modport master (input a, output b);
endinterface
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ['--x-assign 0'],
);
execute (
);
ok(1);
1;
+11
View File
@@ -0,0 +1,11 @@
module t(y);
output [3:0] y;
// bug775
// verilator lint_off WIDTH
assign y = ((0/0) ? 1 : 2) % 0;
initial begin
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+2
View File
@@ -5,6 +5,8 @@
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
`define is_near_real(a,b) ($abs((a)-(b)) < (((a)/(b))*0.0001))
module t (/*AUTOARG*/
// Inputs
clk
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
verilator_flags2 => ["-CFLAGS '-DVL_DEBUG -ggdb -O0'"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+77
View File
@@ -0,0 +1,77 @@
// 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;
//bug765; disappears if add this wire
//wire [7:0] a = (crc[7] ? {7'b0,crc[0]} : crc[7:0]); // favor low values
wire [7:0] a = crc[7:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [15:0] y; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.y (y[15:0]),
// Inputs
.a (a[7:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {48'h0, y};
// 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'h0
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
y,
// Inputs
a
);
input signed [7:0] a;
output [15:0] y;
// verilator lint_off WIDTH
assign y = ~66'd0 <<< {4{a}};
// verilator lint_on WIDTH
endmodule
+63 -1
View File
@@ -5,8 +5,16 @@
`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); fail='1; end while(0)
`define checkf(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d: got=%f exp=%f\n", `__FILE__,`__LINE__, (gotv), (expv)); fail='1; end while(0)
`ifdef VERILATOR
`define c(v,vs) ($c(vs)) // Don't constify a value
`else
`define c(v,vs) (v)
`endif
module t (/*AUTOARG*/);
module t (/*AUTOARG*/
// Outputs
ow4_u
);
bit fail;
@@ -15,6 +23,10 @@
reg [2:0] w3_u;
reg [3:0] w4_u;
reg [4:0] w5_u;
reg [5:0] w6_u;
reg [15:0] w16a_u;
reg [15:0] w16_u;
reg [31:0] w32_u;
real r;
reg signed [4:0] bug754_a;
@@ -116,8 +128,58 @@
w4_u = (w3_u >> 2'b11) >> 1;
`checkh(w4_u, 4'b0000);
// bug766
w16a_u = 16'h1234;
w16_u = (w16a_u >> 16) >>> 32'h7ffffff1;
`checkh(w16_u, 16'h0000);
// bug768
w4_s = 4'sd4;
w4_u = $signed(5'd1 > w4_s-w4_s);
`checkh(w4_u, 4'b1111);
w4_s = `c(4,"4"); // Eval at runtime
w4_u = $signed(5'd1 > w4_s-w4_s);
`checkh(w4_u, 4'b1111);
// bug772
w4_s = w4_u << 1 <<< 0/0;
`ifndef VERILATOR // In v4 can't check value as not 4-state
`checkh(w4_s, 4'bxxxx);
`endif
// bug773
w5_u = `c(31, 31);
w5_s = w5_u >> ((w5_u ? 1 : 2) << w5_u);
`checkh(w5_s, 5'b0);
// bug774
w4_u = `c(4, 5);
w6_u = `c(6, 35);
w4_u = 64'd0 | (w4_u << w6_u);
`checkh(w4_u, 0);
// bug776
w4_u = `c(4, 1);
w4_u = (w4_u >> w4_u) ^~ (w4_u >> w4_u);
`checkh(w4_u, 4'b1111);
// bug828
// verilator lint_off WIDTH
w32_u = 32'(signed'({4'b0001,5'b10000}) << 3);
`checkh(w32_u, 32'h0000_0180);
w32_u = 32'(signed'({4'b0011,5'b10000}) << 3);
`checkh(w32_u, 32'h0000_0380);
// verilator lint_on WIDTH
w32_u = 32'(signed'({4'b0011,5'b10000})) << 3; // Check no width warning
`checkh(w32_u, 32'h0000_0380);
if (fail) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
// bug775
output [3:0] ow4_u; // Must be consumed
assign ow4_u = ((0/0) ? 1 : 2) % 0;
endmodule
+2
View File
@@ -25,6 +25,7 @@ module t (/*AUTOARG*/
initial begin
// Check constant propagation
// Note $abs is not defined in SystemVerilog (as of 2012)
check(`__LINE__, $ceil(-1.2), -1);
check(`__LINE__, $ceil(1.2), 2);
check(`__LINE__, $exp(1.2), 3.3201169227365472380597566370852291584014892578125);
@@ -43,6 +44,7 @@ module t (/*AUTOARG*/
//check(`__LINE__, $pow(-2.3,1.2),0); // Bad value
check(`__LINE__, $sqrt(1.2), 1.095445115010332148841598609578795731067657470703125);
//check(`__LINE__, $sqrt(-1.2), 0); // Bad value
check(`__LINE__, ((1.5)**(1.25)), 1.660023);
`ifndef VERILATOR
check(`__LINE__, $acos (0.2), 1.369438406); // Arg1 is -1..1
check(`__LINE__, $acosh(1.2), 0.622362503);
+3 -3
View File
@@ -14,14 +14,14 @@ package pkg1;
parameter PARAM1 = 8;
endpackage // pkg1
module t (/*AUTOARG*/
module t
import pkg1::*; // Test SV 2012 import format
(/*AUTOARG*/
// Inputs
clk
);
input clk;
import pkg1::*;
reg [PARAM1:0] bus1;
initial begin
+2 -2
View File
@@ -46,8 +46,8 @@ module m1;
initial if (PACKED_PARAM != 8'h36) $stop;
endmodule
module m2;
parameter PAR2 = 10;
// bug 810
module m2 #(/*parameter*/ integer PAR2 = 10);
initial begin
$display("%x",PAR2);
if (PAR2 !== 2) $stop;
+24
View File
@@ -0,0 +1,24 @@
// -*- 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, 2006 by Wilson Snyder.
#include <verilated.h>
#include "Vt_param_public.h"
#include "Vt_param_public_p.h"
int main (int argc, char *argv[]) {
Vt_param_public *topp = new Vt_param_public;
Verilated::debug(0);
// Make sure public tag worked
if (Vt_param_public_p::INPACK) {}
for (int i = 0; i < 10; i++) {
topp->eval();
}
}

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