Compare commits

...
36 Commits
Author SHA1 Message Date
Wilson Snyder 26eb7c9375 Remove version (mod) flag from releases 2009-10-26 20:26:28 -04:00
Wilson Snyder e4d5367ead Version bump 2009-10-26 20:19:23 -04:00
Wilson Snyder 47b5157f01 Support division and modulus of > 64 bit vectors. 2009-10-26 20:12:09 -04:00
Wilson Snyder 39444d83c5 Support little endian bit vectors ("reg [0:2] x;"). 2009-10-25 16:53:55 -04:00
Wilson Snyder 350028553b Fix install missing verilatedsc.h 2009-10-23 19:30:44 -04:00
Wilson Snyder 7392add8e0 Add new tests to support for future commit 2009-10-22 22:25:24 -04:00
Wilson Snyder e14695c96e Fix erroring on strings with backslashed newlines, bug168. 2009-10-22 21:46:49 -04:00
Wilson Snyder b4d3806f10 Fix carriage-returns embedded in display formats
Internals: Store all AstDisplay etc strings in un-backslashed raw format.
2009-10-22 21:29:18 -04:00
Wilson Snyder 996afe7d95 Cleanup handling DOS CRs to match preprocessor
Fix missing line number increment for `pragma
2009-10-22 16:51:34 -04:00
Wilson Snyder 905cadc00e License clarification 2009-10-22 15:46:47 -04:00
Wilson Snyder 6634751303 Verilator --version now uses git describe for tag-relative naming 2009-10-21 09:25:52 -04:00
Wilson Snyder 64b57fa907 Internals: Commentary and new select tests for future merge-in. No functional change. 2009-10-15 21:47:15 -04:00
Wilson Snyder dd4059beb8 Internals: Rework V3Param, V3Width and V3Const to return a AstNode* representing
any replacement edit they made to the passed in node.  Assure all callers use it
and/or comment on non-use.  Hopefully no function changed.
2009-10-14 20:13:04 -04:00
Wilson Snyder fe3b54bc2e Have V3Life unlink at end to prevent proposed new-iteration scheme from breaking. 2009-10-14 08:26:30 -04:00
Wilson Snyder 1b5e1943f5 Part of earlier commit; Fix execute permission 2009-10-12 20:53:21 -04:00
Wilson Snyder b1e6fe7139 Fix core dump with SystemVerilog var declarations under unnamed begins. 2009-10-11 20:50:31 -04:00
Wilson Snyder 92718a819c Fix cell port connection to unsized integer causing false width warning. 2009-10-09 22:55:37 -04:00
Wilson Snyder ceb2f6894f Fix writing to out-of-bounds arrays writing element 0. 2009-10-08 20:42:45 -04:00
Wilson Snyder c42612abac Internal: Reconnect complicated pins in V3Tristate before Unknowns. Prep for next change. 2009-10-07 07:54:30 -04:00
Wilson Snyder 7069d7d802 Internals: Remove AstAssignW::allowImplicit - dead code 2009-10-06 21:58:00 -04:00
Wilson Snyder 9aaa6d5df1 Move V3Unknown to after variable names have been begin'ed; in prep for future change 2009-10-06 21:46:24 -04:00
Wilson Snyder 3eb155cf2a V3Unknown: Don't modify tree if SEL out-of-bounds would be constant. Prep for next change. 2009-10-06 17:19:38 -04:00
Wilson Snyder 7c8d914711 V3Number::setZero can be public. No functional change. 2009-10-05 21:09:26 -04:00
Wilson Snyder 4d1f8bd057 Increase default --unroll-stmts 2009-10-05 07:49:02 -04:00
Wilson Snyder b883ce95b2 Add --gdbbt option 2009-10-04 18:04:37 -04:00
Wilson Snyder 546e7c0c1f Internals: iterateAndNext now requires backp to exist, for forward compatibility 2009-10-04 17:01:35 -04:00
Wilson Snyder 4f2dc0ecff Internals: Route abort() through vlabort(). No functional change 2009-10-04 17:01:28 -04:00
Wilson Snyder 03c5d06107 Visitors that just accept netlists should say so. No functional change 2009-10-01 22:33:11 -04:00
Wilson Snyder 9499047f8e Driver.pl support for iv 2009-10-01 22:32:40 -04:00
Wilson Snyder db5674cb08 Fix VCD files showing internal flattened hierarchy, broke in 3.714. 2009-09-26 09:31:50 -04:00
Wilson Snyder 66d000f4ba Repair new AstConst::Unsigned32 constructor 2009-09-26 06:43:06 -04:00
Wilson Snyder 2c3c990019 Move swap to V3Ast, and tell which AstUser*InUse fails assertions 2009-09-23 23:10:46 -04:00
Wilson Snyder 807aecdb11 Use parallel top level make 2009-09-23 23:10:09 -04:00
Wilson Snyder ea1b705c1c Move test_v submodule into t_case_orig. No functional change 2009-09-23 21:04:12 -04:00
Wilson Snyder cb8b0d3597 No need for V3Signed to recurse into generate if. 2009-09-22 18:58:59 -04:00
Wilson Snyder 7a86514505 Rename opRange->opSel to match AstRange. No functional change. 2009-09-20 09:30:39 -04:00
109 changed files with 3625 additions and 815 deletions
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+16
View File
@@ -3,6 +3,22 @@ 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.720 2009/10/26
** Support little endian bit vectors ("reg [0:2] x;").
** Support division and modulus of > 64 bit vectors. [Gary Thomas]
*** Fix writing to out-of-bounds arrays writing element 0.
**** Fix core dump with SystemVerilog var declarations under unnamed begins.
**** Fix VCD files showing internal flattened hierarchy, broke in 3.714.
**** Fix cell port connection to unsized integer causing false width warning.
**** Fix erroring on strings with backslashed newlines, bug168. [Pete Nixon]
* Verilator 3.714 2009/09/18
** Add --bbox-sys option to blackbox $system calls.
+10 -2
View File
@@ -104,7 +104,8 @@ DISTDEP = info Makefile
# Files to distribute.
DISTBIN = $(wildcard bin/verilator-*)
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING *.in *.ac \
DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
*.in *.ac \
Changes README TODO \
MANIFEST.SKIP \
bin/* \
@@ -134,6 +135,7 @@ INST_PROJ_FILES = \
include/verilated.[chv]* \
include/verilated.mk \
include/verilatedos.[chv]* \
include/verilatedsc.[chv]* \
INST_PROJ_BIN_FILES = \
verilator_bin \
@@ -143,6 +145,12 @@ DISTFILES := $(DISTFILES_INC)
VL_INST_MAN_FILES = verilator.1
ifeq ($(OBJCACHE_HOSTS),)
export OBJCACHE_JOBS :=
else
export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
endif
all: all_nomsg msg_test
all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
@@ -150,7 +158,7 @@ all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
verilator_exe verilator_bin verilator_bin_dbg:
@echo ------------------------------------------------------------
@echo "making verilator in src" ; \
(cd src && $(MAKE) )
(cd src && $(MAKE) $(OBJCACHE_JOBS) )
.PHONY:msg_test
msg_test:
+53 -31
View File
@@ -45,6 +45,7 @@ autoflush STDERR 1;
$Debug = 0;
my $opt_gdb;
my $opt_gdbbt;
# No arguments can't do anything useful. Give help
if ($#ARGV < 0) {
@@ -66,20 +67,29 @@ if (! GetOptions (
# "version!" => \&version, # Also passthru'ed
# Switches
"gdb=s" => \$opt_gdb, # Undocumented debugging
"gdbbt!" => \$opt_gdbbt, # Undocumented debugging
# Additional parameters
"<>" => sub {}, # Ignored
)) {
pod2usage(-exitstatus=>2, -verbose=>0);
}
# Determine runtime flags
my $vcmd =(($opt_gdb?"$opt_gdb ":"")
.verilator_bin()
." ".join(' ',@Opt_Verilator_Sw)
);
# Run verilator
run ($vcmd);
# Determine runtime flags and run
if ($opt_gdbbt && !$opt_gdb && $Debug) {
# Run under GDB to get gdbbt
run ("gdb ".verilator_bin()
." --batch --quiet"
." -ex 'run ".join(' ',@Opt_Verilator_Sw)."'"
." -ex 'set width 0'"
." -ex 'bt'"
." -ex 'c'");
die "%Error: --gdbbt looses the exit status; so must assume run went badly...";
} else {
# Normal, non gdb
run (($opt_gdb?"$opt_gdb ":"")
.verilator_bin()
." ".join(' ',@Opt_Verilator_Sw));
}
#----------------------------------------------------------------------
@@ -655,10 +665,10 @@ Disable the specified warning message.
=item -Wno-lint
Disable all lint related warning messages. This is equivelent to
Disable all lint related warning messages. This is equivalent to
"-Wno-CASEINCOMPLETE -Wno-CASEOVERLAP -Wno-CASEX -Wno-CASEWITHX
-Wno-CMPCONST -Wno-IMPLICIT -Wno-UNDRIVEN -Wno-UNSIGNED -Wno-UNUSED
-Wno-VARHIDDEN -Wno-WIDTH".
-Wno-CMPCONST -Wno-IMPLICIT -Wno-LITENDIAN -Wno-UNDRIVEN -Wno-UNSIGNED
-Wno-UNUSED -Wno-VARHIDDEN -Wno-WIDTH".
It is strongly recommended you cleanup your code rather than using this
option, it is only intended to be use when running test-cases of code
@@ -1637,12 +1647,6 @@ Bit ranges must be numbered with the MSB being numbered greater or the same
as the LSB. Little-bit-endian busses [0:15] are not supported as they
aren't easily made compatible with C++.
=head2 32-Bit Divide
The division and modulus operators are limited to 32 bits. This can be
easily fixed if someone contributes the appropriate wide-integer math
functions.
=head2 Gate Primitives
The 2-state gate primitives (and, buf, nand, nor, not, or, xnor, xor) are
@@ -1878,7 +1882,7 @@ correctly.
Warns that a case statement contains a constant with a C<x>. Verilator is
two-state so interpret such items as always false. Note a common error is
to use a C<X> in a case or casez statement item; often what the user
instead insteaded is to use a casez with C<?>.
instead intended is to use a casez with C<?>.
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
@@ -1944,6 +1948,16 @@ Verilator cannot schedule these variables correctly.
Ignoring this warning may make Verilator simulations differ from other
simulators.
=item LITENDIAN
Warns that a vector is declared with little endian bit numbering
(i.e. [0:7]). Big endian bit numbering is now the overwhelming standard,
and little numbering is now thus often due to simple oversight instead of
intent.
Ignoring this warning will only suppress the lint check, it will simulate
correctly.
=item MULTIDRIVEN
Warns that the specified signal comes from multiple always blocks. This is
@@ -2148,7 +2162,7 @@ correctly.
=item WIDTHCONCAT
Warns that based on width rules of Verilog, a concatenate or replication
has a undeterminate width. In most cases this violates the Verilog rule
has a indeterminate width. In most cases this violates the Verilog rule
that widths inside concatenates and replicates must be sized, and should be
fixed in the code.
@@ -2216,10 +2230,10 @@ Visual C++ Version 7 or newer, but this is not tested by the author.
=item Can you provide binaries?
Verilator is available as a RPM for SuSE, Redhat and perhaps other systems;
this is done by porters and may slightly lag the primary distribution. If
there isn't a binary build for your distribution, how about you set one up?
Please contact the authors for assistance.
Verilator is available as a RPM for SuSE, Fedora, and perhaps other
systems; this is done by porters and may slightly lag the primary
distribution. If there isn't a binary build for your distribution, how
about you set one up? Please contact the authors for assistance.
Note people sometimes request binaries when they are having problems with
their C++ compiler. Alas, binaries won't help this, as in the end a fully
@@ -2239,18 +2253,24 @@ 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 May programs I create with Verilator remain under my own copyright?
=item Will Verilator output remain under my own copyright?
Yes, it's just like using GCC on your programs; this is why Verilator uses
the "GNU *Lesser* Public License" instead of the more typical "GNU Public
License". If you change Verilator itself or the header files Verilator
includes, you must make the source code available under the GNU Lesser
Public License. However, Verilator output (the Verilated code) only
includes the licensed files, and so you are NOT required to release any
output from Verilator.
the "GNU *Lesser* Public License Version 3" instead of the more typical
"GNU Public License". See the licenses for details, but in brief, if you
change Verilator itself or the header files Verilator includes, you must
make the source code available under the GNU Lesser Public License.
However, Verilator output (the Verilated code) only "include"s the licensed
files, and so you are NOT required to release any output from Verilator.
You also have the option of using the Perl Artistic License, which again
does not require you release your Verilog or generated code.
does not require you release your Verilog or generated code, and also
allows you to modify Verilator for internal use without distributing the
modified version. But please contribute back to the community!
One limit is that you cannot under either license release a commercial
simulation product incorporating Verilator without making the source code
available.
=item Why is running Verilator so slow?
@@ -2638,6 +2658,8 @@ License Version 2.0.
=head1 AUTHORS
When possible, please instead report bugs to L<http://www.veripool.org/>.
Wilson Snyder <[email protected]>
Major concepts by Paul Wasson and Duane Galbi.
+111
View File
@@ -136,6 +136,117 @@ WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
return outwp;
}
//===========================================================================
// Slow math
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus) {
// See Knuth Algorithm D. Computes u/v = q.r
// This isn't massively tuned, as wide division is rare
// for debug see V3Number version
// Requires clean input
int words = VL_WORDS_I(lbits);
for (int i=0; i<words; i++) owp[i]=0;
// Find MSB and check for zero.
int umsbp1 = VL_MOSTSETBITP1_W(words,lwp); // dividend
int vmsbp1 = VL_MOSTSETBITP1_W(words,rwp); // divisor
if (VL_UNLIKELY(vmsbp1==0) // rwp==0 so division by zero. Return 0.
|| VL_UNLIKELY(umsbp1==0)) { // 0/x so short circuit and return 0
return owp;
}
int uw = VL_WORDS_I(umsbp1); // aka "m" in the algorithm
int vw = VL_WORDS_I(vmsbp1); // aka "n" in the algorithm
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw-1; j >= 0; j--) {
vluint64_t unw64 = ((k<<VL_ULL(32)) + (vluint64_t)(lwp[j]));
owp[j] = unw64 / (vluint64_t)(rwp[0]);
k = unw64 - (vluint64_t)(owp[j])*(vluint64_t)(rwp[0]);
}
if (is_modulus) {
owp[0] = k;
for (int i=1; i<words; i++) owp[i]=0;
}
return owp;
}
// +1 word as we may shift during normalization
uint32_t un[VL_MULS_MAX_WORDS+1]; // Fixed size, as MSVC++ doesn't allow [words] here
uint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
// Zero for ease of debugging and to save having to zero for shifts
for (int i=0; i<words; i++) { un[i]=vn[i]=0; }
// Algorithm requires divisor MSB to be set
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
int s = 31-VL_BITBIT_I(vmsbp1-1); // shift amount (0...31)
uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
for (int i = vw-1; i>0; i--) {
vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s)));
}
vn[0] = rwp[0] << s;
// Copy and shift dividend by same amount; may set new upper word
if (s) un[uw] = lwp[uw-1] >> (32-s);
else un[uw] = 0;
for (int i=uw-1; i>0; i--) {
un[i] = (lwp[i] << s) | (shift_mask & (lwp[i-1] >> (32-s)));
}
un[0] = lwp[0] << s;
// Main loop
for (int j = uw - vw; j >= 0; j--) {
// Estimate
vluint64_t unw64 = ((vluint64_t)(un[j+vw])<<VL_ULL(32) | (vluint64_t)(un[j+vw-1]));
vluint64_t qhat = unw64 / (vluint64_t)(vn[vw-1]);
vluint64_t rhat = unw64 - qhat*(vluint64_t)(vn[vw-1]);
again:
if (qhat >= VL_ULL(0x100000000)
|| ((qhat*vn[vw-2]) > ((rhat<<VL_ULL(32)) + un[j+vw-2]))) {
qhat = qhat - 1;
rhat = rhat + vn[vw-1];
if (rhat < VL_ULL(0x100000000)) goto again;
}
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i=0; i<vw; i++) {
vluint64_t p = qhat*vn[i]; // Multiply by estimate
t = un[i+j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract
un[i+j] = t;
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32));
}
t = un[j+vw] - k;
un[j+vw] = t;
owp[j] = qhat; // Save quotient digit
if (t < 0) {
// Over subtracted; correct by adding back
owp[j]--;
k = 0;
for (int i=0; i<vw; i++) {
t = (vluint64_t)(un[i+j]) + (vluint64_t)(vn[i]) + k;
un[i+j] = t;
k = t >> VL_ULL(32);
}
un[j+vw] = un[j+vw] + k;
}
}
if (is_modulus) { // modulus
// Need to reverse normalization on copy to output
for (int i=0; i<vw; i++) {
owp[i] = (un[i] >> s) | (shift_mask & (un[i+1] << (32-s)));
}
for (int i=vw; i<words; i++) owp[i] = 0;
return owp;
} else { // division
return owp;
}
}
//===========================================================================
// Formatting
+74 -9
View File
@@ -192,6 +192,9 @@ extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal
/// Math
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
/// File I/O
extern IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq);
@@ -228,6 +231,7 @@ extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
#define VL_SET_WQ(owp,data) { owp[0]=(data); owp[1]=((data)>>VL_WORDSIZE); }
#define VL_SET_WI(owp,data) { owp[0]=(data); owp[1]=0; }
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
// Use a union to avoid cast-to-different-size warnings
/// Return FILE* from QData
@@ -302,6 +306,11 @@ extern double sc_time_stamp();
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
#define VL_ASSIGNCLEAN_W(obits,owp,lwp) VL_CLEAN_WW(obits,obits,owp,lwp)
static inline WDataOutP _VL_CLEAN_INPLACE_W(int obits, WDataOutP owp) {
int words = VL_WORDS_I(obits);
owp[words-1] &= VL_MASK_I(obits);
return(owp);
}
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP lwp){
int words = VL_WORDS_I(obits);
for (int i=0; (i < (words-1)); i++) owp[i] = lwp[i];
@@ -609,7 +618,7 @@ static inline IData VL_CLOG2_Q(QData lhs) {
static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
IData adjust = (VL_COUNTONES_W(words,lwp)==1) ? 0 : 1;
for (int i=words-1; i>=0; i--) {
if (lwp[i]) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + adjust;
@@ -621,6 +630,21 @@ static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
return 0;
}
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) {
// MSB set bit plus one; similar to FLS. 0=value is zero
for (int i=words-1; i>=0; i--) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + 1;
}
}
// Can't get here - one bit must be set
}
}
return 0;
}
//===================================================================
// SIMPLE LOGICAL OPERATORS
@@ -759,10 +783,12 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) {
// EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean;
#define VL_DIV_I(lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_Q(lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_MODDIV_I(lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_Q(lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_DIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,0))
#define VL_MODDIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,1))
static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
QData carry = 0;
@@ -866,31 +892,70 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
return(owp);
}
static inline IData VL_DIVS_III(int,int lbits,int, IData lhs,IData rhs) {
static inline IData VL_DIVS_III(int lbits, IData lhs,IData rhs) {
if (rhs==0) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline QData VL_DIVS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
static inline QData VL_DIVS_QQQ(int lbits, QData lhs,QData rhs) {
if (rhs==0) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline IData VL_MODDIVS_III(int,int lbits,int, IData lhs,IData rhs) {
static inline IData VL_MODDIVS_III(int lbits, IData lhs,IData rhs) {
if (rhs==0) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline QData VL_MODDIVS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs,QData rhs) {
if (rhs==0) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataInP rwp) {
int words = VL_WORDS_I(lbits);
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if ((lsign && !rsign) || (!lsign && rsign)) {
IData qNoSign[VL_MULS_MAX_WORDS];
VL_DIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp;
} else {
return VL_DIV_WWW(lbits,owp,ltup,rtup);
}
}
static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataInP rwp) {
int words = VL_WORDS_I(lbits);
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if (lsign) { // Only dividend sign matters for modulus
IData qNoSign[VL_MULS_MAX_WORDS];
VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp;
} else {
return VL_MODDIV_WWW(lbits,owp,ltup,rtup);
}
}
static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
if (lhs==0) return 0;
IData power = lhs;
+3 -3
View File
@@ -29,9 +29,9 @@ This is the Verilator Package.
This package is Copyright 2003-2009 by Wilson Snyder @email{wsnyder@@wsnyder.org}.
Verilator is free software; you can redistribute it and/or modify it
under the terms of either the GNU General Public License Version 3 or
the Perl Artistic License Version 2.0. (See the documentation for
more details.)
under the terms of either the GNU Lesser General Public License
Version 3 or the Perl Artistic License Version 2.0. (See the
documentation for more details.)
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
+1
View File
@@ -204,6 +204,7 @@ RAW_OBJS = \
V3Unknown.o \
V3Unroll.o \
V3Width.o \
V3WidthSel.o \
# Non-concatable
OBJS += \
+2 -2
View File
@@ -84,7 +84,7 @@ private:
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
// Simplify sensitivity list
V3Const::constifyTreeExpensive(nodep);
V3Const::constifyExpensiveEdit(nodep); nodep=NULL;
}
// Empty visitors, speed things up
virtual void visit(AstNodeStmt* nodep, AstNUser*) { }
@@ -364,7 +364,7 @@ private:
}
public:
// CONSTUCTORS
ActiveVisitor(AstNode* nodep) {
ActiveVisitor(AstNetlist* nodep) {
m_scopeFinalp = NULL;
m_alwaysp = NULL;
m_itemCombo = false;
+1 -1
View File
@@ -80,9 +80,9 @@ private:
}
virtual void visit(AstActive* nodep, AstNUser*) {
UINFO(4," ACTIVE "<<nodep<<endl);
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
AstSenTree* sensesp = nodep->sensesp();
if (!sensesp) nodep->v3fatalSrc("NULL");
V3Const::constifyTreeExpensive(nodep); // Remove duplicate clocks and such
if (sensesp->sensesp()
&& sensesp->sensesp()->castSenItem()
&& sensesp->sensesp()->castSenItem()->isNever()) {
+101 -3
View File
@@ -33,8 +33,8 @@
//======================================================================
// Statics
vluint64_t AstNode::s_editCntGbl=0;
vluint64_t AstNode::s_editCntLast=0;
vluint64_t AstNode::s_editCntGbl=0; // Hot cache line
// To allow for fast clearing of all user pointers, we keep a "timestamp"
// along with each userp, and thus by bumping this count we can make it look
@@ -139,6 +139,21 @@ string AstNode::dedotName(const string& namein) {
return pretty;
}
string AstNode::vcdName(const string& namein) {
// VCD tracing expects space to separate hiearchy
// Dots are reserved for dots the user put in the name
string pretty = namein;
string::size_type pos;
while ((pos=pretty.find("__DOT__")) != string::npos) {
pretty.replace(pos, 7, " ");
}
while ((pos=pretty.find(".")) != string::npos) {
pretty.replace(pos, 1, " ");
}
// Now convert escaped special characters, etc
return prettyName(pretty);
}
string AstNode::prettyName(const string& namein) {
string pretty;
pretty = "";
@@ -181,6 +196,31 @@ string AstNode::prettyTypeName() const {
return string(typeName())+" '"+prettyName()+"'";
}
string AstNode::quoteName(const string& namein) {
// Encode control chars into C style escapes
// Reverse is V3Parse::deQuote
const char* start = namein.c_str();
string out;
for (const char* pos = start; *pos; pos++) {
if (pos[0]=='\\' || pos[0]=='"') {
out += string("\\")+pos[0];
} else if (pos[0]=='\n') {
out += "\\n";
} else if (pos[0]=='\r') {
out += "\\r";
} else if (pos[0]=='\t') {
out += "\\t";
} else if (isprint(pos[0])) {
out += pos[0];
} else {
// This will also cover \a etc
char octal[10]; sprintf(octal,"\\%03o",pos[0]);
out += octal;
}
}
return out;
}
int AstNode::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();
@@ -559,6 +599,23 @@ void AstNode::relinkOneLink(AstNode*& pointpr, // Ref to pointer that gets set
pointpr = newp;
}
void AstNode::addHereThisAsNext (AstNode* newp) {
// {old}->this->{next} becomes {old}->new->this->{next}
AstNRelinker handle;
this->unlinkFrBackWithNext(&handle);
newp->addNext(this);
handle.relink(newp);
}
void AstNode::swapWith (AstNode* bp) {
AstNRelinker aHandle;
AstNRelinker bHandle;
this->unlinkFrBack(&aHandle);
bp->unlinkFrBack(&bHandle);
aHandle.relink(bp);
bHandle.relink(this);
}
//======================================================================
// Clone
@@ -696,7 +753,11 @@ void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
// IMPORTANT: If you replace a node that's the target of this iterator,
// then the NEW node will be iterated on next, it isn't skipped!
// if (!this) return; // Part of for()
for (AstNode* nodep=this; nodep;) {
// Future versions of this function may require the node to have a back to be iterated;
// there's no lower level reason yet though the back must exist.
AstNode* nodep=this;
if (VL_UNLIKELY(nodep && !nodep->m_backp)) nodep->v3fatalSrc("iterateAndNext node has no back");
while (nodep) {
AstNode* niterp = nodep;
ASTNODE_PREFETCH(nodep->m_nextp);
niterp->m_iterpp = &niterp;
@@ -704,7 +765,7 @@ void AstNode::iterateAndNext(AstNVisitor& v, AstNUser* vup) {
// accept may do a replaceNode and change niterp on us...
if (!niterp) return;
niterp->m_iterpp = NULL;
if (niterp!=nodep) { // Edited it
if (VL_UNLIKELY(niterp!=nodep)) { // Edited it
nodep = niterp;
} else { // Same node, just loop
nodep = niterp->m_nextp;
@@ -742,6 +803,42 @@ void AstNode::iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup) {
}
}
AstNode* AstNode::acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup) {
// Some visitors perform tree edits (such as V3Const), and may even
// replace/delete the exact nodep that the visitor is called with. If
// this happens, the parent will loose the handle to the node that was
// processed.
// To solve this, this function returns the pointer to the replacement node,
// which in many cases is just the same node that was passed in.
AstNode* nodep = this; // Note "this" may point to bogus point later in this function
if (nodep->castNetlist()) {
// Calling on top level; we know the netlist won't get replaced
nodep->accept(v, vup);
} else if (!nodep->backp()) {
// Calling on standalone tree; insert a shim node so we can keep track, then delete it on completion
AstBegin* tempp = new AstBegin(nodep->fileline(),"[EditWrapper]",nodep);
{
tempp->stmtsp()->accept(v, vup); nodep=NULL; // nodep to null as may be replaced
}
nodep = tempp->stmtsp()->unlinkFrBackWithNext();
tempp->deleteTree(); tempp=NULL;
} else {
// Use back to determine who's pointing at us (IE assume new node grafts into same place as old one)
AstNode** nextnodepp = NULL;
if (this->m_backp->m_op1p == this) nextnodepp = &(this->m_backp->m_op1p);
else if (this->m_backp->m_op2p == this) nextnodepp = &(this->m_backp->m_op2p);
else if (this->m_backp->m_op3p == this) nextnodepp = &(this->m_backp->m_op3p);
else if (this->m_backp->m_op4p == this) nextnodepp = &(this->m_backp->m_op4p);
else if (this->m_backp->m_nextp == this) nextnodepp = &(this->m_backp->m_nextp);
if (!nextnodepp) this->v3fatalSrc("Node's back doesn't point to forward to node itself");
{
nodep->accept(v, vup); nodep=NULL; // nodep to null as may be replaced
}
nodep = *nextnodepp; // Grab new node from point where old was connected
}
return nodep;
}
//======================================================================
void AstNode::cloneRelinkTree() {
@@ -922,6 +1019,7 @@ void AstNode::v3errorEnd(ostringstream& str) const {
}
//######################################################################
// AstNVisitor
void AstNVisitor::doDeletes() {
for (vector<AstNode*>::iterator it = m_deleteps.begin(); it != m_deleteps.end(); ++it) {
+39 -25
View File
@@ -170,9 +170,8 @@ class AstAttrType {
public:
enum en {
BITS, // V3Const converts to constant
RANGE_LSB, // V3Const converts to constant
ARRAY_LSB, // V3Const converts to constant
//
VAR_BASE, // V3LinkResolve creates for AstPreSel, V3LinkParam removes
VAR_CLOCK, // V3LinkParse moves to AstVar::attrScClocked
VAR_CLOCK_ENABLE, // V3LinkParse moves to AstVar::attrClockEn
VAR_PUBLIC, // V3LinkParse moves to AstVar::sigPublic
@@ -182,7 +181,7 @@ public:
enum en m_e;
const char* ascii() const {
static const char* names[] = {
"BITS", "RANGE_LSB", "ARRAY_LSB",
"BITS", "VAR_BASE",
"VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC", "VAR_PUBLIC_FLAT",
"VAR_ISOLATE_ASSIGNMENTS"
};
@@ -390,19 +389,19 @@ struct AstNUser {
class AstUserInUseBase {
protected:
static void allocate(uint32_t& cntGblRef, bool& userBusyRef) {
static void allocate(int id, uint32_t& cntGblRef, bool& userBusyRef) {
// Perhaps there's still a AstUserInUse in scope for this?
UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser*InUse request when under another AstUserInUse");
UASSERT_STATIC(!userBusyRef, "Conflicting user use; AstUser"+cvtToStr(id)+"InUse request when under another AstUserInUse");
userBusyRef = true;
clearcnt(cntGblRef, userBusyRef);
clearcnt(id, cntGblRef, userBusyRef);
}
static void free(uint32_t& cntGblRef, bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Free of User*() not under AstUserInUse");
clearcnt(cntGblRef, userBusyRef); // Includes a checkUse for us
static void free(int id, uint32_t& cntGblRef, bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Free of User"+cvtToStr(id)+"() not under AstUserInUse");
clearcnt(id, cntGblRef, userBusyRef); // Includes a checkUse for us
userBusyRef = false;
}
static void clearcnt(uint32_t& cntGblRef, bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Clear of User*() not under AstUserInUse");
static void clearcnt(int id, uint32_t& cntGblRef, bool& userBusyRef) {
UASSERT_STATIC(userBusyRef, "Clear of User"+cvtToStr(id)+"() not under AstUserInUse");
// If this really fires and is real (after 2^32 edits???)
// we could just walk the tree and clear manually
++cntGblRef;
@@ -419,9 +418,9 @@ protected:
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
AstUser1InUse() { allocate(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser1InUse() { free (s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
AstUser1InUse() { allocate(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser1InUse() { free (1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(1, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser2InUse : AstUserInUseBase {
protected:
@@ -429,9 +428,9 @@ protected:
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
AstUser2InUse() { allocate(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser2InUse() { free (s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
AstUser2InUse() { allocate(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser2InUse() { free (2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(2, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser3InUse : AstUserInUseBase {
protected:
@@ -439,9 +438,9 @@ protected:
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
AstUser3InUse() { allocate(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser3InUse() { free (s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
AstUser3InUse() { allocate(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser3InUse() { free (3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(3, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
class AstUser4InUse : AstUserInUseBase {
protected:
@@ -449,9 +448,9 @@ protected:
static uint32_t s_userCntGbl; // Count of which usage of userp() this is
static bool s_userBusy; // Count is in use
public:
AstUser4InUse() { allocate(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser4InUse() { free (s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
AstUser4InUse() { allocate(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
~AstUser4InUse() { free (4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
static void clear() { clearcnt(4, s_userCntGbl/*ref*/, s_userBusy/*ref*/); }
};
//######################################################################
@@ -574,7 +573,9 @@ class AstNode {
static int s_cloneCntGbl; // Count of which userp is set
// Attributes
bool m_signed; // Node is signed
bool m_signed:1; // Node is signed
// // Space for more bools here
int m_width; // Bit width of operation
int m_widthMin; // If unsized, bitwidth of minimum implementation
// This member ordering both allows 64 bit alignment and puts associated data together
@@ -673,9 +674,11 @@ public:
virtual string verilogKwd() const { return ""; }
string shortName() const; // Name with __PVT__ removed for concatenating scopes
static string dedotName(const string& namein); // Name with dots removed
static string quoteName(const string& namein); // Name with control chars quoted
static string prettyName(const string& namein); // Name for printing out to the user
static string encodeName(const string& namein); // Encode user name into internal C representation
static string encodeNumber(vlsint64_t numin); // Encode number into internal C representation
static string vcdName(const string& namein); // Name for printing out to vcd files
string prettyName() const { return prettyName(name()); }
string prettyTypeName() const; // "VARREF name" for error messages
FileLine* fileline() const { return m_fileline; }
@@ -730,7 +733,7 @@ public:
static void user4ClearTree() { AstUser4InUse::clear(); }
vluint64_t editCount() const { return m_editCount; }
void editCountInc() { m_editCount = ++s_editCntGbl; }
void editCountInc() { m_editCount = ++s_editCntGbl; } // Preincrement, so can "watch AstNode::s_editCntGbl=##"
static vluint64_t editCountLast() { return s_editCntLast; }
static vluint64_t editCountGbl() { return s_editCntGbl; }
static void editCountSetLast() { s_editCntLast = editCountGbl(); }
@@ -747,13 +750,18 @@ public:
AstNode* addNext(AstNode* newp); // Returns this, adds to end of list
AstNode* addNextNull(AstNode* newp); // Returns this, adds to end of list, NULL is OK
void addNextHere(AstNode* newp); // Adds after speced node
void addHereThisAsNext(AstNode* newp); // Adds at old place of this, this becomes next
void replaceWith(AstNode* newp); // Replace current node in tree with new node
void v3errorEnd(ostringstream& str) const;
virtual void dump(ostream& str=cout);
AstNode* unlinkFrBack(AstNRelinker* linkerp=NULL); // Unlink this from whoever points to it.
AstNode* unlinkFrBackWithNext(AstNRelinker* linkerp=NULL); // Unlink this from whoever points to it, keep entire next list with unlinked node
void swapWith(AstNode* bp);
void relink(AstNRelinker* linkerp); // Generally use linker->relink() instead
void cloneRelinkNode() { cloneRelink(); }
// Iterate and insert - assumes tree format
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // When calling, "this" is second argument
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // When calling, "this" is second argument
// METHODS - Iterate on a tree
AstNode* cloneTree(bool cloneNextLink);
@@ -785,6 +793,7 @@ public:
void iterateAndNextIgnoreEdit(AstNVisitor& v, AstNUser* vup=NULL);
void iterateChildren(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
void iterateChildrenBackwards(AstNVisitor& v, AstNUser* vup=NULL); // Excludes following this->next
AstNode* acceptSubtreeReturnEdits(AstNVisitor& v, AstNUser* vup=NULL); // Return edited nodep; see comments in V3Ast.cpp
// CONVERSION
AstNode* castNode() { return this; }
@@ -932,11 +941,14 @@ struct AstNodePreSel : public AstNode {
setOp1p(lhs); setOp2p(rhs); setNOp3p(ths); }
ASTNODE_BASE_FUNCS(NodePreSel)
AstNode* lhsp() const { return op1p()->castNode(); }
AstNode* fromp() const { return lhsp(); }
AstNode* rhsp() const { return op2p()->castNode(); }
AstNode* thsp() const { return op3p()->castNode(); }
AstAttrOf* attrp() const { return op4p()->castAttrOf(); }
void lhsp(AstNode* nodep) { return setOp1p(nodep); }
void rhsp(AstNode* nodep) { return setOp2p(nodep); }
void thsp(AstNode* nodep) { return setOp3p(nodep); }
void attrp(AstAttrOf* nodep) { return setOp4p((AstNode*)nodep); }
// METHODS
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode*) const { return true; }
@@ -948,6 +960,8 @@ struct AstNodeStmt : public AstNode {
: AstNode(fl) {}
ASTNODE_BASE_FUNCS(NodeStmt)
// METHODS
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
};
struct AstNodeAssign : public AstNodeStmt {
+110 -1
View File
@@ -141,6 +141,14 @@ AstRange* AstVar::arrayp(int dimension) const {
return NULL;
}
int AstVar::arrayDimensions() const {
int entries=0;
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
entries++;
}
return entries;
}
uint32_t AstVar::arrayElements() const {
uint32_t entries=1;
for (AstRange* arrayp=this->arraysp(); arrayp; arrayp = arrayp->nextp()->castRange()) {
@@ -149,6 +157,37 @@ uint32_t AstVar::arrayElements() const {
return entries;
}
// Special operators
int AstArraySel::dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
// Only called after V3Param; so only ArraySel's need to be recursed
int dim = 0;
while (nodep) {
if (nodep->castNodeSel()) { dim++; nodep=nodep->castNodeSel()->fromp(); continue; }
if (nodep->castNodePreSel()) { dim++; nodep=nodep->castNodePreSel()->fromp(); continue; }
break;
}
return dim;
}
AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
// Else AstArraySel etc; search for the base
while (nodep) {
if (nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); continue; }
else if (nodep->castSel()) { nodep=nodep->castSel()->fromp(); continue; }
// AstNodeSelPre stashes the associated variable under a ATTROF so it isn't constified
else if (nodep->castAttrOf()) { nodep=nodep->castAttrOf()->fromp(); continue; }
else if (nodep->castNodePreSel()) {
if (nodep->castNodePreSel()->attrp()) {
nodep=nodep->castNodePreSel()->attrp();
} else {
nodep=nodep->castNodePreSel()->lhsp();
}
continue;
}
else break;
}
return nodep;
}
bool AstScope::broken() const {
return ((m_aboveScopep && !m_aboveScopep->brokeExists())
|| (m_aboveCellp && !m_aboveCellp->brokeExists())
@@ -199,6 +238,68 @@ bool AstSenTree::hasCombo() {
return false;
}
//======================================================================
// Special walking tree inserters
void AstNode::addBeforeStmt(AstNode* newp, AstNode*) {
if (!backp()) newp->v3fatalSrc("Can't find current statement to addBeforeStmt");
// Look up; virtual call will find where to put it
this->backp()->addBeforeStmt(newp, this);
}
void AstNode::addNextStmt(AstNode* newp, AstNode*) {
if (!backp()) newp->v3fatalSrc("Can't find current statement to addBeforeStmt");
// Look up; virtual call will find where to put it
this->backp()->addNextStmt(newp, this);
}
void AstNodeStmt::addBeforeStmt(AstNode* newp, AstNode*) {
// Insert newp before current node
this->addHereThisAsNext(newp);
}
void AstNodeStmt::addNextStmt(AstNode* newp, AstNode*) {
// Insert newp after current node
this->addNextHere(newp);
}
void AstWhile::addBeforeStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule for other statement types)
if (belowp == precondsp()) {
// Must have been first statement in precondsp list, so newp is new first statement
belowp->addHereThisAsNext(newp);
} else if (belowp == condp()) {
// Goes before condition, IE in preconditions
addPrecondsp(newp);
} else if (belowp == bodysp()) {
// Was first statement in body, so new front
belowp->addHereThisAsNext(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
void AstWhile::addNextStmt(AstNode* newp, AstNode* belowp) {
// Special, as statements need to be put in different places
// Belowp is how we came to recurse up to this point
// Preconditions insert first just before themselves (the normal rule for other statement types)
if (belowp == precondsp()) {
// Next in precond list
belowp->addNextHere(newp);
} else if (belowp == condp()) {
// Becomes first statement in body, body may have been empty
if (bodysp()) {
bodysp()->addHereThisAsNext(newp);
} else {
addBodysp(newp);
}
} else if (belowp == bodysp()) {
// Next statement in body
belowp->addNextHere(newp);
} else {
belowp->v3fatalSrc("Doesn't look like this was really under the while");
}
}
//======================================================================
// Per-type Debugging
@@ -211,7 +312,7 @@ void AstNode::dump(ostream& os) {
<<" "<<(isSigned()?"s":"")
<<"w"<<(widthSized()?"":"u")<<width();
if (!widthSized()) os<<"/"<<widthMin();
if (name()!="") os<<" "<<name();
if (name()!="") os<<" "<<AstNode::quoteName(name());
}
void AstAttrOf::dump(ostream& str) {
@@ -241,6 +342,10 @@ void AstPin::dump(ostream& str) {
else { str<<" ->UNLINKED"; }
if (svImplicit()) str<<" [.SV]";
}
void AstRange::dump(ostream& str) {
this->AstNode::dump(str);
if (littleEndian()) str<<" [LITTLE]";
}
void AstVarXRef::dump(ostream& str) {
this->AstNode::dump(str);
if (lvalue()) str<<" [LV] => ";
@@ -318,6 +423,10 @@ void AstNodeFTask::dump(ostream& str) {
this->AstNode::dump(str);
if (taskPublic()) str<<" [PUBLIC]";
}
void AstBegin::dump(ostream& str) {
this->AstNode::dump(str);
if (unnamed()) str<<" [UNNAMED]";
}
void AstCoverDecl::dump(ostream& str) {
this->AstNode::dump(str);
if (this->dataDeclNullp()) {
+56 -32
View File
@@ -46,6 +46,7 @@ struct AstConst : public AstNodeMath {
private:
V3Number m_num; // Constant value
public:
class Unsized32 {}; // for creator type-overload selection
AstConst(FileLine* fl, const V3Number& num)
:AstNodeMath(fl)
,m_num(num) {
@@ -55,6 +56,9 @@ public:
AstConst(FileLine* fl, uint32_t num)
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { width(m_num.width(), m_num.sized()?0:m_num.minWidth()); }
AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { m_num.width(32,false); width(32,m_num.minWidth()); }
ASTNODE_NODE_FUNCS(Const, CONST)
virtual string name() const { return num().ascii(); } // * = Value
virtual const V3Number& num() const { return m_num; } // * = Value
@@ -72,20 +76,30 @@ public:
struct AstRange : public AstNode {
// Range specification, for use under variables and cells
private:
bool m_littleEndian:1; // Bit vector is little endian
public:
AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp)
:AstNode(fl) {
m_littleEndian = false;
setOp2p(msbp); setOp3p(lsbp); }
AstRange(FileLine* fl, int msb, int lsb)
:AstNode(fl) {
m_littleEndian = false;
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
width(msb-lsb+1,msb-lsb+1);
}
ASTNODE_NODE_FUNCS(Range, RANGE)
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
AstNode* msbEndianedp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration
AstNode* lsbEndianedp() const { return littleEndian()?msbp():lsbp(); }
int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); }
int elementsConst() const { return msbConst()-lsbConst()+1; }
int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; }
bool littleEndian() const { return m_littleEndian; }
void littleEndian(bool flag) { m_littleEndian=flag; }
virtual void dump(ostream& str);
virtual string emitC() { V3ERROR_NA; return ""; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
@@ -116,15 +130,8 @@ struct AstArraySel : public AstNodeSel {
virtual bool same(AstNode* samep) const { return true; }
virtual int instrCount() const { return widthInstrs(); }
// Special operators
static int dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
int dim = 0;
while (nodep && nodep->castArraySel()) { dim++; nodep=nodep->castArraySel()->fromp(); }
return dim;
}
static AstNode* baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
while (nodep && nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); }
return nodep;
}
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
};
struct AstWordSel : public AstNodeSel {
@@ -149,6 +156,8 @@ struct AstSelExtract : public AstNodePreSel {
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
: AstNodePreSel(fl, fromp, msbp, lsbp) {}
ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT)
AstNode* msbp() const { return rhsp(); }
AstNode* lsbp() const { return thsp(); }
};
struct AstSelBit : public AstNodePreSel {
@@ -159,6 +168,7 @@ struct AstSelBit : public AstNodePreSel {
width(1,1);
}
ASTNODE_NODE_FUNCS(SelBit, SELBIT)
AstNode* bitp() const { return rhsp(); }
};
struct AstSelPlus : public AstNodePreSel {
@@ -167,6 +177,8 @@ struct AstSelPlus : public AstNodePreSel {
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
:AstNodePreSel(fl, fromp, bitp, widthp) {}
ASTNODE_NODE_FUNCS(SelPlus, SELPLUS)
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
struct AstSelMinus : public AstNodePreSel {
@@ -175,6 +187,8 @@ struct AstSelMinus : public AstNodePreSel {
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
:AstNodePreSel(fl, fromp, bitp, widthp) {}
ASTNODE_NODE_FUNCS(SelMinus, SELMINUS)
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
struct AstSel : public AstNodeTriop {
@@ -192,7 +206,7 @@ struct AstSel : public AstNodeTriop {
}
ASTNODE_NODE_FUNCS(Sel, SEL)
virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) {
out.opRange(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); }
out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); }
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
virtual string emitC() {
return this->widthp()->isOne()
@@ -354,7 +368,11 @@ public:
int widthTotalBytes() const; // Width in bytes rounding up 1,2,4,8,12,...
int msb() const { if (!rangep()) return 0; return rangep()->msbConst(); }
int lsb() const { if (!rangep()) return 0; return rangep()->lsbConst(); }
int msbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->lsbConst():rangep()->msbConst(); }
int lsbEndianed() const { if (!rangep()) return 0; return littleEndian()?rangep()->msbConst():rangep()->lsbConst(); }
int msbMaxSelect() const { return (lsb()<0 ? msb()-lsb() : msb()); } // Maximum value a [] select may index
bool littleEndian() const { return (rangep() && rangep()->littleEndian()); }
int arrayDimensions() const;
uint32_t arrayElements() const; // 1, or total multiplication of all dimensions
virtual string verilogKwd() const;
void propagateAttrFrom(AstVar* fromp) {
@@ -698,19 +716,23 @@ struct AstBegin : public AstNode {
// Children: statements
private:
string m_name; // Name of block
bool m_unnamed; // Originally unnamed
public:
// Node that simply puts name into the output stream
AstBegin(FileLine* fileline, const string& name, AstNode* stmtsp)
: AstNode(fileline)
, m_name(name) {
addNOp1p(stmtsp);
m_unnamed = (name=="");
}
ASTNODE_NODE_FUNCS(Begin, BEGIN)
virtual void dump(ostream& str);
virtual string name() const { return m_name; } // * = Block name
virtual void name(const string& name) { m_name = name; }
// op1 = Statements
AstNode* stmtsp() const { return op1p()->castNode(); } // op1 = List of statements
void addStmtp(AstNode* nodep) { addOp1p(nodep); }
bool unnamed() const { return m_unnamed; }
};
struct AstGenerate : public AstNode {
@@ -959,17 +981,18 @@ struct AstAssignDly : public AstNodeAssign {
struct AstAssignW : public AstNodeAssign {
// Like assign, but wire/assign's in verilog, the only setting of the specified variable
private:
bool m_allowImplicit; // Output can be a implicit wire
public:
AstAssignW(FileLine* fileline, AstNode* lhsp, AstNode* rhsp)
: AstNodeAssign(fileline, lhsp, rhsp) {
m_allowImplicit = false;
}
: AstNodeAssign(fileline, lhsp, rhsp) { }
ASTNODE_NODE_FUNCS(AssignW, ASSIGNW)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignW(this->fileline(), lhsp, rhsp); }
bool allowImplicit() const { return m_allowImplicit; }
void allowImplicit(bool flag) { m_allowImplicit = flag; }
AstAlways* convertToAlways() {
AstNode* lhs1p = lhsp()->unlinkFrBack();
AstNode* rhs1p = rhsp()->unlinkFrBack();
AstAlways* newp = new AstAlways (fileline(), NULL,
new AstAssign (fileline(), lhs1p, rhs1p));
replaceWith(newp); // User expected to then deleteTree();
return newp;
}
};
struct AstPull : public AstNode {
@@ -1431,6 +1454,8 @@ struct AstWhile : public AstNodeStmt {
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
virtual void addBeforeStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
virtual void addNextStmt(AstNode* newp, AstNode* belowp); // Stop statement searchback here
};
struct AstGenIf : public AstNodeIf {
@@ -1609,7 +1634,7 @@ public:
widthSignedFrom(varp);
m_code = 0;
m_codeInc = varp->arrayElements() * varp->widthWords();
m_lsb = varp->lsb(); m_msb = varp->msb();
m_lsb = varp->lsbEndianed(); m_msb = varp->msbEndianed();
m_arrayLsb = varp->arrayp(0) ? varp->arrayp(0)->lsbConst() : 0;
m_arrayMsb = varp->arrayp(0) ? varp->arrayp(0)->msbConst() : 0;
}
@@ -1623,8 +1648,8 @@ public:
uint32_t code() const { return m_code; }
void code(uint32_t code) { m_code=code; }
uint32_t codeInc() const { return m_codeInc; }
int msb() const { return m_msb; }
int lsb() const { return m_lsb; }
int msbEndianed() const { return m_msb; } // Note msb maybe < lsb if little endian
int lsbEndianed() const { return m_lsb; }
uint32_t arrayMsb() const { return m_arrayMsb; }
uint32_t arrayLsb() const { return m_arrayLsb; }
uint32_t arrayWidth() const { if (!arrayMsb()) return 0; return arrayMsb()-arrayLsb()+1; }
@@ -1706,15 +1731,14 @@ struct AstAttrOf : public AstNode {
private:
// Return a value of a attribute, for example a LSB or array LSB of a signal
AstAttrType m_attrType; // What sort of extraction
int m_dimension; // Dimension number (0 is leftmost), for ARRAY_LSB extractions
public:
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL, int dimension=0)
AstAttrOf(FileLine* fl, AstAttrType attrtype, AstNode* fromp=NULL)
: AstNode(fl) {
setNOp1p(fromp); m_attrType = attrtype; m_dimension = dimension; }
setNOp1p(fromp);
m_attrType = attrtype; }
ASTNODE_NODE_FUNCS(AttrOf, ATTROF)
AstNode* fromp() const { return op1p(); }
AstAttrType attrType() const { return m_attrType; }
int dimension() const { return m_dimension; }
virtual void dump(ostream& str=cout);
};
@@ -2358,7 +2382,7 @@ struct AstDiv : public AstNodeBiop {
ASTNODE_NODE_FUNCS(Div, DIV)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDiv(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %k/ %r)"; }
virtual string emitC() { return "VL_DIV_%lq(%lW, %P, %li, %ri)"; }
virtual string emitC() { return "VL_DIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
@@ -2370,7 +2394,7 @@ struct AstDivS : public AstNodeBiop {
ASTNODE_NODE_FUNCS(DivS, DIVS)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opDivS(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %k/ %r)"; }
virtual string emitC() { return "VL_DIVS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
virtual string emitC() { return "VL_DIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
@@ -2383,7 +2407,7 @@ struct AstModDiv : public AstNodeBiop {
ASTNODE_NODE_FUNCS(ModDiv, MODDIV)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDiv(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %k%% %r)"; }
virtual string emitC() { return "VL_MODDIV_%lq(%lW, %P, %li, %ri)"; }
virtual string emitC() { return "VL_MODDIV_%nq%lq%rq(%lw, %P, %li, %ri)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
@@ -2395,7 +2419,7 @@ struct AstModDivS : public AstNodeBiop {
ASTNODE_NODE_FUNCS(ModDivS, MODDIVS)
virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opModDivS(lhs,rhs); }
virtual string emitVerilog() { return "%k(%l %k%% %r)"; }
virtual string emitC() { return "VL_MODDIVS_%nq%lq%rq(%nw,%lw,%rw, %P, %li, %ri)"; }
virtual string emitC() { return "VL_MODDIVS_%nq%lq%rq(%lw, %P, %li, %ri)"; }
virtual bool cleanOut() {return false;}
virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
virtual bool sizeMattersLhs() {return true;} virtual bool sizeMattersRhs() {return true;}
+35 -23
View File
@@ -25,6 +25,9 @@
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
//
// There are two scopes; named BEGINs change %m and variable scopes.
// Unnamed BEGINs change only variable, not $display("%m") scope.
//
//*************************************************************************
#include "config_build.h"
@@ -47,7 +50,8 @@ private:
// STATE
AstModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_beginScope; // Name of begin blocks above us
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_repeatNum; // Repeat counter
// METHODS
@@ -72,24 +76,31 @@ private:
virtual void visit(AstBegin* nodep, AstNUser*) {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
string oldScope = m_beginScope;
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
//UINFO(8,"nname "<<m_beginScope<<endl);
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0,pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (m_beginScope=="") m_beginScope = ident;
else m_beginScope = m_beginScope + "__DOT__"+ident;
// Create CellInline for dotted resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_beginScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
//UINFO(8,"nname "<<m_namedScope<<endl);
if (nodep->name() != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0,pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (!nodep->unnamed()) {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
// Remap var names
// Remap var names and replace lower Begins
nodep->iterateChildren(*this);
if (AstNode* stmtsp = nodep->stmtsp()) {
@@ -100,12 +111,13 @@ private:
}
pushDeletep(nodep); nodep=NULL;
}
m_beginScope = oldScope;
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (m_beginScope != "") {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_beginScope+"__DOT__"+nodep->name());
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
// Move to module
nodep->unlinkFrBack();
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
@@ -114,9 +126,9 @@ private:
}
virtual void visit(AstCell* nodep, AstNUser*) {
UINFO(8," CELL "<<nodep<<endl);
if (m_beginScope != "") {
if (m_namedScope != "") {
// Rename it
nodep->name(m_beginScope+"__DOT__"+nodep->name());
nodep->name(m_namedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
// Move to module
nodep->unlinkFrBack();
@@ -174,11 +186,11 @@ private:
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()
// Similar code in V3Inline
if (m_beginScope != "") {
if (m_namedScope != "") {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_beginScope)));
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_namedScope)));
if (afterp) nodep->scopeAttrp(afterp);
}
nodep->iterateChildren(*this);
+3 -5
View File
@@ -262,11 +262,10 @@ private:
public:
// CONSTUCTORS
CleanVisitor() {}
virtual ~CleanVisitor() {}
void main(AstNetlist* nodep) {
CleanVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~CleanVisitor() {}
};
//######################################################################
@@ -274,6 +273,5 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
CleanVisitor visitor;
visitor.main(nodep);
CleanVisitor visitor (nodep);
}
+4 -7
View File
@@ -280,8 +280,7 @@ private:
virtual void visit(AstAlways* nodep, AstNUser*) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
nodep->replaceWith(cmtp);
AstNode* stmtsp = nodep->bodysp();
if (stmtsp) {
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
@@ -290,8 +289,7 @@ private:
virtual void visit(AstAlwaysPost* nodep, AstNUser*) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
nodep->replaceWith(cmtp);
AstNode* stmtsp = nodep->bodysp();
if (stmtsp) {
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
@@ -320,8 +318,7 @@ private:
virtual void visit(AstInitial* nodep, AstNUser*) {
AstNode* cmtp = new AstComment(nodep->fileline(), nodep->typeName());
nodep->replaceWith(cmtp);
AstNode* stmtsp = nodep->bodysp();
if (stmtsp) {
if (AstNode* stmtsp = nodep->bodysp()) {
stmtsp->unlinkFrBackWithNext();
cmtp->addNextHere(stmtsp);
}
@@ -534,7 +531,7 @@ private:
public:
// CONSTUCTORS
ClockVisitor(AstNode* nodep) {
ClockVisitor(AstNetlist* nodep) {
m_modp=NULL; m_activep=NULL;
m_evalFuncp = NULL;
m_topScopep=NULL;
+26 -34
View File
@@ -59,7 +59,7 @@ public:
// CONSTUCTORS
ConstVarMarkVisitor(AstNode* nodep) {
AstNode::user4ClearTree(); // Check marked InUse before we're called
nodep->iterateAndNext(*this, NULL);
nodep->accept(*this);
}
virtual ~ConstVarMarkVisitor() {}
};
@@ -1053,7 +1053,7 @@ private:
nodep->iterateChildren(*this);
if (!nodep->varp()) nodep->v3fatalSrc("Not linked");
bool did=false;
if (!m_cpp && nodep->varp()->hasSimpleInit()) {
if (!m_cpp && nodep->varp()->hasSimpleInit() && !nodep->backp()->castAttrOf()) {
//if (debug()) nodep->varp()->initp()->dumpTree(cout," visitvaref: ");
nodep->varp()->initp()->iterateAndNext(*this);
if (operandConst(nodep->varp()->initp())
@@ -1079,23 +1079,7 @@ private:
V3Number num (nodep->fileline(), 32, nodep->fromp()->widthMin());
replaceNum(nodep, num); nodep=NULL;
} else {
if (!nodep->fromp()->castNodeVarRef()) nodep->v3fatalSrc("Not linked");
AstVar* varp = nodep->fromp()->castNodeVarRef()->varp();
if (!varp) nodep->v3fatalSrc("Not linked");
if (nodep->attrType()==AstAttrType::RANGE_LSB) {
if (!varp->rangep()) nodep->v3fatalSrc("RANGE_LSB on vec w/o range\n");
if (operandConst(varp->rangep()->lsbp())) {
V3Number num (nodep->fileline(), 32, varp->lsb());
replaceNum(nodep, num); nodep=NULL;
}
} else if (nodep->attrType()==AstAttrType::ARRAY_LSB) {
AstRange* arrayp=varp->arrayp(nodep->dimension());
if (!arrayp) nodep->v3fatalSrc("ARRAY_LSB on vec w/o range or right # dimensions\n");
if (operandConst(arrayp->lsbp())) {
V3Number num (nodep->fileline(), 32, arrayp->lsbConst());
replaceNum(nodep, num); nodep=NULL;
}
} else nodep->v3fatalSrc("Missing ATTR type case\n");
nodep->v3fatalSrc("Missing ATTR type case");
}
}
bool onlySenItemInSenTree(AstNodeSenItem* nodep) {
@@ -1471,6 +1455,10 @@ private:
}
}
// These are converted by V3Param. Don't constify as we don't want the from() VARREF to disappear, if any
// If output of a presel didn't get consted, chances are V3Param didn't visit properly
virtual void visit(AstNodePreSel* nodep, AstNUser*) {}
//-----
// Below lines are magic expressions processed by astgen
// "AstNODETYPE { # bracket not paren
@@ -1717,8 +1705,7 @@ private:
} else {
// Calculate the width of this operation
if (m_params && !nodep->width()) {
V3Width::widthParams(nodep);
V3Signed::signedParams(nodep);
nodep = V3Width::widthParamsEdit(nodep);
}
nodep->iterateChildren(*this);
}
@@ -1736,57 +1723,62 @@ public:
m_scopep = NULL;
}
virtual ~ConstVisitor() {}
void main(AstNode* nodep) {
AstNode* mainAcceptEdit(AstNode* nodep) {
// Operate starting at a random place
nodep->accept(*this);
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
// Const class functions
void V3Const::constifyParam(AstNode* nodep) {
AstNode* V3Const::constifyParamsEdit(AstNode* nodep) {
//if (debug()>0) nodep->dumpTree(cout," forceConPRE : ");
V3Width::widthSignedIfNotAlready(nodep); // Make sure we've sized everything first
// Resize even if the node already has a width, because burried in the treee we may
// have a node we just created with signing, etc, that isn't sized yet.
nodep = V3Width::widthParamsEdit(nodep); // Make sure we've sized everything first
ConstVisitor visitor (true,false,false,false);
if (AstVar* varp=nodep->castVar()) {
// If a var wants to be constified, it's really a param, and
// we want the value to be constant. We aren't passed just the
// init value because we need widthing above to handle the var's type.
if (varp->initp()) visitor.main(varp->initp());
if (varp->initp()) visitor.mainAcceptEdit(varp->initp());
} else {
visitor.main(nodep);
nodep = visitor.mainAcceptEdit(nodep);
}
// Because we do edits, nodep links may get trashed and core dump this.
//if (debug()>0) nodep->dumpTree(cout," forceConDONE: ");
return nodep;
}
void V3Const::constifyAll(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,true,false,false);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyAllLint(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,true,false);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyCpp(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,false,true);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyTree(AstNode* nodep) {
AstNode* V3Const::constifyEdit(AstNode* nodep) {
ConstVisitor visitor (false,false,false,false);
visitor.main(nodep);
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
void V3Const::constifyTreeExpensive(AstNode* nodep) {
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
ConstVisitor visitor (false,true,false,false);
visitor.main(nodep);
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
+6 -3
View File
@@ -32,7 +32,8 @@
class V3Const {
public:
// Force this cell node's parameter list to become a constant
static void constifyParam(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyParamsEdit(AstNode* nodep);
// Everything that's possible
static void constifyAll(AstNetlist* nodep);
// Also, warn
@@ -40,9 +41,11 @@ public:
// C++ datatypes
static void constifyCpp(AstNetlist* nodep);
// Only the current node and lower
static void constifyTree(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyEdit(AstNode* nodep);
// Only the current node and lower, with special SenTree optimization
static void constifyTreeExpensive(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyExpensiveEdit(AstNode* nodep);
};
#endif // Guard
+1 -1
View File
@@ -215,7 +215,7 @@ private:
}
// VISITORS - LINE COVERAGE
virtual void visit(AstIf* nodep, AstNUser*) {
virtual void visit(AstIf* nodep, AstNUser*) { // Note not AstNodeIf; other types don't get covered
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
+1 -1
View File
@@ -441,7 +441,7 @@ private:
public:
// CONSTUCTORS
DelayedVisitor(AstNode* nodep) {
DelayedVisitor(AstNetlist* nodep) {
m_inDly = false;
m_activep=NULL;
m_cfuncp=NULL;
+1 -1
View File
@@ -156,7 +156,7 @@ private:
public:
// CONSTUCTORS
DepthVisitor(AstNode* nodep) {
DepthVisitor(AstNetlist* nodep) {
m_modp=NULL;
m_funcp=NULL;
m_stmtp=NULL;
+1 -1
View File
@@ -126,7 +126,7 @@ private:
public:
// CONSTUCTORS
DepthBlockVisitor(AstNode* nodep) {
DepthBlockVisitor(AstNetlist* nodep) {
m_modp=NULL;
m_depth=0;
//
+7 -9
View File
@@ -227,7 +227,7 @@ public:
}
virtual void visit(AstDisplay* nodep, AstNUser*) {
string text = nodep->text();
if (nodep->addNewline()) text += "\\n";
if (nodep->addNewline()) text += "\n";
displayNode(nodep, text, nodep->exprsp(), false);
}
virtual void visit(AstFScanF* nodep, AstNUser*) {
@@ -994,9 +994,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
isStmt = true;
nodep->v3fatalSrc("Unknown displayEmit node type");
}
puts("\"");
ofp()->putsNoTracking(emitDispState.m_format); // Not putsQuoted - already contains \s
puts("\"");
ofp()->putsQuoted(emitDispState.m_format);
// Arguments
for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) {
puts(",");
@@ -1841,7 +1839,7 @@ class EmitCTrace : EmitCStmts {
puts("vcdp->declArray");
} else if (nodep->isQuad()) {
puts("vcdp->declQuad ");
} else if (nodep->msb() || nodep->lsb()) {
} else if (nodep->msbEndianed() || nodep->lsbEndianed()) {
puts("vcdp->declBus ");
} else {
puts("vcdp->declBit ");
@@ -1855,8 +1853,8 @@ class EmitCTrace : EmitCStmts {
} else {
puts(",-1");
}
if (nodep->msb() || nodep->lsb()) {
puts(","+cvtToStr(nodep->msb())+","+cvtToStr(nodep->lsb()));
if (nodep->msbEndianed() || nodep->lsbEndianed()) {
puts(","+cvtToStr(nodep->msbEndianed())+","+cvtToStr(nodep->lsbEndianed()));
}
puts(");");
}
@@ -1870,7 +1868,7 @@ class EmitCTrace : EmitCStmts {
puts("vcdp->"+full+"Array");
} else if (nodep->isQuad()) {
puts("vcdp->"+full+"Quad ");
} else if (nodep->declp()->msb() || nodep->declp()->lsb()) {
} else if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
puts("vcdp->"+full+"Bus ");
} else {
puts("vcdp->"+full+"Bit ");
@@ -1879,7 +1877,7 @@ class EmitCTrace : EmitCStmts {
+ ((arrayindex<0) ? 0 : (arrayindex*nodep->declp()->widthWords()))));
puts(",");
emitTraceValue(nodep, arrayindex);
if (nodep->declp()->msb() || nodep->declp()->lsb()) {
if (nodep->declp()->msbEndianed() || nodep->declp()->lsbEndianed()) {
puts(","+cvtToStr(nodep->declp()->widthMin()));
}
puts(");\n");
+3 -3
View File
@@ -109,7 +109,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(";\n");
}
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
putbs("assign ");
putbs("alias ");
nodep->lhsp()->iterateAndNext(*this);
putbs(" = ");
nodep->rhsp()->iterateAndNext(*this);
@@ -368,8 +368,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstRange* nodep, AstNUser*) {
puts("[");
nodep->msbp()->iterateAndNext(*this); puts(":");
nodep->lsbp()->iterateAndNext(*this); puts("]");
nodep->msbEndianedp()->iterateAndNext(*this); puts(":");
nodep->lsbEndianedp()->iterateAndNext(*this); puts("]");
}
virtual void visit(AstSel* nodep, AstNUser*) {
nodep->fromp()->iterateAndNext(*this); puts("[");
+13 -10
View File
@@ -303,6 +303,18 @@ string V3Error::msgPrefix(V3ErrorCode code) {
else return "%Warning-"+(string)code.ascii()+": ";
}
//======================================================================
// Abort/exit
void V3Error::vlAbort () {
if (V3Error::debugDefault()) {
cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
abort();
} else {
exit(10);
}
}
//======================================================================
// Global Functions
@@ -325,10 +337,6 @@ void V3Error::suppressThisWarning() {
}
}
void V3Error::v3abort () {
v3fatalSrc("v3abort called\n");
}
void V3Error::v3errorEnd (ostringstream& sstr) {
#ifdef __COVERITY__
if (s_errorCode==V3ErrorCode::FATAL) __coverity_panic__(x);
@@ -385,12 +393,7 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
#endif
}
if (V3Error::debugDefault()) {
cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
abort();
} else {
exit(10);
}
vlAbort();
}
}
}
+4 -1
View File
@@ -64,6 +64,7 @@ public:
IMPERFECTSCH, // Imperfect schedule (disabled by default)
IMPLICIT, // Implicit wire
IMPURE, // Impure function not being inlined
LITENDIAN, // Little bit endian vector
MULTIDRIVEN, // Driven from multiple blocks
REDEFMACRO, // Redefining existing define macro
UNDRIVEN, // No drivers
@@ -96,6 +97,7 @@ public:
"BLKANDNBLK",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CMPCONST",
"COMBDLY", "STMTDLY", "SYMRSVDWORD", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
"LITENDIAN",
"MULTIDRIVEN", "REDEFMACRO",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
@@ -118,6 +120,7 @@ public:
|| m_e==CASEWITHX || m_e==CASEX
|| m_e==CMPCONST
|| m_e==IMPLICIT
|| m_e==LITENDIAN
|| m_e==UNDRIVEN || m_e==UNSIGNED
|| m_e==UNUSED || m_e==VARHIDDEN
|| m_e==WIDTH); }
@@ -172,7 +175,7 @@ class V3Error {
static ostringstream& v3errorPrep (V3ErrorCode code) {
s_errorStr.str(""); s_errorCode=code; return s_errorStr; }
static ostringstream& v3errorStr () { return s_errorStr; }
static void v3abort();
static void vlAbort();
static void v3errorEnd(ostringstream& sstr); // static, but often overridden in classes.
};
+3 -6
View File
@@ -905,13 +905,11 @@ private:
public:
// CONSTUCTORS
ExpandVisitor() {
ExpandVisitor(AstNetlist* nodep) {
m_stmtp=NULL;
}
virtual ~ExpandVisitor() {}
void main(AstNode* nodep) {
nodep->accept(*this);
}
virtual ~ExpandVisitor() {}
};
//----------------------------------------------------------------------
@@ -922,6 +920,5 @@ public:
void V3Expand::expandAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ExpandVisitor visitor;
visitor.main(nodep);
ExpandVisitor visitor (nodep);
}
+4 -10
View File
@@ -31,6 +31,7 @@
#include "V3Global.h"
#include "V3File.h"
#include "V3PreShell.h"
#include "V3Ast.h"
//######################################################################
// V3File Internal state
@@ -435,16 +436,9 @@ void V3OutFile::putsQuoted(const char* strg) {
// Quote \ and " for use inside C programs
// Don't use to quote a filename for #include - #include doesn't \ escape.
putcNoTracking('"');
for (const char* cp=strg; *cp; cp++) {
if (*cp == '\\') {
putcNoTracking('\\');
putcNoTracking('\\');
} else if (*cp == '"') {
putcNoTracking('\\');
putcNoTracking('"');
} else {
putcNoTracking (*cp);
}
string quoted = AstNode::quoteName(strg);
for (const char* cp=quoted.c_str(); *cp; cp++) {
putcNoTracking (*cp);
}
putcNoTracking('"');
}
+1 -1
View File
@@ -688,7 +688,7 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
if (debug()>=9) consumerp->dumpTree(cout,"\telimUseCns: ");
//Caution: Can't let V3Const change our handle to consumerp, such as by
// optimizing away this assignment, etc.
V3Const::constifyTree(consumerp);
consumerp = V3Const::constifyEdit(consumerp);
if (debug()>=5) consumerp->dumpTree(cout,"\telimUseDne: ");
}
}
+1 -1
View File
@@ -146,7 +146,7 @@ private:
}
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterateAndNext(*this);
newmodp->iterate(*this); // Not iterateAndNext because newmodp isn't linked; no back
m_cellp = NULL;
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
+1 -1
View File
@@ -87,7 +87,7 @@ private:
UINFO(4," PIN "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
nodep->v3error("Output pin is assigned to a constant, electrical short");
nodep->v3error("Output port is connected to a constant pin, electrical short");
// Use user1p on the PIN to indicate we created an assign for this pin
if (!nodep->user1()) {
nodep->user1(1);
+13 -2
View File
@@ -34,6 +34,7 @@
#include <cstdarg>
#include <unistd.h>
#include <map>
#include <vector>
#include "V3Global.h"
#include "V3Life.h"
@@ -53,13 +54,21 @@ class LifeState {
public:
V3Double0 m_statAssnDel; // Statistic tracking
V3Double0 m_statAssnCon; // Statistic tracking
vector<AstNode*> m_unlinkps;
public:
// CONSTRUCTORS
LifeState() {}
~LifeState() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
V3Stats::addStat("Optimizations, Lifetime constant prop", m_statAssnCon);
for (vector<AstNode*>::iterator it = m_unlinkps.begin(); it != m_unlinkps.end(); ++it) {
(*it)->unlinkFrBack();
(*it)->deleteTree();
}
}
// METHODS
void pushUnlinkDeletep(AstNode* nodep) { m_unlinkps.push_back(nodep); }
};
//######################################################################
@@ -144,9 +153,11 @@ public:
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
// Don't delete it now as it will confuse iteration since it maybe WAY
// above our current iteration point.
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->complexAssign();
oldassp->unlinkFrBack()->deleteTree(); oldassp=NULL;
m_statep->pushUnlinkDeletep(oldassp); oldassp=NULL;
m_statep->m_statAssnDel++;
}
}
@@ -307,7 +318,7 @@ private:
if (lastEdit != AstNode::editCountGbl()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
}
// Has to be direct assignment without any EXTRACTing.
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
+19 -1
View File
@@ -72,6 +72,7 @@ private:
V3SymTable* m_curVarsp; // Symbol table of variables and tasks under table we're inserting into
V3SymTable* m_cellVarsp; // Symbol table of variables under cell's module
int m_beginNum; // Begin block number, 0=none seen
int m_modBeginNum; // Begin block number in module, 0=none seen
bool m_inGenerate; // Inside a generate
vector<V3SymTable*> m_delSymps; // Symbol tables to delete
@@ -193,6 +194,7 @@ private:
m_cellVarsp = NULL;
m_paramNum = 0;
m_beginNum = 0;
m_modBeginNum = 0;
nodep->iterateChildren(*this);
// Prep for next
m_curVarsp = NULL;
@@ -328,8 +330,23 @@ private:
++m_beginNum;
nodep->name(nodep->name()+cvtToStr(m_beginNum));
}
if (m_idState==ID_FIND && nodep->name()=="" && nodep->unnamed()) {
// Unnamed blocks are only important when they contain var
// decls, so search for them. (Otherwise adding all the
// unnamed#'s would just confuse tracing variables in
// places such as tasks, where "task ...; begin ... end"
// are common.
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (stmtp->castVar()) {
++m_modBeginNum;
nodep->name("unnamedblk"+cvtToStr(m_modBeginNum));
break;
}
}
}
// Check naming (we don't really care, but some tools do, so better to warn)
if (m_idState==ID_FIND) {
if (m_idState==ID_FIND && nodep->name()!="") {
findAndInsertAndCheck(nodep, nodep->name());
}
// Recurse
@@ -480,6 +497,7 @@ public:
m_ftaskp = NULL;
m_paramNum = 0;
m_beginNum = 0;
m_modBeginNum = 0;
m_inGenerate = false;
//
rootp->accept(*this);
+3 -6
View File
@@ -258,15 +258,13 @@ private:
public:
// CONSTUCTORS
LinkCellsVisitor() {
LinkCellsVisitor(AstNetlist* rootp) {
m_modp = NULL;
m_libVertexp = NULL;
m_topVertexp = NULL;
}
virtual ~LinkCellsVisitor() {}
void main(AstNetlist* rootp) {
rootp->accept(*this);
}
virtual ~LinkCellsVisitor() {}
};
//######################################################################
@@ -274,6 +272,5 @@ public:
void V3LinkCells::link(AstNetlist* rootp) {
UINFO(4,__FUNCTION__<<": "<<endl);
LinkCellsVisitor visitor;
visitor.main(rootp);
LinkCellsVisitor visitor (rootp);
}
+17 -144
View File
@@ -160,6 +160,11 @@ private:
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
did=1;
}
if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
AstNode* fromp = selp->lhsp()->unlinkFrBack();
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
did=1;
}
}
}
if (!nodep->sensp()->castNodeVarRef()) {
@@ -171,151 +176,19 @@ private:
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
}
void iterateSelTriop(AstNodePreSel* nodep) {
nodep->iterateChildren(*this);
}
AstNode* newSubAttrOf(AstNode* underp, AstNode* fromp, AstAttrType attrType) {
// Account for a variable's LSB in bit selections
// Replace underp with a SUB(underp, ATTROF(varp, attrType))
int dimension=0;
while (fromp && !fromp->castNodeVarRef() && (fromp->castSel() || fromp->castArraySel())) {
if (fromp->castSel()) fromp = fromp->castSel()->fromp();
else fromp = fromp->castArraySel()->fromp();
dimension++;
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
if (!nodep->attrp()) {
nodep->iterateChildren(*this);
// Constification may change the fromp() to a constant, which will loose the
// variable we're extracting from (to determine MSB/LSB/endianness/etc.)
// So we replicate it in another node
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
AstNode* basefromp = AstArraySel::baseFromp(nodep);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
varrefp->cloneTree(false)));
}
AstNodeVarRef* varrefp = fromp->castNodeVarRef();
if (!varrefp) fromp->v3fatalSrc("Bit/array selection of non-variable");
if (!varrefp->varp()) varrefp->v3fatalSrc("Signal not linked");
AstRange* vararrayp = varrefp->varp()->arrayp(dimension);
AstRange* varrangep = varrefp->varp()->rangep();
if ((attrType==AstAttrType::ARRAY_LSB
// SUB #'s Not needed because LSB==0? (1D only, else we'll constify it later)
? (vararrayp && !vararrayp->lsbp()->isZero())
: (varrangep && !varrangep->lsbp()->isZero()))) {
AstNode* newrefp;
if (varrefp->castVarXRef()) {
newrefp = new AstVarXRef(underp->fileline(),
varrefp->varp(), varrefp->castVarXRef()->dotted(), false);
} else {
newrefp = new AstVarRef (underp->fileline(),
varrefp->varp(), false);
}
AstNode* newp = new AstSub (underp->fileline(),
underp,
new AstAttrOf(underp->fileline(),
attrType, newrefp, dimension));
return newp;
} else {
return underp;
}
}
void selCheckDimension(AstSel* nodep) {
// Perform error checks on the node
AstNode* fromp = nodep->lhsp();
AstNode* basefromp = AstArraySel::baseFromp(fromp);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
AstVar* varp = varrefp ? varrefp->varp() : NULL;
if (fromp->castSel()
|| (varp && !varp->rangep() && !varp->isParam())) {
nodep->v3error("Illegal bit select; variable already selected, or bad dimension");
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
// Couldn't tell until link time if [#] references a bit or an array
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
AstNode* basefromp = AstArraySel::baseFromp(fromp);
int dimension = AstArraySel::dimension(fromp);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
if (varrefp
&& varrefp->varp()
&& varrefp->varp()->arrayp(dimension)) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstNode* newp = new AstArraySel
(nodep->fileline(),
fromp,
newSubAttrOf(bitp, fromp, AstAttrType::ARRAY_LSB));
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else {
// SELBIT(range, index) -> SEL(array, index, 1)
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(bitp, fromp, AstAttrType::RANGE_LSB),
new AstConst (nodep->fileline(),one));
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
AstNode* widthp;
if (msbp->castConst() && lsbp->castConst()) {
// Quite common, save V3Const some effort
V3Number widnum (msbp->fileline(),32,msbp->castConst()->toSInt() +1-lsbp->castConst()->toSInt());
widnum.width(32,false); // Unsized so width from user
widthp = new AstConst (msbp->fileline(), widnum);
pushDeletep(msbp);
} else {
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
widthp = new AstSub (lsbp->fileline(),
new AstAdd(msbp->fileline(),
new AstConst(msbp->fileline(),one),
msbp),
lsbp->cloneTree(true));
}
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
// SELPLUS -> SEL
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* lsbp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelMinus* nodep, AstNUser*) {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
V3Number one (msbp->fileline(),32,1); one.width(32,false); // Unsized so width from user
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(new AstSub (msbp->fileline(),
msbp,
new AstSub (msbp->fileline(),
widthp->cloneTree(true),
new AstConst (msbp->fileline(), one))),
fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
+1 -1
View File
@@ -122,7 +122,7 @@ private:
}
public:
// CONSTUCTORS
NameVisitor(AstNode* nodep) {
NameVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~NameVisitor() {}
+139 -13
View File
@@ -245,7 +245,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
case 'd': setBit(obit++,1); setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); break;
case 'e': setBit(obit++,0); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break;
case 'f': setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); setBit(obit++,1); break;
case 'z': case '?':
case 'z': case '?':
setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); setBit(obit++,'z'); break;
case 'x':
setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); setBit(obit++,'x'); break;
@@ -1087,37 +1087,47 @@ V3Number& V3Number::opMulS (const V3Number& lhs, const V3Number& rhs) {
return *this;
}
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 (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large / math not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large / math not implemented yet: "<<*this);
setQuad(lhs.toUQuad() / rhs.toUQuad());
return *this;
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() / rhs.toUQuad());
return *this;
} else {
// Wide division
return opModDivGuts(lhs,rhs,false);
}
}
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();
V3Number lhsNoSign = lhs; if (lhs.isNegative()) lhsNoSign.opUnaryMin(lhs);
V3Number rhsNoSign = rhs; if (rhs.isNegative()) rhsNoSign.opUnaryMin(rhs);
V3Number qNoSign = opDiv(lhsNoSign,rhsNoSign);
//UINFO(9, " >divs-mid "<<lhs<<" "<<rhs<<" "<<qNoSign<<endl);
if ((lhs.isNegative() && !rhs.isNegative())
|| (!lhs.isNegative() && rhs.isNegative())) {
opUnaryMin(qNoSign);
} else {
opAssign(qNoSign);
}
UINFO(9, " <divs-out "<<lhs<<" "<<rhs<<" ="<<*this<<endl);
return *this;
}
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 (lhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large % math not implemented yet: "<<*this);
if (rhs.width()>64) m_fileline->v3fatalSrc("Unsupported: Large % math not implemented yet: "<<*this);
setQuad(lhs.toUQuad() % rhs.toUQuad());
return *this;
if (lhs.width()<=64) {
setQuad(lhs.toUQuad() % rhs.toUQuad());
return *this;
} else {
// Wide modulus
return opModDivGuts(lhs,rhs,true);
}
}
V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
// Signed moddiv
@@ -1133,6 +1143,122 @@ V3Number& V3Number::opModDivS (const V3Number& lhs, const V3Number& rhs) {
}
return *this;
}
V3Number& V3Number::opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus) {
// See Knuth Algorithm D. Computes u/v = q.r
// This isn't massively tuned, as wide division is rare
setZero();
// Find MSB and check for zero.
int words = lhs.words();
int umsbp1 = lhs.mostSetBitP1(); // dividend
int vmsbp1 = rhs.mostSetBitP1(); // divisor
if (VL_UNLIKELY(vmsbp1==0) // rwp==0 so division by zero. Return 0.
|| VL_UNLIKELY(umsbp1==0)) { // 0/x so short circuit and return 0
UINFO(9, " opmoddiv-zero "<<lhs<<" "<<rhs<<" now="<<*this<<endl);
return *this;
}
int uw = VL_WORDS_I(umsbp1); // aka "m" in the algorithm
int vw = VL_WORDS_I(vmsbp1); // aka "n" in the algorithm
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw-1; j >= 0; j--) {
vluint64_t unw64 = ((k<<VL_ULL(32)) + (vluint64_t)(lhs.m_value[j]));
m_value[j] = unw64 / (vluint64_t)(rhs.m_value[0]);
k = unw64 - (vluint64_t)(m_value[j])*(vluint64_t)(rhs.m_value[0]);
}
UINFO(9, " opmoddiv-1w "<<lhs<<" "<<rhs<<" q="<<*this<<" rem=0x"<<hex<<k<<dec<<endl);
if (is_modulus) { setZero(); m_value[0] = k; }
return *this;
}
// +1 word as we may shift during normalization
uint32_t un[VL_MULS_MAX_WORDS+1]; // Fixed size, as MSVC++ doesn't allow [words] here
uint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
// Zero for ease of debugging and to save having to zero for shifts
for (int i=0; i<6; i++) { un[i]=vn[i]=m_value[i]=0; }
for (int i=6; i<words+1; i++) { un[i]=vn[i]=0; } // +1 as vn may get extra word
// Algorithm requires divisor MSB to be set
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
int s = 31-VL_BITBIT_I(vmsbp1-1); // shift amount (0...31)
uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
for (int i = vw-1; i>0; i--) {
vn[i] = (rhs.m_value[i] << s) | (shift_mask & (rhs.m_value[i-1] >> (32-s)));
}
vn[0] = rhs.m_value[0] << s;
// Copy and shift dividend by same amount; may set new upper word
if (s) un[uw] = lhs.m_value[uw-1] >> (32-s);
else un[uw] = 0;
for (int i=uw-1; i>0; i--) {
un[i] = (lhs.m_value[i] << s) | (shift_mask & (lhs.m_value[i-1] >> (32-s)));
}
un[0] = lhs.m_value[0] << s;
//printf(" un="); for(int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n");
//printf(" vn="); for(int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n");
//printf(" mv="); for(int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n");
// Main loop
for (int j = uw - vw; j >= 0; j--) {
// Estimate
vluint64_t unw64 = ((vluint64_t)(un[j+vw])<<VL_ULL(32) | (vluint64_t)(un[j+vw-1]));
vluint64_t qhat = unw64 / (vluint64_t)(vn[vw-1]);
vluint64_t rhat = unw64 - qhat*(vluint64_t)(vn[vw-1]);
again:
if (qhat >= VL_ULL(0x100000000)
|| ((qhat*vn[vw-2]) > ((rhat<<VL_ULL(32)) + un[j+vw-2]))) {
qhat = qhat - 1;
rhat = rhat + vn[vw-1];
if (rhat < VL_ULL(0x100000000)) goto again;
}
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i=0; i<vw; i++) {
vluint64_t p = qhat*vn[i]; // Multiply by estimate
t = un[i+j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract
un[i+j] = t;
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32));
}
t = un[j+vw] - k;
un[j+vw] = t;
this->m_value[j] = qhat; // Save quotient digit
if (t < 0) {
// Over subtracted; correct by adding back
this->m_value[j]--;
k = 0;
for (int i=0; i<vw; i++) {
t = (vluint64_t)(un[i+j]) + (vluint64_t)(vn[i]) + k;
un[i+j] = t;
k = t >> VL_ULL(32);
}
un[j+vw] = un[j+vw] + k;
}
}
//printf(" un="); for(int i=5; i>=0; i--) printf(" %08x",un[i]); printf("\n");
//printf(" vn="); for(int i=5; i>=0; i--) printf(" %08x",vn[i]); printf("\n");
//printf(" mv="); for(int i=5; i>=0; i--) printf(" %08x",m_value[i]); printf("\n");
if (is_modulus) { // modulus
// Need to reverse normalization on copy to output
for (int i=0; i<vw; i++) {
m_value[i] = (un[i] >> s) | (shift_mask & (un[i+1] << (32-s)));
}
for (int i=vw; i<words; i++) m_value[i] = 0;
UINFO(9, " opmoddiv-mod "<<lhs<<" "<<rhs<<" now="<<*this<<endl);
return *this;
} else { // division
UINFO(9, " opmoddiv-div "<<lhs<<" "<<rhs<<" now="<<*this<<endl);
return *this;
}
}
V3Number& V3Number::opPow (const V3Number& lhs, const V3Number& rhs) {
// L(i) bit return, if any 4-state, 4-state return
if (lhs.isFourState() || rhs.isFourState()) return setAllBitsX();
@@ -1185,7 +1311,7 @@ V3Number& V3Number::opExtendS (const V3Number& lhs) {
}
V3Number& V3Number::opClean (const V3Number& lhs, uint32_t bits) {
return opRange(lhs, bits-1, 0);
return opSel(lhs, bits-1, 0);
}
void V3Number::opCleanThis() {
@@ -1195,12 +1321,12 @@ void V3Number::opCleanThis() {
}
}
V3Number& V3Number::opRange (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
V3Number& V3Number::opSel (const V3Number& lhs, const V3Number& msb, const V3Number& lsb) {
if (lsb.isFourState() || msb.isFourState()) return setAllBitsX();
return opRange(lhs, msb.toUInt(), lsb.toUInt());
return opSel(lhs, msb.toUInt(), lsb.toUInt());
}
V3Number& V3Number::opRange (const V3Number& lhs, uint32_t msbval, uint32_t lsbval) {
V3Number& V3Number::opSel (const V3Number& lhs, uint32_t msbval, uint32_t lsbval) {
setZero();
int ibit=lsbval;
for(int bit=0; bit<this->width(); bit++) {
+5 -3
View File
@@ -42,12 +42,12 @@ class V3Number {
vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
// METHODS
void init(FileLine* fileline, int width);
V3Number& setZero();
V3Number& setSingleBits(char value);
void opCleanThis();
public:
FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline=fl; }
V3Number& setZero();
V3Number& setQuad(vluint64_t value);
V3Number& setLong(uint32_t value);
void setBit (int bit, char value) { // Note must be pre-zeroed!
@@ -104,6 +104,8 @@ private:
int words() const { return ((width()+31)/32); }
V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
public:
class VerilogString {}; // for creator type-overload selection
// CONSTRUCTORS
@@ -181,8 +183,8 @@ public:
V3Number& opConcat (const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl (const V3Number& lhs, const V3Number& rhs);
V3Number& opRepl (const V3Number& lhs, uint32_t rhs);
V3Number& opRange (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opRange (const V3Number& lhs, uint32_t rhs, uint32_t ths);
V3Number& opSel (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opSel (const V3Number& lhs, uint32_t rhs, uint32_t ths);
V3Number& opCond (const V3Number& lhs, const V3Number& rhs, const V3Number& ths);
V3Number& opCaseEq (const V3Number& lhs, const V3Number& rhs);
V3Number& opCaseNeq (const V3Number& lhs, const V3Number& rhs);
+4 -1
View File
@@ -769,6 +769,9 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( !strcmp (sw, "-gdb") && (i+1)<argc ) {
shift; // Used only in perl shell
}
else if ( !strcmp (sw, "-gdbbt")) {
// Used only in perl shell
}
else if ( !strcmp (sw, "-mod-prefix") && (i+1)<argc ) {
shift; m_modPrefix = argv[i];
}
@@ -962,7 +965,7 @@ V3Options::V3Options() {
m_outputSplitCTrace = 0;
m_traceDepth = 0;
m_unrollCount = 64;
m_unrollStmts = 20;
m_unrollStmts = 100;
m_compLimitParens = 0;
m_compLimitBlocks = 0;
+2 -1
View File
@@ -1096,7 +1096,8 @@ void OrderVisitor::processDomainsIterate(OrderEitherVertex* vertexp) {
AstNodeSenItem* newtree2p = fromVertexp->domainp()->sensesp()->cloneTree(true);
if (!newtree2p) fromVertexp->domainp()->v3fatalSrc("No senitem found under clocked domain");
newtreep->addSensesp(newtree2p);
V3Const::constifyTreeExpensive(newtreep); // Remove duplicates
newtree2p=NULL; // Below edit may replace it
V3Const::constifyExpensiveEdit(newtreep); // Remove duplicates
newtreep->multi(true); // Comment that it was made from 2 clock domains
domainp = m_finder.getSenTree(domainp->fileline(), newtreep);
if (ddebug) {
+27 -14
View File
@@ -55,7 +55,9 @@ private:
// NODE STATE
// AstModule::user4() // bool True if parameters numbered
// AstVar::user4() // int Global parameter number (for naming new module)
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
AstUser4InUse m_inuser4;
// User1/2/3 used by constant function simulations
// STATE
typedef std::map<AstVar*,AstVar*> VarCloneMap;
@@ -93,7 +95,7 @@ private:
}
}
string paramSmallName(AstModule* modp, AstVar* varp) {
if (!varp->user4()) {
if (varp->user4()<=1) {
makeSmallNames(modp);
}
int index = varp->user4()/256;
@@ -129,11 +131,19 @@ private:
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
if (nodep->isParam()) {
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
V3Const::constifyParam(nodep); // The variable, not just the var->init()
if (!nodep->user4()) {
nodep->user4(1); // Mark done - Note values >1 used for letter numbering
nodep->iterateChildren(*this);
if (nodep->isParam()) {
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
V3Const::constifyParamsEdit(nodep); // The variable, not just the var->init()
}
}
}
// Make sure varrefs cause vars to constify before things above
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (nodep->varp()) nodep->varp()->iterate(*this);
}
// Generate Statements
virtual void visit(AstGenerate* nodep, AstNUser*) {
@@ -151,9 +161,9 @@ private:
nodep->deleteTree(); nodep=NULL;
}
virtual void visit(AstGenIf* nodep, AstNUser*) {
V3Width::widthParams(nodep); // Param typed widthing will NOT recurse the body
V3Signed::signedParams(nodep);
V3Const::constifyParam(nodep->condp());
nodep->condp()->iterateAndNext(*this);
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
V3Const::constifyParamsEdit(nodep->condp()); // condp may change
if (AstConst* constp = nodep->condp()->castConst()) {
AstNode* keepp = (constp->isZero()
? nodep->elsesp()
@@ -165,6 +175,7 @@ private:
nodep->unlinkFrBack();
}
nodep->deleteTree(); nodep=NULL;
// Normal edit rules will now recurse the replacement
} else {
nodep->condp()->v3error("Generate If condition must evaluate to constant");
}
@@ -172,22 +183,23 @@ private:
virtual void visit(AstGenFor* nodep, AstNUser*) {
// We parse a very limited form of FOR, so we don't need to do a full
// simulation to unroll the loop
V3Width::widthParams(nodep); // Param typed widthing will NOT recurse the body
V3Signed::signedParams(nodep);
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
// Note V3Unroll will replace some AstVarRef's to the loop variable with constants
V3Unroll::unrollGen(nodep); nodep=NULL;
}
virtual void visit(AstGenCase* nodep, AstNUser*) {
AstNode* keepp = NULL;
nodep->exprp()->iterateAndNext(*this);
V3Case::caseLint(nodep);
V3Width::widthParams(nodep); // Param typed widthing will NOT recurse the body
V3Signed::signedParams(nodep);
V3Const::constifyParam(nodep->exprp());
V3Width::widthParamsEdit(nodep); // Param typed widthing will NOT recurse the body
V3Const::constifyParamsEdit(nodep->exprp()); // exprp may change
AstConst* exprp = nodep->exprp()->castConst();
// Constify
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
for (AstNode* ep = itemp->condsp(); ep; ) {
AstNode* nextp = ep->nextp(); //May edit list
V3Const::constifyParam(ep);
ep->iterateAndNext(*this);
V3Const::constifyParamsEdit(ep); ep=NULL; // ep may change
ep = nextp;
}
}
@@ -242,13 +254,14 @@ public:
void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Cell: Check for parameters in the instantiation.
nodep->iterateChildren(*this);
if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
if (nodep->paramsp()) {
UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants
if (debug()>9) nodep->dumpTree(cout,"cell:\t");
// Evaluate all module constants
V3Const::constifyParam(nodep);
V3Const::constifyParamsEdit(nodep);
// Make sure constification worked
// Must be a separate loop, as constant conversion may have changed some pointers.
+1
View File
@@ -107,6 +107,7 @@ psl [p]sl
<STRMODE><<EOF>> { linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
<STRMODE>{crnl} { linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
<STRMODE>[^\"\\] { yymore(); }
<STRMODE>{backslash}{crnl} { linenoInc(); yymore(); }
<STRMODE>{backslash}. { yymore(); }
<STRMODE>{quote} { yy_pop_state();
if (V3PreLex::s_currentLexp->m_parenLevel) appendDefValue(yytext,yyleng);
+3 -6
View File
@@ -306,17 +306,15 @@ private:
public:
// CONSTUCTORS
PremitVisitor() {
PremitVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
m_stmtp = NULL;
m_inWhilep = NULL;
m_inTracep = NULL;
}
virtual ~PremitVisitor() {}
void main(AstNode* nodep) {
nodep->accept(*this);
}
virtual ~PremitVisitor() {}
};
//----------------------------------------------------------------------
@@ -327,6 +325,5 @@ public:
void V3Premit::premitAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
PremitVisitor visitor;
visitor.main(nodep);
PremitVisitor visitor (nodep);
}
+2 -2
View File
@@ -237,7 +237,7 @@ private:
}
public:
// CONSTUCTORS
ScopeVisitor(AstNode* nodep) {
ScopeVisitor(AstNetlist* nodep) {
m_aboveCellp = NULL;
m_aboveScopep = NULL;
m_modp = NULL;
@@ -313,7 +313,7 @@ private:
}
public:
// CONSTUCTORS
ScopeCleanupVisitor(AstNode* nodep) {
ScopeCleanupVisitor(AstNetlist* nodep) {
m_scopep = NULL;
nodep->accept(*this);
}
+23 -10
View File
@@ -161,6 +161,13 @@ private:
// so, it's just
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
if (!nodep->castGenIf()) { // for m_paramsOnly
nodep->ifsp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNext(*this);
}
nodep->condp()->iterateAndNext(*this);
}
virtual void visit(AstPin* nodep, AstNUser*) {
// Same as above taskref argument.
nodep->iterateChildren(*this);
@@ -352,12 +359,14 @@ private:
public:
// CONSTRUCTORS
SignedVisitor(AstNode* nodep, bool paramsOnly) {
SignedVisitor(bool paramsOnly) {
m_paramsOnly = paramsOnly;
m_taskDepth = 0;
nodep->accept(*this);
}
virtual ~SignedVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
@@ -384,10 +393,11 @@ private:
}
public:
// CONSTRUCTORS
SignedRemoveVisitor(AstNode* nodep) {
nodep->accept(*this);
}
SignedRemoveVisitor() {}
virtual ~SignedRemoveVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
@@ -395,12 +405,15 @@ public:
void V3Signed::signedAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
SignedVisitor visitor (nodep, false);
SignedRemoveVisitor rvisitor (nodep);
(void)signedParamsEdit(nodep);
}
void V3Signed::signedParams(AstNode* nodep) {
AstNode* V3Signed::signedParamsEdit(AstNode* nodep) {
// Only called from V3Width::widthParamsEdit
UINFO(4,__FUNCTION__<<": "<<endl);
SignedVisitor visitor (nodep, true);
SignedRemoveVisitor rvisitor (nodep);
SignedVisitor visitor (true);
nodep = visitor.mainAcceptEdit(nodep);
SignedRemoveVisitor rvisitor;
nodep = rvisitor.mainAcceptEdit(nodep);
return nodep;
}
+3 -1
View File
@@ -32,7 +32,9 @@
class V3Signed {
public:
static void signedAll(AstNetlist* nodep);
static void signedParams(AstNode* nodep);
protected:
friend class V3Width; // Use widthParamsEdit instead of signedParamsEdit
static AstNode* signedParamsEdit(AstNode* nodep); // May replace nodep
};
#endif // Guard
+2 -1
View File
@@ -503,7 +503,8 @@ private:
UINFO(5," FUNCREF "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
AstFunc* funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
V3Width::widthSignedIfNotAlready(funcp); // Make sure we've sized the function
if (m_params) { V3Width::widthParamsEdit(funcp); } funcp=NULL; // Make sure we've sized the function
funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
// Apply function call values to function
// Note we'd need a stack if we allowed recursive functions!
AstNode* pinp = nodep->pinsp(); AstNode* nextpinp = NULL;
+1 -1
View File
@@ -548,7 +548,7 @@ private:
public:
// CONSTUCTORS
SplitVisitor(AstNode* nodep, bool reorder)
SplitVisitor(AstNetlist* nodep, bool reorder)
: m_reorder(reorder) {
scoreboardClear();
nodep->accept(*this);
+18 -14
View File
@@ -191,11 +191,7 @@ private:
// Wire assigns must become always statements to deal with insertion
// of multiple statements. Perhaps someday make all wassigns into always's?
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
AstNode* lhsp = m_assignwp->lhsp()->unlinkFrBack();
AstNode* rhsp = m_assignwp->rhsp()->unlinkFrBack();
AstNode* assignp = new AstAssign (m_assignwp->fileline(), lhsp, rhsp);
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL;
}
// We make multiple edges if a task is called multiple times from another task.
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
@@ -243,7 +239,7 @@ public:
AstNode::user3ClearTree();
AstNode::user4ClearTree();
//
nodep->iterateAndNext(*this, NULL);
nodep->accept(*this);
//
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
m_callGraph.dumpDotFilePrefixed("task_call");
@@ -280,8 +276,8 @@ private:
}
public:
// CONSTUCTORS
TaskRelinkVisitor(AstNode* nodep) {
nodep->iterateAndNext(*this, NULL);
TaskRelinkVisitor(AstBegin* nodep) { // Passed temporary tree
nodep->accept(*this);
}
virtual ~TaskRelinkVisitor() {}
};
@@ -430,7 +426,12 @@ private:
refp->taskp()->castFunc()->fvarp()->user2p(outvscp);
}
// Replace variable refs
TaskRelinkVisitor visit (beginp);
// Iteration requires a back, so put under temporary node
{
AstBegin* tempp = new AstBegin(beginp->fileline(),"[EditWrapper]",beginp);
TaskRelinkVisitor visit (tempp);
tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
}
//
if (debug()>=9) { beginp->dumpTree(cout,"-iotask: "); }
return beginp;
@@ -582,7 +583,12 @@ private:
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
}
// Replace variable refs
TaskRelinkVisitor visit (cfuncp);
// Iteration requires a back, so put under temporary node
{
AstBegin* tempp = new AstBegin(cfuncp->fileline(),"[EditWrapper]",cfuncp);
TaskRelinkVisitor visit (tempp);
tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
}
// Delete rest of cloned task and return new func
pushDeletep(nodep); nodep=NULL;
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
@@ -599,16 +605,14 @@ private:
m_scopep = oldscopep;
}
void insertBeforeStmt(AstNode* nodep, AstNode* newp) {
// See also AstNode::addBeforeStmt; this predates that function
if (debug()>=9) { nodep->dumpTree(cout,"-newstmt:"); }
if (!m_insStmtp) nodep->v3fatalSrc("Function not underneath a statement");
if (m_insMode == IM_BEFORE) {
// Add the whole thing before insertAt
UINFO(5," IM_Before "<<m_insStmtp<<endl);
AstNRelinker handle;
m_insStmtp->unlinkFrBackWithNext(&handle);
if (debug()>=9) { newp->dumpTree(cout,"-newfunc:"); }
newp->addNext(m_insStmtp);
handle.relink(newp);
m_insStmtp->addHereThisAsNext(newp);
}
else if (m_insMode == IM_AFTER) {
UINFO(5," IM_After "<<m_insStmtp);
+4 -2
View File
@@ -125,8 +125,10 @@ private:
AstVar* varp = nodep->varp();
AstScope* scopep = nodep->scopep();
// Compute show name
string showname = scopep->prettyName() + "." + varp->prettyName();
if (showname.substr(0,4) == "TOP.") showname.replace(0,4,"");
// This code assumes SPTRACEVCDC_VERSION >= 1330;
// it uses spaces to separate hierarchy components.
string showname = AstNode::vcdName(scopep->name() + " " + varp->name());
if (showname.substr(0,4) == "TOP ") showname.replace(0,4,"");
if (!m_initSubFuncp) nodep->v3fatalSrc("NULL");
if (varIgnoreTrace(varp)) {
m_statIgnSigs++;
+4
View File
@@ -58,6 +58,7 @@
#include "V3Ast.h"
#include "V3Const.h"
#include "V3Stats.h"
#include "V3Inst.h"
//######################################################################
@@ -545,6 +546,9 @@ private:
refp->user1p(enp);
refp->varp()->user1p(enp);
}
// Simplify interconnect in preperation for V3Inst
// (This could be a separate visitor, but we're in the neighborhood)
V3Inst::pinReconnectSimple(nodep, m_cellp, m_modp);
}
// Default: Just iterate
+154 -80
View File
@@ -51,13 +51,18 @@ class UnknownVisitor : public AstNVisitor {
private:
// NODE STATE
// Cleared on Netlist
// AstSel::user() -> bool. Set true if already processed
// AstArraySel::user() -> bool. Set true if already processed
// AstNode::user2p() -> AstIf* Inserted if assignment for conditional
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
AstModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
V3Double0 m_statUnkVars; // Statistic tracking
AstModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
V3Double0 m_statUnkVars; // Statistic tracking
AstAssignW* m_assignwp; // Current assignment
AstAssignDly* m_assigndlyp; // Current assignment
// METHODS
static int debug() {
@@ -66,6 +71,80 @@ private:
return level;
}
void replaceBoundLvalue(AstNode* nodep, AstNode* condp) {
// Spec says a out-of-range LHS SEL results in a NOP.
// This is a PITA. We could:
// 1. IF(...) around an ASSIGN,
// but that would break a "foo[TOO_BIG]=$fopen(...)".
// 2. Hack to extend the size of the output structure
// by one bit, and write to that temporary, but never read it.
// That makes there be two widths() and is likely a bug farm.
// 3. Make a special SEL to choose between the real lvalue
// and a temporary NOP register.
// 4. Assign to a temp, then IF that assignment.
// This is suspected to be nicest to later optimizations.
// 4 seems best but breaks later optimizations. 3 was tried,
// but makes a mess in the emitter as lvalue switching is needed. So 4.
// SEL(...) -> temp
// if (COND(LTE(bit<=maxlsb))) ASSIGN(SEL(...)),temp)
if (m_assignwp) {
// Wire assigns must become always statements to deal with insertion
// of multiple statements. Perhaps someday make all wassigns into always's?
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL;
}
bool needDly = m_assigndlyp;
if (m_assigndlyp) {
// Delayed assignments become normal assignments,
// then the temp created becomes the delayed assignment
AstNode* newp = new AstAssign(m_assigndlyp->fileline(),
m_assigndlyp->lhsp()->unlinkFrBackWithNext(),
m_assigndlyp->rhsp()->unlinkFrBackWithNext());
m_assigndlyp->replaceWith(newp); pushDeletep(m_assigndlyp); m_assigndlyp=NULL;
}
AstNode* prep = nodep;
// Scan back to put the condlvalue above all selects (IE top of the lvalue)
while (prep->backp()->castNodeSel()
|| prep->backp()->castSel()) {
prep=prep->backp();
}
FileLine* fl = nodep->fileline();
nodep=NULL; // Zap it so we don't use it by mistake - use prep
// Already exists; rather than IF(a,... IF(b... optimize to IF(a&&b,
// Saves us teaching V3Const how to optimize, and it won't be needed again.
if (AstIf* ifp = prep->user2p()->castNode()->castIf()) {
if (needDly) prep->v3fatalSrc("Should have already converted to non-delay");
AstNRelinker replaceHandle;
AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
AstNode* newp = new AstLogAnd (condp->fileline(),
condp,
earliercondp);
UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl);
replaceHandle.relink(newp);
}
else {
string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
new AstRange(fl, prep->width()-1, 0));
m_modp->addStmtp(varp);
AstNode* abovep = prep->backp(); // Grab above point before loose it w/ next replace
prep->replaceWith(new AstVarRef(fl, varp, true));
AstNode* newp = new AstIf(fl, condp,
(needDly
? ((new AstAssignDly(fl, prep,
new AstVarRef(fl, varp, false)))->castNode())
: ((new AstAssign (fl, prep,
new AstVarRef(fl, varp, false)))->castNode())),
NULL);
if (debug()>=9) newp->dumpTree(cout," _new: ");
abovep->addNextStmt(newp,abovep);
prep->user2p(newp); // Save so we may LogAnd it next time
}
}
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
UINFO(4," MOD "<<nodep<<endl);
@@ -74,6 +153,16 @@ private:
nodep->iterateChildren(*this);
m_modp = NULL;
}
virtual void visit(AstAssignDly* nodep, AstNUser*) {
m_assigndlyp = nodep;
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assigndlyp = NULL;
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
m_assignwp = nodep;
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assignwp = NULL;
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
m_constXCvt = false; // Avoid loosing the X's in casex
nodep->condsp()->iterateAndNext(*this);
@@ -82,11 +171,11 @@ private:
}
void visitEqNeqCase(AstNodeBiop* nodep) {
UINFO(4," N/EQCASE->EQ "<<nodep<<endl);
V3Const::constifyTree(nodep->lhsp());
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) {
// Both sides are constant, node can be constant
V3Const::constifyTree(nodep); nodep=NULL;
V3Const::constifyEdit(nodep); nodep=NULL;
return;
} else {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
@@ -112,11 +201,11 @@ private:
}
void visitEqNeqWild(AstNodeBiop* nodep) {
UINFO(4," N/EQWILD->EQ "<<nodep<<endl);
V3Const::constifyTree(nodep->lhsp());
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) {
// Both sides are constant, node can be constant
V3Const::constifyTree(nodep); nodep=NULL;
V3Const::constifyEdit(nodep); nodep=NULL;
return;
} else {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
@@ -249,52 +338,35 @@ private:
int maxlsb = maxmsb - nodep->widthMin() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
if (!lvalue) {
// See if the condition is constant true
AstNode* condp = new AstLte (nodep->fileline(),
nodep->lsbp()->cloneTree(false),
new AstConst(nodep->fileline(), maxlsbnum));
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
condp->deleteTree();
}
else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
xnum.setAllBitsX();
// Put the new nodes under a temporary XOR operator we'll rip up in a moment.
// This way when we constify, if the expression
// is a constant it will still be under the XOR.
AstXor* newp = new AstXor (
nodep->fileline(),
new AstCondBound (nodep->fileline(),
new AstLte (nodep->fileline(),
nodep->lsbp()->cloneTree(false),
new AstConst(nodep->fileline(), maxlsbnum)),
nodep,
new AstConst(nodep->fileline(), xnum)),
new AstConst (nodep->fileline(), 0)); // Just so it's a valid XOR
AstNode* newp = new AstCondBound (nodep->fileline(),
condp,
nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout," _new: ");
V3Const::constifyTree(newp->lhsp()); // Just the conditional
if (debug()>=9) newp->dumpTree(cout," _con: ");
// Link in conditional, can blow away temp xor
AstNode* nnp = newp->lhsp()->unlinkFrBack();
replaceHandle.relink(nnp); nodep=NULL;
newp->deleteTree(); newp=NULL;
// Added X's, tristate them too
nnp->accept(*this);
}
else {
// SEL(...) -> SEL(COND(LTE(bit<=maxlsb), bit, 0))
AstNRelinker replaceHandle;
AstNode* lsbp = nodep->lsbp()->unlinkFrBack(&replaceHandle);
V3Number zeronum (nodep->fileline(), lsbp->width(), 0);
AstCondBound* newp = new AstCondBound
(lsbp->fileline(),
new AstLte (lsbp->fileline(),
lsbp->cloneTree(false),
new AstConst(lsbp->fileline(), maxlsbnum)),
lsbp,
new AstConst(lsbp->fileline(), zeronum));
// Link in conditional
replaceHandle.relink(newp);
// Added X's, tristate them too
if (debug()>=9) nodep->dumpTree(cout," _new: ");
V3Const::constifyTree(nodep);
if (debug()>=9) nodep->dumpTree(cout," _con: ");
nodep->iterateChildren(*this);
newp->accept(*this);
}
else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
}
@@ -303,6 +375,7 @@ private:
nodep->iterateChildren(*this);
if (!nodep->user1()) {
nodep->user1(1);
if (debug()==9) nodep->dumpTree(cout,"-in: ");
// Guard against reading/writing past end of arrays
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
int dimension = AstArraySel::dimension(nodep->fromp());
@@ -319,53 +392,50 @@ private:
}
if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb);
if (!lvalue
// See if the condition is constant true
AstNode* condp = new AstLte (nodep->fileline(),
nodep->bitp()->cloneTree(false),
new AstConst(nodep->fileline(), widthnum));
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
condp->deleteTree();
}
else if (!lvalue
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
xnum.setAllBitsX();
// Put the new nodes under a temporary XOR operator we'll rip up in a moment.
// This way when we constify, if the expression
// is a constant it will still be under the XOR.
AstXor* newp = new AstXor (
nodep->fileline(),
new AstCondBound (nodep->fileline(),
new AstLte (nodep->fileline(),
nodep->bitp()->cloneTree(false),
new AstConst(nodep->fileline(), widthnum)),
nodep,
new AstConst(nodep->fileline(), xnum)),
new AstConst (nodep->fileline(), 0)); // Just so it's a valid XOR
AstNode* newp = new AstCondBound (nodep->fileline(),
condp,
nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout," _new: ");
V3Const::constifyTree(newp->lhsp()); // Just the conditional
if (debug()>=9) newp->dumpTree(cout," _con: ");
// Link in conditional, can blow away temp xor
AstNode* nnp = newp->lhsp()->unlinkFrBack();
replaceHandle.relink(nnp); nodep=NULL;
newp->deleteTree(); newp=NULL;
replaceHandle.relink(newp);
// Added X's, tristate them too
nnp->accept(*this);
newp->accept(*this);
}
else {
else if (!lvalue) { // Mid-multidimension read, just use zero
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
AstNRelinker replaceHandle;
AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
V3Number zeronum (nodep->fileline(), bitp->width(), 0);
AstCondBound* newp = new AstCondBound
(bitp->fileline(),
new AstLte (bitp->fileline(),
bitp->cloneTree(false),
new AstConst(bitp->fileline(), widthnum)),
bitp,
new AstConst(bitp->fileline(), zeronum));
replaceHandle.relink(newp);
AstNode* newp = new AstCondBound (bitp->fileline(),
condp,
bitp,
new AstConst(bitp->fileline(), zeronum));
// Added X's, tristate them too
if (debug()>=9) nodep->dumpTree(cout," _new: ");
V3Const::constifyTree(nodep);
if (debug()>=9) nodep->dumpTree(cout," _con: ");
nodep->iterateChildren(*this);
if (debug()>=9) newp->dumpTree(cout," _new: ");
replaceHandle.relink(newp);
newp->accept(*this);
}
else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
}
@@ -377,7 +447,11 @@ private:
public:
// CONSTUCTORS
UnknownVisitor(AstNode* nodep) {
UnknownVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_assigndlyp = NULL;
m_assignwp = NULL;
m_constXCvt = false;
nodep->accept(*this);
}
virtual ~UnknownVisitor() {
+21 -15
View File
@@ -108,7 +108,7 @@ private:
if (nodep->castGenFor() && !m_forVarp->isGenVar()) {
nodep->v3error("Non-genvar used in generate for: "<<m_forVarp->name()<<endl);
}
if (m_generate) V3Const::constifyParam(initAssp->rhsp());
if (m_generate) V3Const::constifyParamsEdit(initAssp->rhsp()); // rhsp may change
AstConst* constInitp = initAssp->rhsp()->castConst();
if (!constInitp) return cantUnroll(nodep, "non-constant initializer");
//
@@ -142,7 +142,7 @@ private:
// Subtracts have it on the rhs, because you write i=i-1; i=1-i is non-sensible.
AstConst* preconstIncp = (subtract ? incInstrp->rhsp()->castConst()
: incInstrp->lhsp()->castConst());
if (m_generate) V3Const::constifyParam(preconstIncp);
if (m_generate) preconstIncp = V3Const::constifyParamsEdit(preconstIncp)->castConst();
AstConst* constIncp = (subtract ? incInstrp->rhsp()->castConst()
: incInstrp->lhsp()->castConst());
UINFO(8, " Inc expr ok: "<<constIncp<<endl);
@@ -161,7 +161,7 @@ private:
if (condBip->lhsp()->castVarRef()->varp() != m_forVarp
|| condBip->lhsp()->castVarRef()->varScopep() != m_forVscp)
return cantUnroll(nodep, "different variable in condition");
if (m_generate) V3Const::constifyParam(condBip->rhsp());
if (m_generate) V3Const::constifyParamsEdit(condBip->rhsp()); // rhsp may change
AstConst* constStopp = condBip->rhsp()->castConst();
if (!constStopp) return cantUnroll(nodep, "non-constant final value");
UINFO(8, " Stop expr ok: "<<constStopp<<endl);
@@ -257,9 +257,14 @@ private:
m_varValuep = new AstConst(nodep->fileline(), loopValue);
m_varModeReplace = true;
oneloopp->iterateAndNext(*this);
m_varModeReplace = false;
// Iteration requires a back, so put under temporary node
if (oneloopp) {
AstBegin* tempp = new AstBegin(oneloopp->fileline(),"[EditWrapper]",oneloopp);
m_varModeReplace = true;
tempp->stmtsp()->iterateAndNext(*this);
m_varModeReplace = false;
tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
}
if (newbodysp) newbodysp->addNext(oneloopp);
else newbodysp = oneloopp;
@@ -294,17 +299,17 @@ private:
if (m_varModeCheck || m_varModeReplace) {
} else {
// Constify before unroll call, as it may change what is underneath.
if (nodep->precondsp()) V3Const::constifyTree(nodep->precondsp());
if (nodep->condp()) V3Const::constifyTree(nodep->condp());
if (nodep->precondsp()) V3Const::constifyEdit(nodep->precondsp()); // precondsp may change
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); //condp may change
// Grab initial value
AstNode* initp = NULL; // Should be statement before the while.
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
if (initp) V3Const::constifyTree(initp);
initp = NULL; if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
if (initp) { V3Const::constifyEdit(initp); initp=NULL; }
if (nodep->backp()->nextp() == nodep) initp=nodep->backp();
// Grab assignment
AstNode* incp = NULL; // Should be last statement
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {}
if (incp) V3Const::constifyTree(incp);
if (incp) { V3Const::constifyEdit(incp); incp=NULL; }
for (incp = nodep->bodysp(); incp && incp->nextp(); incp = incp->nextp()) {} // Again, as may have changed
// And check it
if (forUnrollCheck(nodep, initp,
@@ -321,9 +326,9 @@ private:
if (m_varModeCheck || m_varModeReplace) {
} else {
// Constify before unroll call, as it may change what is underneath.
if (nodep->initsp()) V3Const::constifyTree(nodep->initsp());
if (nodep->condp()) V3Const::constifyTree(nodep->condp());
if (nodep->incsp()) V3Const::constifyTree(nodep->incsp());
if (nodep->initsp()) V3Const::constifyEdit(nodep->initsp()); // initsp may change
if (nodep->condp()) V3Const::constifyEdit(nodep->condp()); // condp may change
if (nodep->incsp()) V3Const::constifyEdit(nodep->incsp()); // incsp may change
if (nodep->condp()->isZero()) {
// We don't need to do any loops. Remove the GenFor,
// Genvar's don't care about any initial assignments.
@@ -383,7 +388,8 @@ private:
if (m_varModeReplace
&& nodep->varp() == m_forVarp
&& nodep->varScopep() == m_forVscp
&& !nodep->lvalue()) {
&& !nodep->lvalue()
&& !nodep->backp()->castAttrOf()) { // Most likely under a select
AstNode* newconstp = m_varValuep->cloneTree(false);
nodep->replaceWith(newconstp);
pushDeletep(nodep);
+146 -82
View File
@@ -231,7 +231,7 @@ private:
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
V3Const::constifyParam(nodep->rhsp());
V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
AstConst* constp = nodep->rhsp()->castConst();
if (!constp) { nodep->v3error("Replication value isn't a constant."); return; }
uint32_t times = constp->toUInt();
@@ -249,45 +249,26 @@ private:
}
}
virtual void visit(AstRange* nodep, AstNUser* vup) {
// If there's an edit, then processes the edit'ee (can't just rely on iterateChildren because sometimes we for(...) here ourself
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
if (vup->c()->prelim()) {
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
V3Const::constifyParam(nodep->msbp());
V3Const::constifyParam(nodep->lsbp());
AstConst* msbConstp = nodep->msbp()->castConst();
AstConst* lsbConstp = nodep->lsbp()->castConst();
if (!msbConstp || !lsbConstp) {
if (!msbConstp) nodep->v3error("MSB of bit range isn't a constant");
if (!lsbConstp) nodep->v3error("LSB of bit range isn't a constant");
nodep->width(1,1); return;
}
int msb = msbConstp->toSInt();
int lsb = lsbConstp->toSInt();
if (msb > (1<<28)) nodep->v3error("MSB of bit range is huge; vector of over 1billion bits: 0x"<<hex<<msb);
if (msb<lsb) {
// If it's a array, ok to have either ordering, we'll just correct
// So, see if we're sitting under a variable's arrayp.
AstNode* huntbackp = nodep;
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
if (huntbackp->backp()->castVar()
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
} else {
nodep->v3error("Unsupported: MSB < LSB of bit range: "<<msb<<"<"<<lsb);
}
// Correct it.
swap(msbConstp, lsbConstp);
int x=msb; msb=lsb; lsb=x;
}
int width = msb-lsb+1;
int width = nodep->elementsConst();
if (width > (1<<28)) nodep->v3error("Width of bit range is huge; vector of over 1billion bits: 0x"<<hex<<width);
nodep->width(width,width);
if (nodep->littleEndian()) {
nodep->v3warn(LITENDIAN,"Little bit endian vector: MSB < LSB of bit range: "<<nodep->lsbConst()<<":"<<nodep->msbConst());
}
}
}
virtual void visit(AstSel* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
V3Const::constifyParam(nodep->widthp());
V3Const::constifyParamsEdit(nodep->widthp()); // widthp may change
AstConst* widthConstp = nodep->widthp()->castConst();
if (!widthConstp) {
nodep->v3error("Width of bit extract isn't a constant");
@@ -323,7 +304,8 @@ private:
fromlsb = varrp->varp()->lsb();
}
int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,BOTH).p());
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,FINAL).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,FINAL).p());
if (widthBad(nodep->lsbp(),selwidth,selwidth)
&& nodep->lsbp()->width()!=32) {
nodep->v3warn(WIDTH,"Bit extraction of var["<<frommsb<<":"<<fromlsb<<"] requires "
@@ -341,6 +323,7 @@ private:
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<frommsb<<":"<<fromlsb);
}
// iterate FINAL is two blocks above
widthCheck(nodep,"Extract Range",nodep->lsbp(),selwidth,selwidth,true);
}
}
@@ -348,7 +331,7 @@ private:
virtual void visit(AstArraySel* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
nodep->bitp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
int dimension = AstArraySel::dimension(nodep->fromp());
AstNodeVarRef* varrp = basefromp->castNodeVarRef();
@@ -369,7 +352,7 @@ private:
nodep->width(outwidth,outwidth); // Width out = width of array
}
int selwidth = V3Number::log2b(frommsb+1-1)+1; // Width to address a bit
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,BOTH).p());
nodep->fromp()->iterateAndNext(*this,WidthVP(selwidth,selwidth,FINAL).p());
if (widthBad(nodep->bitp(),selwidth,selwidth)
&& nodep->bitp()->width()!=32)
nodep->v3warn(WIDTH,"Bit extraction of array["<<frommsb<<":"<<fromlsb<<"] requires "
@@ -381,6 +364,54 @@ private:
widthCheck(nodep,"Extract Range",nodep->bitp(),selwidth,selwidth,true);
}
}
virtual void visit(AstSelBit* nodep, AstNUser* vup) {
// Just a quick check as after V3Param these nodes instead are AstSel's
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelBit should disappear after widthSel");
if (vup->c()->prelim()) {
nodep->lhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); // from
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p()); // bit
}
}
virtual void visit(AstSelExtract* nodep, AstNUser* vup) {
// Just a quick check as after V3Param these nodes instead are AstSel's
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelExtract should disappear after widthSel");
if (vup->c()->prelim()) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->msbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->lsbp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
}
}
virtual void visit(AstSelPlus* nodep, AstNUser* vup) {
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelPlus should disappear after widthSel");
if (vup->c()->prelim()) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->bitp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (AstConst* constp = nodep->widthp()->castConst()) {
int width = constp->toSInt();
nodep->width(width,width);
}
}
}
virtual void visit(AstSelMinus* nodep, AstNUser* vup) {
AstNode* selp = V3Width::widthSelNoIterEdit(nodep); if (selp!=nodep) { nodep=NULL; selp->iterate(*this,vup); return; }
nodep->v3fatalSrc("AstSelMinus should disappear after widthSel");
if (vup->c()->prelim()) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->bitp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->widthp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (AstConst* constp = nodep->widthp()->castConst()) {
int width = constp->toSInt();
nodep->width(width,width);
}
}
}
virtual void visit(AstExtend* nodep, AstNUser* vup) {
// Only created by this process, so we know width from here down it is correct.
}
@@ -395,6 +426,8 @@ private:
nodep->width(nodep->num().width(), nodep->num().minWidth());
}
}
// We don't size the constant until we commit the widths, as need parameters
// to remain unsized, and numbers to remain unsized to avoid backp() warnings
}
virtual void visit(AstRand* nodep, AstNUser* vup) {
if (vup->c()->prelim()) {
@@ -429,8 +462,8 @@ private:
int selwidth = V3Number::log2b(nodep->lhsp()->width())+1;
nodep->width(selwidth,selwidth);
}
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
nodep->fromp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->width(32,1); // Approximation, unsized 32
}
@@ -459,7 +492,10 @@ private:
width = mwidth = 0; // But see below later.
}
if (nodep->initp()) {
nodep->initp()->iterateAndNext(*this,WidthVP(width,0,BOTH).p());
nodep->initp()->iterateAndNext(*this,WidthVP(width,0,PRELIM).p());
// Although nodep will get a different width for parameters just below,
// we want the init numbers to retain their width/minwidth until parameters are replaced.
nodep->initp()->iterateAndNext(*this,WidthVP(width,0,FINAL).p());
if (nodep->isParam()) {
if (nodep->rangep()) {
// Parameters need to preserve widthMin from the value, not get a constant size
@@ -481,7 +517,8 @@ private:
nodep->rangep(new AstRange(nodep->fileline(),width-1,0));
nodep->rangep()->width(width,width);
}
nodep->width(width,mwidth); // No need to check; varrefs are the "checkers"
nodep->width(width,mwidth);
// See above note about initp()->...FINAL
if (nodep->initp()) widthCheck(nodep,"Initial value",nodep->initp(),width,mwidth);
UINFO(4,"varWidthed "<<nodep<<endl);
//if (debug()) nodep->dumpTree(cout," InitPos: ");
@@ -518,8 +555,9 @@ private:
AstNodeCase* lastCasep = m_casep;
m_casep = nodep;
nodep->exprp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,PRELIM).p());
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p());
for (AstCaseItem* nextp, *itemp = nodep->itemsp(); itemp; itemp=nextp) {
nextp = itemp->nextp()->castCaseItem(); // Prelim may cause the node to get replaced
itemp->iterate(*this,WidthVP(ANYSIZE,0,PRELIM).p()); itemp=NULL;
}
int width = nodep->exprp()->width();
int mwidth = nodep->exprp()->widthMin();
@@ -544,8 +582,11 @@ private:
// Need to look across multiple case values for one set of statements
int width = nodep->condsp()->width();
int mwidth = nodep->condsp()->widthMin();
for (AstNode* nextp, *condp = nodep->condsp(); condp; condp=nextp) {
nextp = condp->nextp(); // Prelim may cause the node to get replaced
condp->iterate(*this,vup); condp=NULL;
}
for (AstNode* condp = nodep->condsp(); condp; condp=condp->nextp()) {
condp->iterate(*this,vup);
width = max(width,condp->width());
mwidth = max(mwidth,condp->widthMin());
if (vup->c()->final()) {
@@ -577,7 +618,7 @@ private:
virtual void visit(AstNodeIf* nodep, AstNUser*) {
// TOP LEVEL NODE
//if (debug()) nodep->dumpTree(cout," IfPre: ");
if (!nodep->castGenIf()) {
if (!nodep->castGenIf()) { // for m_paramsOnly
nodep->ifsp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNext(*this);
}
@@ -730,7 +771,6 @@ private:
<<" generates "<<expwidth<<" bits.");
awidth = expwidth;
}
nodep->width(awidth,awidth);
} else {
if (nodep->modVarp()->isTristate()) {
if (pinwidth != expwidth) {
@@ -749,10 +789,12 @@ private:
// We can't make the RANGE/EXTEND until V3Inst phase, as need RHS of assignment
awidth = expwidth;
}
nodep->width(awidth,awidth);
}
nodep->width(awidth,awidth);
nodep->exprp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
if (!m_cellRangep) {
widthCheckPin(nodep, nodep->exprp(), pinwidth, inputPin);
}
nodep->exprp()->iterateAndNext(*this,WidthVP(awidth,awidth,FINAL).p());
}
//if (debug()) nodep->dumpTree(cout,"- PinPos: ");
}
@@ -795,19 +837,25 @@ private:
m_taskDepth--;
}
// And do the arguments to the task/function too
AstNode* pinp = nodep->pinsp();
AstNode* stmt_nextp; // List may change, so need to keep pointer
for (AstNode* stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
stmt_nextp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()
&& pinp!=NULL) { // Else argument error we'll find later
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
int width = portp->width();
int ewidth = portp->widthMin();
pinp->accept(*this,WidthVP(width,ewidth,BOTH).p());
widthCheck(nodep,"Function Argument",pinp,width,ewidth);
pinp = pin_nextp;
for (int accept_mode=1; accept_mode>=0; accept_mode--) { // Avoid duplicate code; just do inner stuff twice
AstNode* pinp = nodep->pinsp();
for (AstNode* stmt_nextp, *stmtp = nodep->taskp()->stmtsp(); stmtp; stmtp=stmt_nextp) {
stmt_nextp = stmtp->nextp();
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()
&& pinp!=NULL) { // Else argument error we'll find later
AstNode* pin_nextp = pinp->nextp(); // List may change, so remember nextp
if (accept_mode) {
// Prelim may cause the node to get replaced; we've lost our
// pointer, so need to iterate separately later
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),PRELIM).p()); pinp=NULL;
} else {
// Do PRELIM again, because above accept may have exited early due to node replacement
pinp->accept(*this,WidthVP(portp->width(),portp->widthMin(),BOTH).p());
widthCheck(nodep,"Function Argument",pinp,portp->width(),portp->widthMin());
}
pinp = pin_nextp;
}
}
}
}
@@ -837,23 +885,17 @@ private:
bool fixAutoExtend (AstNode*& nodepr, int expWidth);
void fixWidthExtend (AstNode* nodep, int expWidth);
void fixWidthReduce (AstNode* nodep, int expWidth);
void swap (AstNode* ap, AstNode* bp) {
AstNRelinker aHandle;
AstNRelinker bHandle;
ap->unlinkFrBack(&aHandle);
bp->unlinkFrBack(&bHandle);
aHandle.relink(bp);
bHandle.relink(ap);
}
public:
// CONSTUCTORS
WidthVisitor(AstNode* nodep, bool paramsOnly) {
WidthVisitor(bool paramsOnly) {
m_paramsOnly = paramsOnly;
m_taskDepth = 0;
m_cellRangep = NULL;
m_casep = NULL;
nodep->accept(*this, WidthVP(ANYSIZE,0,BOTH).p());
}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
}
virtual ~WidthVisitor() {}
};
@@ -862,8 +904,8 @@ public:
// METHODs
bool WidthVisitor::widthBad (AstNode* nodep, int expWidth, int expWidthMin) {
if (nodep->width()==0) nodep->v3fatalSrc("Under node has no expected width?? Missing Visitor func?");
if (expWidth==0) nodep->v3fatalSrc("Node has no expected width?? Missing Visitor func?");
if (nodep->width()==0) nodep->v3fatalSrc("Under node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidth==0) nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" has no expected width?? Missing Visitor func?");
if (expWidthMin==0) expWidthMin = expWidth;
if (nodep->widthSized() && nodep->width() != expWidthMin) return true;
if (!nodep->widthSized() && nodep->widthMin() > expWidthMin) return true;
@@ -882,8 +924,8 @@ void WidthVisitor::fixWidthExtend (AstNode* nodep, int expWidth) {
// Save later constant propagation work, just right-size it.
V3Number num (nodep->fileline(), expWidth);
num.opAssign(constp->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
newp->signedFrom(constp);
constp->replaceWith(newp);
pushDeletep(constp); constp=NULL;
nodep=newp;
@@ -918,8 +960,8 @@ void WidthVisitor::fixWidthReduce (AstNode* nodep, int expWidth) {
if (constp) {
V3Number num (nodep->fileline(), expWidth);
num.opRedOr(constp->num());
num.isSigned(constp->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
newp->signedFrom(constp);
constp->replaceWith(newp);
nodep=newp;
} else {
@@ -987,6 +1029,7 @@ void WidthVisitor::widthCheck (AstNode* nodep, const char* side,
void WidthVisitor::widthCheckReduce (AstNode* nodep, const char* side,
AstNode* underp, int expWidth, int expWidthMin,
bool ignoreWarn) {
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
if (expWidthMin==0) expWidthMin = expWidth;
if (expWidth!=1) nodep->v3fatalSrc("Only for binary functions");
bool bad = widthBad(underp,expWidth,expWidthMin);
@@ -1005,6 +1048,7 @@ void WidthVisitor::widthCheckReduce (AstNode* nodep, const char* side,
}
void WidthVisitor::widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth, bool inputPin) {
// Before calling this, iterate into underp with FINAL state, so numbers get resized appropriately
bool bad = widthBad(underp,expWidth,expWidth);
if (bad && fixAutoExtend(underp/*ref*/,expWidth)) bad=false; // Changes underp
if (bad) {
@@ -1171,14 +1215,31 @@ class WidthCommitVisitor : public AstNVisitor {
// Copy all width() to widthMin(). V3Const expects this
private:
// VISITORS
virtual void visit(AstConst* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
if ((nodep->width() != nodep->num().width()) || !nodep->num().sized()) {
V3Number num (nodep->fileline(), nodep->width());
num.opAssign(nodep->num());
num.isSigned(nodep->isSigned());
AstNode* newp = new AstConst(nodep->fileline(), num);
nodep->replaceWith(newp);
//if (debug()>4) nodep->dumpTree(cout," fixConstSize_old: ");
//if (debug()>4) newp->dumpTree(cout," _new: ");
pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->width(nodep->width(),nodep->width());
nodep->iterateChildren(*this);
}
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
// This check could go anywhere after V3Param
nodep->v3fatalSrc("Presels should have been removed before this point");
}
public:
// CONSTUCTORS
WidthCommitVisitor(AstNode* nodep) {
nodep->iterateAndNext(*this, NULL);
WidthCommitVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~WidthCommitVisitor() {}
};
@@ -1189,24 +1250,27 @@ public:
void V3Width::width(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
// We should do it in bottom-up module order, but it works in any order.
WidthVisitor visitor (nodep, false);
WidthVisitor visitor (false);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Width::widthParams(AstNode* nodep) {
AstNode* V3Width::widthParamsEdit(AstNode* nodep) {
UINFO(4,__FUNCTION__<<": "<<endl);
// We should do it in bottom-up module order, but it works in any order.
WidthVisitor visitor (nodep, true);
WidthVisitor visitor (true);
nodep = visitor.mainAcceptEdit(nodep);
nodep = V3Signed::signedParamsEdit(nodep);
return nodep;
}
void V3Width::widthSignedIfNotAlready(AstNode* nodep) {
AstNode* V3Width::widthParamsEditIfNeed(AstNode* nodep) {
if (!nodep->width()) {
V3Width::widthParams(nodep);
V3Signed::signedParams(nodep);
nodep = V3Width::widthParamsEdit(nodep);
}
return nodep;
}
void V3Width::widthCommit(AstNode* nodep) {
void V3Width::widthCommit(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
WidthCommitVisitor visitor (nodep);
}
+8 -3
View File
@@ -33,10 +33,15 @@ class V3Width {
public:
static void width(AstNetlist* nodep);
// Smaller step... Only do a single node for parameter propagation
static void widthParams(AstNode* nodep);
static void widthSignedIfNotAlready(AstNode* nodep);
static AstNode* widthParamsEdit(AstNode* nodep);
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
// Final step... Mark all widths as equal
static void widthCommit(AstNode* nodep);
static void widthCommit(AstNetlist* nodep);
// For use only in WidthVisitor
// Replace AstSelBit, etc with AstSel/AstArraySel
// Returns replacement node if nodep was deleted, or null if none.
static AstNode* widthSelNoIterEdit(AstNode* nodep);
};
#endif // Guard
+345
View File
@@ -0,0 +1,345 @@
//*************************************************************************
// DESCRIPTION: Verilator: Expression width calculations
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// V3WidthSel's Transformations:
// Top down traversal:
// Replace SELPLUS/SELMINUS with SEL
// Replace SELEXTRACT with SEL
// Replace SELBIT with SEL or ARRAYSEL
//
// This code was once in V3LinkResolve, but little endian bit vectors won't
// work that early. It was considered for V3Width and V3Param, but is
// fairly ugly both places as the nodes change in too strongly
// interconnected ways.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include <cstdio>
#include <cstdarg>
#include <unistd.h>
#include "V3Global.h"
#include "V3Width.h"
#include "V3Const.h"
//######################################################################
// Width state, as a visitor of each AstNode
class WidthSelVisitor : public AstNVisitor {
private:
// IMPORTANT
//**** This is not a normal visitor, in that all iteration is instead
// done by the caller (V3Width). This avoids duplicating much of the
// complicated GenCase/GenFor/Cell/Function call logic that all depends
// on if widthing top-down or just for parameters.
#define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel
//
// NODE STATE
// isBelowSeled() used insead of userp, as we're out of
// non-conflicting users, and having a persistent variable means this
// code can be skipped during most later stage constification calls.
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void checkConstantOrReplace(AstNode* nodep, const string& message) {
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
if (!nodep->castConst()) {
nodep->v3error(message);
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
pushDeletep(nodep); nodep=NULL;
}
}
void selCheckDimension(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
// Perform error checks on the node
AstVar* varp = varFromBasefrom(basefromp);
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
int dimensions = varp->arrayDimensions();
if (dimension < dimensions) {
if (rangedSelect) {
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
}
} else if (dimension > dimensions) { // Too many indexes provided
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
} else if (dimension == dimensions) { // Right number, but...
if (!varp->rangep()) {
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
}
}
}
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
// Return lhs-rhs, but if rhs is negative use an add, so we won't
// have to deal with signed math and related 32bit sign extension problems
if (rhs == 0) {
return lhsp;
} else if (rhs > 0) {
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
newp->signedFrom(lhsp);
return newp;
} else { // rhs < 0;
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
newp->signedFrom(lhsp);
return newp;
}
}
AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) {
// Return lhs-rhs
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(rhsp->fileline(),
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
rhsp);
newp->signedFrom(rhsp); // Important as AstSub default is lhs's sign
return newp;
}
AstVar* varFromBasefrom(AstNode* basefromp) {
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
if (!varrefp) basefromp->v3fatalSrc("Bit/array selection of non-variable");
AstVar* varp = varrefp->varp(); if (!varp) varrefp->v3fatalSrc("Signal not linked");
return varp;
}
AstNode* newSubLsbOf(AstNode* underp, AstNode* basefromp) {
// Account for a variable's LSB in bit selections
// Will likely become SUB(underp, lsb_of_signal)
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
AstVar* varp = varFromBasefrom(basefromp);
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
if (!varp->rangep()) {
// vector without range is ok, for example a INTEGER x; y = x[21:0];
return underp;
} else {
if (!varp->rangep()->msbp()->castConst()
|| !varp->rangep()->lsbp()->castConst())
varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp)
if (varp->littleEndian()) {
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
AstNode* newp = newSubNeg(varp->msb(), underp);
return newp;
} else {
// reg [3:1] needs a SUB(under,1)
AstNode* newp = newSubNeg(underp, varp->lsb());
return newp;
}
}
}
// VISITORS
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
virtual void visit(AstRange* nodep, AstNUser*) {
// Convert all range values to constants
UINFO(6,"RANGE "<<nodep<<endl);
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant");
checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant");
int msb = nodep->msbConst();
int lsb = nodep->lsbConst();
if (msb<lsb) {
// If it's an array, ok to have either ordering, we'll just correct
// So, see if we're sitting under a variable's arrayp.
AstNode* huntbackp = nodep;
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
if (huntbackp->backp()->castVar()
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
} else {
// Little endian bits are legal, just remember to swap
// Warning is in V3Width to avoid false warnings when in "off" generate if's
nodep->littleEndian(!nodep->littleEndian());
}
// Internally we'll always have msb() be the greater number
// We only need to correct when doing [] AstSel extraction,
// and when tracing the vector.
nodep->msbp()->swapWith(nodep->lsbp());
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
UINFO(6,"SELBIT "<<nodep<<endl);
if (debug()>=9) nodep->backp()->dumpTree(cout,"-vsbin(-1): ");
// lhsp/rhsp do not need to be constant
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
selCheckDimension(nodep, basefromp, dimension, false);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
AstVar* varp = varFromBasefrom(basefromp);
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
if (varp->arrayp(dimension)) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstRange* arrayp = varp->arrayp(dimension); // NULL checked above
AstNode* subp = bitp;
if (!arrayp->lsbp()->isZero() || arrayp->msbConst()<0) {
subp = newSubNeg (subp, arrayp->lsbConst());
}
AstArraySel* newp = new AstArraySel
(nodep->fileline(),
fromp,
subp);
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else {
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(bitp, basefromp),
// Unsized so width from user
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
UINFO(6,"SELEXTRACT "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX0: ");
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX3: ");
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
AstVar* varp = varFromBasefrom(basefromp);
vlsint32_t msb = msbp->castConst()->toSInt();
vlsint32_t lsb = lsbp->castConst()->toSInt();
selCheckDimension(nodep, basefromp, dimension, msb!=lsb);
if (varp->rangep() && varp->rangep()->littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
}
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
widthp);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
pushDeletep(msbp); msbp=NULL;
}
void replaceSelPlusMinus(AstNodePreSel* nodep) {
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
// Now replace it with a AstSel
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
int width = widthp->castConst()->toSInt();
AstVar* varp = varFromBasefrom(basefromp);
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
selCheckDimension(nodep, basefromp, dimension, width!=1);
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (varp->rangep() && varp->rangep()->littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg((varp->msb()-width+1), rhsp),
widthp);
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
widthp);
}
} else if (nodep->castSelMinus()) {
if (varp->rangep() && varp->rangep()->littleEndian()) {
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(varp->msb(), rhsp),
widthp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(rhsp, varp->lsb()+(width-1)),
widthp);
}
} else {
nodep->v3fatalSrc("Bad Case");
}
UINFO(6," new "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);
}
virtual void visit(AstSelMinus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);
}
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
//--------------------
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
// See notes above; we never iterate
}
public:
// CONSTUCTORS
WidthSelVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
virtual ~WidthSelVisitor() {}
};
//######################################################################
// Width class functions
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
WidthSelVisitor visitor;
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
#undef iterateChildren
+9 -8
View File
@@ -193,19 +193,21 @@ void process () {
V3Inst::dearrayAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
// Expand inouts, stage 2
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
V3Tristate::tristateAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
// 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.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
// Task inlining & pushing BEGINs names to variables/cells
// Begin processing must be after Param, before module inlining
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
// 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.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
// Module inlining
// Cannot remove dead variables after this, as alias information for final
// V3Scope's V3LinkDot is in the AstVar.
@@ -265,7 +267,7 @@ void process () {
// Loop unrolling & convert FORs to WHILEs
V3Unroll::unrollAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
// Convert case statements to if() blocks. Must be after V3Unknown
V3Case::caseAll(v3Global.rootp());
@@ -273,13 +275,12 @@ void process () {
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
}
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
// Make large low-fanin logic blocks into lookup tables
// This should probably be done much later, once we have common logic elimination.
if (v3Global.opt.oTable()) {
+1 -1
View File
@@ -25,7 +25,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.714 2009/09/18"
#define DTVERSION "Verilator 3.720 2009/10/26"
//**********************************************************************
//**** Functions
+4 -3
View File
@@ -19,13 +19,14 @@ my $dir = $ARGV[0]; defined $dir or die "%Error: No directory argument,";
chdir $dir;
my $rev = 'UNKNOWN_REV';
my $data = `git log | head -1`;
if ($data =~ /commit\s*([a-z0-9]+)/i) {
my $data = `git describe`;
if ($data =~ /(verilator.*)/i) {
$rev = $1;
}
$data = `git status`;
if ($data !~ /nothing to commit/i) {
if ($data =~ /Changed but not updated/i
|| $data =~ /Changes to be committed/i) {
$rev .= " (mod)";
}
+20 -18
View File
@@ -136,6 +136,7 @@ void yyerrorf(const char* format, ...) {
ws [ \t\f\r]+
wsnr [ \t\f]+
crnl [\r]*[\n]
/* identifier */
id [a-zA-Z_][a-zA-Z0-9_$]*
/* escaped identifier */
@@ -148,7 +149,7 @@ escid \\[^ \t\f\r\n]+
/* Verilog 1995 */
<V95,V01,V05,S05,PSL>{
{ws} { } /* otherwise ignore white-space */
\n { NEXTLINE(); } /* Count line numbers */
{crnl} { NEXTLINE(); } /* Count line numbers */
/* Extensions to Verilog set, some specified by PSL */
"$c"[0-9]* { FL; return yD_C; } /*Verilator only*/
/* System Tasks */
@@ -765,17 +766,19 @@ escid \\[^ \t\f\r\n]+
/************************************************************************/
/* STRINGS */
<STRING>\n { yyerrorf("Unterminated string\n"); }
<STRING>\r ;
<STRING>[^\"\\]* { yymore(); }
<STRING>{crnl} { yyerrorf("Unterminated string"); }
<STRING>\\{crnl} { yymore(); NEXTLINE(); }
<STRING>\\. { yymore(); }
<STRING>\" { yy_pop_state();
yylval.strp = V3Read::newString(yytext+1,yyleng-2);
return yaSTRING; }
<STRING>. { yymore(); }
<STRING><<EOF>> { yyerrorf("EOF in string");
yyleng = 0; yy_pop_state(); }
/************************************************************************/
/* Attributes */
<ATTRMODE>\n { yymore(); NEXTLINE(); }
<ATTRMODE>{crnl} { yymore(); NEXTLINE(); }
<ATTRMODE>"*)" { yy_pop_state(); }
<ATTRMODE>. { yymore(); }
<ATTRMODE><<EOF>> { yyerrorf("EOF in (*");
@@ -795,7 +798,7 @@ escid \\[^ \t\f\r\n]+
"`accelerate" { } // Verilog-XL compatibility
"`autoexpand_vectornets" { } // Verilog-XL compatibility
"`celldefine" { V3Read::inCellDefine(true); }
"`default_decay_time"{ws}+[^\n]* { } // Verilog spec - delays only
"`default_decay_time"{ws}+[^\n\r]* { } // Verilog spec - delays only
"`delay_mode_distributed" { } // Verilog spec - delays only
"`delay_mode_path" { } // Verilog spec - delays only
"`delay_mode_unit" { } // Verilog spec - delays only
@@ -806,7 +809,7 @@ escid \\[^ \t\f\r\n]+
"`endprotect" { }
"`expand_vectornets" { } // Verilog-XL compatibility
"`inline" { }
"`line"{ws}+[^\n]*\n { V3Read::ppline(yytext); }
"`line"{ws}+[^\n\r]*{crnl} { V3Read::ppline(yytext); }
"`noaccelerate" { } // Verilog-XL compatibility
"`noexpand_vectornets" { } // Verilog-XL compatibility
"`noremove_gatenames" { } // Verilog-XL compatibility
@@ -814,7 +817,7 @@ escid \\[^ \t\f\r\n]+
"`nosuppress_faults" { } // Verilog-XL compatibility
"`nounconnected_drive" { } // Verilog-XL compatibility
"`portcoerce" { }
"`pragma"{ws}+[^\n]*\n { } // Verilog 2005
"`pragma"{ws}+[^\n\r]* { } // Verilog 2005
"`protect" { }
"`psl" { if (V3Read::optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
"`remove_gatenames" { } // Verilog-XL compatibility
@@ -827,7 +830,7 @@ escid \\[^ \t\f\r\n]+
"`systemc_imp_header" { BEGIN SYSCIMPH; }
"`systemc_implementation" { BEGIN SYSCIMP; }
"`systemc_interface" { BEGIN SYSCINT; }
"`timescale"{ws}+[^\n]*\n { NEXTLINE(); } // Verilog spec - not supported
"`timescale"{ws}+[^\n\r]* { } // Verilog spec - not supported
"`verilog" { BEGIN V3Read::lastVerilogState(); }
"`begin_keywords"[ \t]*\"1364-1995\" { yy_push_state(V95); V3Read::pushBeginKeywords(YY_START); }
@@ -838,19 +841,18 @@ escid \\[^ \t\f\r\n]+
"`end_keywords" { yy_pop_state(); if (!V3Read::popBeginKeywords()) yyerrorf("`end_keywords when not inside `begin_keywords block"); }
}
<SYSCHDR>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCHDR; }
<SYSCINT>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCINT; }
<SYSCIMP>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCIMP; }
<SYSCIMPH>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCIMPH; }
<SYSCCTOR>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCCTOR; }
<SYSCDTOR>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCDTOR; }
<IGNORE>[ \t]*[^` \t\n][^\n]*\n { NEXTLINE(); }
<SYSCHDR>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCHDR; }
<SYSCINT>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCINT; }
<SYSCIMP>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCIMP; }
<SYSCIMPH>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCIMPH; }
<SYSCCTOR>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCCTOR; }
<SYSCDTOR>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); yylval.strp = V3Read::newString(yytext); return yaSCDTOR; }
<IGNORE>[ \t]*[^` \t\n\r][^\n\r]*{crnl} { NEXTLINE(); }
/* Pick up text-type data */
<SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
{wsnr}* { yymore(); }
\n { NEXTLINE(); yymore(); }
\r ;
{crnl} { NEXTLINE(); yymore(); }
}
/************************************************************************/
+32 -25
View File
@@ -1395,7 +1395,8 @@ stmtBlock<nodep>: // IEEE: statement + seq_block + par_block
seq_block<nodep>: // ==IEEE: seq_block
// // IEEE doesn't allow declarations in unnamed blocks, but several simulators do.
yBEGIN blockDeclStmtList yEND { $$ = $2; }
// // So need begin's even if unnamed to scope variables down
yBEGIN blockDeclStmtList yEND { $$ = new AstBegin($1,"",$2); }
| yBEGIN /**/ yEND { $$ = NULL; }
| yBEGIN ':' seq_blockId blockDeclStmtList yEND endLabelE { $$ = new AstBegin($2,*$3,$4); }
| yBEGIN ':' seq_blockId /**/ yEND endLabelE { $$ = new AstBegin($2,*$3,NULL); }
@@ -1676,20 +1677,20 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
| yD_STOP parenE { $$ = new AstStop($1); }
| yD_STOP '(' expr ')' { $$ = new AstStop($1); }
//
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
| yD_DISPLAY '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
| yD_WRITE '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
| yD_FDISPLAY '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); }
| yD_FWRITE '(' idClassSel ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); }
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); }
| yD_INFO '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); }
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); }
| yD_WARNING '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); }
| yD_ERROR parenE { $$ = V3Parse::createDisplayError($1); }
| yD_ERROR '(' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
| yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
| yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_FATAL '(' expr ',' yaSTRING commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_DISPLAY parenE { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,"", NULL,NULL); }
| yD_DISPLAY '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$3,NULL,$4); }
| yD_WRITE '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$3,NULL,$4); }
| yD_FDISPLAY '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::DISPLAY,*$5,$3,$6); }
| yD_FWRITE '(' idClassSel ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WRITE, *$5,$3,$6); }
| yD_INFO parenE { $$ = new AstDisplay($1,AstDisplayType::INFO, "", NULL,NULL); }
| yD_INFO '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::INFO, *$3,NULL,$4); }
| yD_WARNING parenE { $$ = new AstDisplay($1,AstDisplayType::WARNING,"", NULL,NULL); }
| yD_WARNING '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::WARNING,*$3,NULL,$4); }
| yD_ERROR parenE { $$ = V3Parse::createDisplayError($1); }
| yD_ERROR '(' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::ERROR, *$3,NULL,$4); $$->addNext(new AstStop($1)); }
| yD_FATAL parenE { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); }
| yD_FATAL '(' expr ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, "", NULL,NULL); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
| yD_FATAL '(' expr ',' str commaEListE ')' { $$ = new AstDisplay($1,AstDisplayType::FATAL, *$5,NULL,$6); $$->addNext(new AstStop($1)); if ($3) $3->deleteTree(); }
//
| yD_READMEMB '(' expr ',' varRefMem ')' { $$ = new AstReadMem($1,false,$3,$5,NULL,NULL); }
| yD_READMEMB '(' expr ',' varRefMem ',' expr ')' { $$ = new AstReadMem($1,false,$3,$5,$7,NULL); }
@@ -1710,8 +1711,8 @@ system_f_call<nodep>: // IEEE: system_tf_call (as func)
| yD_FEOF '(' expr ')' { $$ = new AstFEof($1,$3); }
| yD_FGETC '(' expr ')' { $$ = new AstFGetC($1,$3); }
| yD_FGETS '(' idClassSel ',' expr ')' { $$ = new AstFGetS($1,$3,$5); }
| yD_FSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' yaSTRING commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_FSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstFScanF($1,*$5,$3,$6); }
| yD_SSCANF '(' expr ',' str commaVRDListE ')' { $$ = new AstSScanF($1,*$5,$3,$6); }
| yD_ISUNKNOWN '(' expr ')' { $$ = new AstIsUnknown($1,$3); }
| yD_ONEHOT '(' expr ')' { $$ = new AstOneHot($1,$3); }
| yD_ONEHOT0 '(' expr ')' { $$ = new AstOneHot0($1,$3); }
@@ -2191,7 +2192,7 @@ gatePulldownList<nodep>:
;
gateBuf<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,$6); }
;
gateBufif0<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), $6)); }
@@ -2200,7 +2201,7 @@ gateBufif1<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, $6, new AstConst($3,V3Number($3,"1'bz")))); }
;
gateNot<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
;
gateNotif0<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstConst($3,V3Number($3,"1'bz")), new AstNot($3, $6))); }
@@ -2209,22 +2210,22 @@ gateNotif1<assignwp>:
gateIdE instRangeE '(' idClassSel ',' expr ',' expr ')' { $$ = new AstAssignW ($3,$4,new AstCond($3,$8, new AstNot($3,$6), new AstConst($3,V3Number($3,"1'bz")))); }
;
gateAnd<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
;
gateNand<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateAndPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
;
gateOr<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
;
gateNor<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateOrPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
;
gateXor<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,$6); }
;
gateXnor<assignwp>:
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); $$->allowImplicit(true); }
gateIdE instRangeE '(' idClassSel ',' gateXorPinList ')' { $$ = new AstAssignW ($3,$4,new AstNot($5,$6)); }
;
gatePullup<nodep>:
gateIdE instRangeE '(' idClassSel ')' { $$ = new AstPull ($3, $4, true); }
@@ -2371,6 +2372,11 @@ varRefBase<varrefp>:
id { $$ = new AstVarRef(CRELINE(),*$1,false);}
;
// yaSTRING shouldn't be used directly, instead via an abstraction below
str<strp>: // yaSTRING but with \{escapes} need decoded
yaSTRING { $$ = V3Read::newString(V3Parse::deQuote(CRELINE(),*$1)); }
;
strAsInt<nodep>:
yaSTRING { $$ = new AstConst(CRELINE(),V3Number(V3Number::VerilogString(),CRELINE(),V3Parse::deQuote(CRELINE(),*$1)));}
;
@@ -2592,6 +2598,7 @@ AstVar* V3Parse::createVariable(FileLine* fileline, string name, AstRange* array
string V3Parse::deQuote(FileLine* fileline, string text) {
// Fix up the quoted strings the user put in, for example "\"" becomes "
// Reverse is AstNode::quoteName(...)
bool quoted = false;
string newtext;
unsigned char octal_val = 0;
+105 -23
View File
@@ -13,7 +13,7 @@ BEGIN {
use Getopt::Long;
use IO::File;
use Pod::Usage;
use Data::Dumper;
use Data::Dumper; $Data::Dumper::Sortkeys=1;
use strict;
use vars qw ($Debug %Vars $Driver $Fork);
use POSIX qw(strftime);
@@ -42,33 +42,37 @@ our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^
$Debug = 0;
my $opt_benchmark;
my @opt_tests;
my $opt_nc;
my $opt_vcs;
my $opt_v3;
my $opt_stop;
my $opt_optimize;
my $opt_trace;
my $opt_gdb;
my $opt_gdbbt;
my $opt_iv;
my $opt_jobs = 1;
my $opt_nc;
my $opt_optimize;
my $opt_stop;
my $opt_trace;
my $opt_v3;
my $opt_vcs;
my $opt_verbose;
my $Opt_Verilated_Debug;
our @Opt_Driver_Verilator_Flags;
Getopt::Long::config ("pass_through");
if (! GetOptions (
"help" => \&usage,
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
"debug" => \&debug,
"vcs!" => \$opt_vcs,
"verilated_debug!" => \$Opt_Verilated_Debug,
"j=i" => \$opt_jobs,
"v3!" => \$opt_v3,
"nc!" => \$opt_nc,
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"help" => \&usage,
"iverilog!" => \$opt_iv,
"j=i" => \$opt_jobs,
"nc!" => \$opt_nc,
"optimize:s" => \$opt_optimize,
"stop!" => \$opt_stop,
"trace!" => \$opt_trace,
"v3!" => \$opt_v3,
"vcs!" => \$opt_vcs,
"verbose!" => \$opt_verbose,
"verilated_debug!" => \$Opt_Verilated_Debug,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try '$0 --help'\n";
@@ -78,7 +82,7 @@ $opt_jobs = calc_jobs() if defined $opt_jobs && $opt_jobs==0;
$Fork->max_proc($opt_jobs);
if (!$opt_vcs && !$opt_nc && !$opt_v3) {
if (!$opt_iv && !$opt_vcs && !$opt_nc && !$opt_v3) {
$opt_v3 = 1;
}
@@ -93,8 +97,9 @@ my $okcnt=0; my $failcnt=0;
my @fails;
foreach my $testpl (@opt_tests) {
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
one_test(pl_filename => $testpl, iv=>1) if $opt_iv;
one_test(pl_filename => $testpl, nc=>1) if $opt_nc;
one_test(pl_filename => $testpl, vcs=>1) if $opt_vcs;
one_test(pl_filename => $testpl, 'v3'=>1) if $opt_v3;
}
@@ -243,6 +248,11 @@ sub new {
))],
v_flags2 => [], # Overridden in some sim files
v_other_filenames => [], # After the filename so we can spec multiple files
# IV
iv => 0,
iv_flags => [split(/\s+/,"-o $self->{obj_dir}/simiv")],
iv_flags2 => [], # Overridden in some sim files
ivrun_flags => [],
# VCS
vcs => 0,
vcs_flags => [split(/\s+/,"+cli -I +define+vcs+1 -q -sverilog")],
@@ -267,6 +277,7 @@ sub new {
$self->{mode} ||= "vcs" if $self->{vcs};
$self->{mode} ||= "v3" if $self->{v3};
$self->{mode} ||= "nc" if $self->{nc};
$self->{mode} ||= "iv" if $self->{iv};
$self->{VM_PREFIX} ||= "V".$self->{name};
$self->{stats} ||= "$self->{obj_dir}/V".$self->{name}."__stats.txt";
$self->{status_filename} ||= "$self->{obj_dir}/V".$self->{name}.".status";
@@ -388,10 +399,27 @@ sub compile {
@{$param{v_other_filenames}},
]);
}
if ($param{iv}) {
$self->_make_top();
my @cmd = (($ENV{VERILATOR_IVERILOG}||"iverilog"),
@{$param{iv_flags}},
@{$param{iv_flags2}},
@{$param{v_flags}},
@{$param{v_flags2}},
$param{top_filename},
$param{top_shell_filename},
@{$param{v_other_filenames}});
@cmd = grep { s/\+define\+/-D /g; $_; } @cmd;
$self->_run(logfile=>"$self->{obj_dir}/iv_compile.log",
fails=>$param{fails},
cmd=>\@cmd);
}
if ($param{v3}) {
$opt_gdb="gdbrun" if defined $opt_gdb;
my @verilator_flags = @{$param{verilator_flags}};
unshift @verilator_flags, "--gdb $opt_gdb" if $opt_gdb;
unshift @verilator_flags, "--gdbbt" if $opt_gdbbt;
unshift @verilator_flags, @Opt_Driver_Verilator_Flags;
unshift @verilator_flags, "--x-assign unique"; # More likely to be buggy
unshift @verilator_flags, "--trace" if $opt_trace;
@@ -462,6 +490,13 @@ sub execute {
return 1 if $self->errors;
my %param = (%{$self}, @_); # Default arguments are from $self
$self->oprint("Run\n");
if ($param{iv}) {
$self->_run(logfile=>"$self->{obj_dir}/iv_sim.log",
fails=>$param{fails},
cmd=>["$self->{obj_dir}/simiv",
@{$param{ivrun_flags}},
]);
}
if ($param{nc}) {
$self->_run(logfile=>"$self->{obj_dir}/nc_sim.log",
fails=>$param{fails},
@@ -903,17 +938,59 @@ sub vcd_identical {
my $fn2 = shift;
if (!-r $fn1) { $self->error("File does not exist $fn1\n"); return 0; }
if (!-r $fn2) { $self->error("File does not exist $fn2\n"); return 0; }
my $out = `vcddiff --help`;
if ($out !~ /Usage:/) { $self->skip("No vcddiff installed\n"); return 0; }
$out = `vcddiff "$fn1" "$fn2"`;
if ($out ne '') {
print $out;
$self->error("VCD miscompare $fn1 $fn2\n");
return 0;
{
# vcddiff to check transitions, if installed
my $out = `vcddiff --help`;
if ($out !~ /Usage:/) { $self->skip("No vcddiff installed\n"); return 0; }
my $cmd = qq{vcddiff "$fn1" "$fn2"};
print "\t$cmd\n" if $::Debug;
$out = `$cmd`;
if ($out ne '') {
print $out;
$self->error("VCD miscompare $fn1 $fn2\n");
return 0;
}
}
{
# vcddiff doesn't check module and variable scope, so check that
# Also provides backup if vcddiff not installed
my $h1 = $self->_vcd_read($fn1);
my $h2 = $self->_vcd_read($fn2);
$Data::Dumper::Sortkeys=1;
my $a = Dumper($h1);
my $b = Dumper($h2);
if ($a ne $b) {
print "$a\n$b\n" if $::Debug;
$self->error("VCD hier mismatch $fn1 $fn2\n");
return 0;
}
}
return 1;
}
sub _vcd_read {
my $self = (ref $_[0]? shift : $Self);
my $filename = shift;
my $data = {};
my $fh = IO::File->new ("<$filename");
if (!$fh) { warn "%Error: $! $filename\n"; return $data; }
my @hier = ($data);
while (defined(my $line = $fh->getline)) {
if ($line =~ /\$scope module\s+(\S+)/) {
$hier[$#hier]->{$1} ||= {};
push @hier, $hier[$#hier]->{$1};
} elsif ($line =~ /(\$var \S+\s+\d+\s+)\S+\s+(\S+)/) {
$hier[$#hier]->{$1.$2} ||= 1;
} elsif ($line =~ /\$enddefinitions/) {
last;
}
while ($line =~ s/\$upscope//) {
pop @hier;
}
}
return $data;
}
sub file_grep_not {
my $self = (ref $_[0]? shift : $Self);
my $filename = shift;
@@ -1032,6 +1109,11 @@ specifies the number of simulation cycles (for tests that support it).
Run verilator under the debugger.
=item --gdbbt
Run verilator under the debugger, only to print backtrace information.
Requires --debug.
=item --help
Displays this message and program version and exits.
+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;
+95
View File
@@ -0,0 +1,95 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 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 [2:0] in = (crc[1:0]==0 ? 3'd0
: crc[1:0]==0 ? 3'd1
: crc[1:0]==0 ? 3'd2 : 3'd4);
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [31:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[31:0]),
// Inputs
.clk (clk),
.in (in[2:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {32'h0, 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'h704ca23e2a83e1c5
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
clk, in
);
// Replace this module with the device under test.
//
// Change the code in the t module to apply values to the inputs and
// merge the output values into the result vector.
input clk;
input [2:0] in;
output reg [31:0] out;
localparam ST_0 = 0;
localparam ST_1 = 1;
localparam ST_2 = 2;
always @(posedge clk) begin
case (1'b1) // synopsys parallel_case
in[ST_0]: out <= 32'h1234;
in[ST_1]: out <= 32'h4356;
in[ST_2]: out <= 32'h9874;
default: out <= 32'h1;
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
@@ -3,17 +3,12 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
`include "verilated.v"
module t_case(/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
output passed; reg passed; initial passed = 0;
reg _ranit;
reg rnd;
@@ -111,17 +106,11 @@ module t_case(/*AUTOARG*/
//
if (rnd) begin
// This gets covered
$write("");
end
if (rnd) begin
// This doesn't
// verilator coverage_block_off
$write("");
end
//
$write("[%0t] t_case: Passed\n", $time);
passed <= 1'b1;
$write("*-* All Finished *-*\n");
$finish;
end
end
+9 -2
View File
@@ -12,7 +12,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@@ -26,9 +26,16 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
[0] Embedded
multiline
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;
+3
View File
@@ -37,6 +37,9 @@ module t;
$display("[%0t] %s%s%s", $time,
"hel", "lo, fr", "om a very long string. Percent %s are literally substituted in.");
$write("[%0t] Embedded \r return\n", $time);
$display("[%0t] Embedded\
multiline", $time);
// Str check
`ifndef nc // NC-Verilog 5.3 chokes on this test
+9 -2
View File
@@ -15,7 +15,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@@ -29,9 +29,16 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
[0] Embedded
multiline
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;
Regular → Executable
View File
+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;
+79
View File
@@ -0,0 +1,79 @@
// DESCRIPTION: Verilator: Verilog Test module
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [31:0] in = crc[31:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [31:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[31:0]),
// Inputs
.in (in[31:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {32'h0, 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'h3e3a62edb61f8c7f
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
in
);
input [31:0] in;
output [31:0] out;
genvar i;
generate
for (i=0; i<16; i=i+1) begin : gblk
assign out[i*2+1:i*2] = in[(30-i*2)+1:(30-i*2)];
end
endgenerate
endmodule
View File
+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-IMPLICIT"],
);
execute (
check_finished=>1,
);
ok(1);
1;
+110
View File
@@ -0,0 +1,110 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [31:0] in = crc[31:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [71:0] muxed; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.muxed (muxed[71:0]),
// Inputs
.clk (clk),
.in (in[31:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {muxed[63:0]};
wire [5:0] width_check = cyc[5:0] + 1;
// 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'h20050a66e7b253d1
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
muxed,
// Inputs
clk, in
);
input clk;
input [31:0] in;
output [71:0] muxed;
wire [71:0] a = {in[7:0],~in[31:0],in[31:0]};
wire [71:0] b = {~in[7:0],in[31:0],~in[31:0]};
/*AUTOWIRE*/
Muxer muxer (
.sa (0),
.sb (in[0]),
/*AUTOINST*/
// Outputs
.muxed (muxed[71:0]),
// Inputs
.a (a[71:0]),
.b (b[71:0]));
endmodule
module Muxer (/*AUTOARG*/
// Outputs
muxed,
// Inputs
sa, sb, a, b
);
input sa;
input sb;
output wire [71:0] muxed;
input [71:0] a;
input [71:0] b;
// Constification wasn't sizing with inlining and gave
// unsized error on below
// v
assign muxed = (({72{sa}} & a)
| ({72{sb}} & b));
endmodule
+1 -1
View File
@@ -9,7 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
make_top_shell=>0,
verilator_flags=> [qw(-sp -Wno-WIDTH)],
verilator_flags2 => [qw(-sp -Wno-WIDTH)],
verilator_make_gcc=>0,
);
+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;
+145
View File
@@ -0,0 +1,145 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2004 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
// verilator lint_off WIDTH
//============================================================
reg bad;
initial begin
bad=0;
c96(96'h0_0000_0000_0000_0000, 96'h8_8888_8888_8888_8888, 96'h0_0000_0000_0000_0000, 96'h0);
c96(96'h8_8888_8888_8888_8888, 96'h0_0000_0000_0000_0000, 96'h0_0000_0000_0000_0000, 96'h0);
c96(96'h8_8888_8888_8888_8888, 96'h0_0000_0000_0000_0002, 96'h4_4444_4444_4444_4444, 96'h0);
c96(96'h8_8888_8888_8888_8888, 96'h0_2000_0000_0000_0000, 96'h0_0000_0000_0000_0044, 96'h0_0888_8888_8888_8888);
c96(96'h8_8888_8888_8888_8888, 96'h8_8888_8888_8888_8888, 96'h0_0000_0000_0000_0001, 96'h0);
c96(96'h8_8888_8888_8888_8888, 96'h8_8888_8888_8888_8889, 96'h0_0000_0000_0000_0000, 96'h8_8888_8888_8888_8888);
c96(96'h1_0000_0000_8eba_434a, 96'h0_0000_0000_0000_0001, 96'h1_0000_0000_8eba_434a, 96'h0);
c96(96'h0003, 96'h0002, 96'h0001, 96'h0001);
c96(96'h0003, 96'h0003, 96'h0001, 96'h0000);
c96(96'h0003, 96'h0004, 96'h0000, 96'h0003);
c96(96'h0000, 96'hffff, 96'h0000, 96'h0000);
c96(96'hffff, 96'h0001, 96'hffff, 96'h0000);
c96(96'hffff, 96'hffff, 96'h0001, 96'h0000);
c96(96'hffff, 96'h0003, 96'h5555, 96'h0000);
c96(96'hffff_ffff, 96'h0001, 96'hffff_ffff, 96'h0000);
c96(96'hffff_ffff, 96'hffff, 96'h0001_0001, 96'h0000);
c96(96'hfffe_ffff, 96'hffff, 96'h0000_ffff, 96'hfffe);
c96(96'h1234_5678, 96'h9abc, 96'h0000_1e1e, 96'h2c70);
c96(96'h0000_0000, 96'h0001_0000, 96'h0000, 96'h0000_0000);
c96(96'h0007_0000, 96'h0003_0000, 96'h0002, 96'h0001_0000);
c96(96'h0007_0005, 96'h0003_0000, 96'h0002, 96'h0001_0005);
c96(96'h0006_0000, 96'h0002_0000, 96'h0003, 96'h0000_0000);
c96(96'h8000_0001, 96'h4000_7000, 96'h0001, 96'h3fff_9001);
c96(96'hbcde_789a, 96'hbcde_789a, 96'h0001, 96'h0000_0000);
c96(96'hbcde_789b, 96'hbcde_789a, 96'h0001, 96'h0000_0001);
c96(96'hbcde_7899, 96'hbcde_789a, 96'h0000, 96'hbcde_7899);
c96(96'hffff_ffff, 96'hffff_ffff, 96'h0001, 96'h0000_0000);
c96(96'hffff_ffff, 96'h0001_0000, 96'hffff, 96'h0000_ffff);
c96(96'h0123_4567_89ab, 96'h0001_0000, 96'h0123_4567, 96'h0000_89ab);
c96(96'h8000_fffe_0000, 96'h8000_ffff, 96'h0000_ffff, 96'h7fff_ffff);
c96(96'h8000_0000_0003, 96'h2000_0000_0001, 96'h0003, 96'h2000_0000_0000);
c96(96'hffff_ffff_0000_0000, 96'h0001_0000_0000, 96'hffff_ffff, 96'h0000_0000_0000);
c96(96'hffff_ffff_0000_0000, 96'hffff_0000_0000, 96'h0001_0001, 96'h0000_0000_0000);
c96(96'hfffe_ffff_0000_0000, 96'hffff_0000_0000, 96'h0000_ffff, 96'hfffe_0000_0000);
c96(96'h1234_5678_0000_0000, 96'h9abc_0000_0000, 96'h0000_1e1e, 96'h2c70_0000_0000);
c96(96'h0000_0000_0000_0000, 96'h0001_0000_0000_0000, 96'h0000, 96'h0000_0000_0000_0000);
c96(96'h0007_0000_0000_0000, 96'h0003_0000_0000_0000, 96'h0002, 96'h0001_0000_0000_0000);
c96(96'h0007_0005_0000_0000, 96'h0003_0000_0000_0000, 96'h0002, 96'h0001_0005_0000_0000);
c96(96'h0006_0000_0000_0000, 96'h0002_0000_0000_0000, 96'h0003, 96'h0000_0000_0000_0000);
c96(96'h8000_0001_0000_0000, 96'h4000_7000_0000_0000, 96'h0001, 96'h3fff_9001_0000_0000);
c96(96'hbcde_789a_0000_0000, 96'hbcde_789a_0000_0000, 96'h0001, 96'h0000_0000_0000_0000);
c96(96'hbcde_789b_0000_0000, 96'hbcde_789a_0000_0000, 96'h0001, 96'h0000_0001_0000_0000);
c96(96'hbcde_7899_0000_0000, 96'hbcde_789a_0000_0000, 96'h0000, 96'hbcde_7899_0000_0000);
c96(96'hffff_ffff_0000_0000, 96'hffff_ffff_0000_0000, 96'h0001, 96'h0000_0000_0000_0000);
c96(96'hffff_ffff_0000_0000, 96'h0001_0000_0000_0000, 96'hffff, 96'h0000_ffff_0000_0000);
c96(96'h7fff_8000_0000_0000, 96'h8000_0000_0001, 96'h0000_fffe, 96'h7fff_ffff_0002);
c96(96'h8000_0000_fffe_0000, 96'h8000_0000_ffff, 96'h0000_ffff, 96'h7fff_ffff_ffff);
c96(96'h0008_8888_8888_8888_8888, 96'h0002_0000_0000_0000, 96'h0004_4444, 96'h0000_8888_8888_8888);
if (bad) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
task c96;
input [95:0] u;
input [95:0] v;
input [95:0] expq;
input [95:0] expr;
c96u( u, v, expq, expr);
c96s( u, v, expq, expr);
c96s(-u, v,-expq,-expr);
c96s( u,-v,-expq, expr);
c96s(-u,-v, expq,-expr);
endtask
task c96u;
input [95:0] u;
input [95:0] v;
input [95:0] expq;
input [95:0] expr;
reg [95:0] gotq;
reg [95:0] gotr;
gotq = u/v;
gotr = u%v;
if (gotq != expq && v!=0) begin
bad = 1;
end
if (gotr != expr && v!=0) begin
bad = 1;
end
if (bad
`ifdef TEST_VERBOSE
|| 1
`endif
) begin
$write(" %x /u %x = got %x exp %x %% got %x exp %x", u,v,gotq,expq,gotr,expr);
// Test for v=0 to prevent Xs causing grief
if (gotq != expq && v!=0) $write(" BADQ");
if (gotr != expr && v!=0) $write(" BADR");
$write("\n");
end
endtask
task c96s;
input signed [95:0] u;
input signed [95:0] v;
input signed [95:0] expq;
input signed [95:0] expr;
reg signed [95:0] gotq;
reg signed [95:0] gotr;
gotq = u/v;
gotr = u%v;
if (gotq != expq && v!=0) begin
bad = 1;
end
if (gotr != expr && v!=0) begin
bad = 1;
end
if (bad
`ifdef TEST_VERBOSE
|| 1
`endif
) begin
$write(" %x /s %x = got %x exp %x %% got %x exp %x", u,v,gotq,expq,gotr,expr);
// Test for v=0 to prevent Xs causing grief
if (gotq != expq && v!=0) $write(" BADQ");
if (gotr != expr && v!=0) $write(" BADR");
$write("\n");
end
endtask
endmodule
+9
View File
@@ -273,6 +273,15 @@ module t (/*AUTOARG*/
//============================================================
reg signed [105: 0] W0032 /*verilator public*/; //=106'h3ff0000000100000000bd597bb1
always @(check) begin : Block237
W0032 = 106'sh3ff0000000100000000bd597bb1;
if ((106'sh1ca0000000000000000b96b8dc2 / 106'sh3ff0000000100000000bd597bb1) != 106'sh3fffffffffffffffffffffffe36) if (check) $stop;
if ((106'sh1ca0000000000000000b96b8dc2 / W0032) != 106'sh3fffffffffffffffffffffffe36) if (check) $stop;
end
//============================================================
always @ (posedge clk) begin
if (cyc!=0) begin
cyc <= cyc + 1;
+8 -5
View File
@@ -11,11 +11,14 @@ compile (
fails=>$Self->{v3},
nc=>0, # Need to get it not to give the prompt
expect=>
'%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable already selected, or bad dimension
%Error: Exiting due to.*',
q{%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dimn
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim0
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit or array select; variable already selected, or bad dimension: dim1
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim2
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; can't bit extract from arrayed dimension: dim0nv
.*%Error: t/t_mem_multi_ref_bad.v:\d+: Illegal bit select; variable does not have a bit range, or bad dimension: dim0nv
.*%Error: Exiting due to.*},
);
ok(1);
+4
View File
@@ -4,15 +4,19 @@
// without warranty, 2005 by Wilson Snyder.
module t (/*AUTOARG*/);
reg dimn;
reg [1:0] dim0;
reg [1:0] dim1 [1:0];
reg [1:0] dim2 [1:0][1:0];
reg dim0nv[1:0];
initial begin
dimn[1:0] = 0; // Bad: Not ranged
dim0[1][1] = 0; // Bad: Not arrayed
dim1[1][1][1] = 0; // Bad: Not arrayed to right depth
dim2[1][1][1] = 0; // OK
dim2[0 +: 1][1] = 0; // Bad: Range on non-bits
dim2[1 : 0][1] = 0; // Bad: Range on non-bits
dim2[1][1:0] = 0; // Bad: Bitsel too soon
dim0nv[1:0] = 0; // Bad: Not vectored
dim0nv[1][1] = 0; // Bad: Not arrayed to right depth
-2
View File
@@ -15,8 +15,6 @@ compile (
'%Warning-WIDTHCONCAT: t/t_param_concat.v:\d+: Unsized numbers/parameters not allowed in concatenations.
%Warning-WIDTHCONCAT: Use "/\* verilator lint_off WIDTHCONCAT \*/" and lint_on around source to disable this message.
%Warning-WIDTHCONCAT: t/t_param_concat.v:\d+: Unsized numbers/parameters not allowed in replications.
%Warning-WIDTHCONCAT: t/t_param_concat.v:\d+: Unsized numbers/parameters not allowed in concatenations.
%Warning-WIDTHCONCAT: t/t_param_concat.v:\d+: Unsized numbers/parameters not allowed in replications.
%Error: Exiting due to.*',
);
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+93
View File
@@ -0,0 +1,93 @@
// DESCRIPTION: Verilator: Verilog Test module
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [31:0] in = crc[31:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [31:0] out; // From test of Test.v
// End of automatics
Test #(16,2) test (/*AUTOINST*/
// Outputs
.out (out[31:0]),
// Inputs
.clk (clk),
.in (in[31:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {32'h0, 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'hf9b3a5000165ed38
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
clk, in
);
input clk;
input [31:0] in;
output [31:0] out;
parameter N = 0;
parameter PASSDOWN = 1;
add #(PASSDOWN) add (.in (in[(2*N)-1:(0*N)]),
.out (out));
endmodule
module add (/*AUTOARG*/
// Outputs
out,
// Inputs
in
);
parameter PASSDOWN = 9999;
input [31:0] in;
output [31:0] out;
wire out = in + PASSDOWN;
endmodule
+2 -2
View File
@@ -10,8 +10,8 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
compile (
fails=>1,
expect=>
'%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit range: 0<22
%Error: t/t_select_bad_msb.v:\d+: Unsupported: MSB < LSB of bit extract: 1<4
'%Warning-LITENDIAN: t/t_select_bad_msb.v:\d+: Little bit endian vector: MSB < LSB of bit range: 0:22
.*
%Error: Exiting due to.*',
) if $Self->{v3};
+1 -1
View File
@@ -11,7 +11,7 @@ compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
q{%Error: t/t_select_bad_tri.v:\d+: Selection index is constantly unknown or tristated: lsb=7'bxxxxxxx width=\?32\?sh47
q{%Error: t/t_select_bad_tri.v:\d+: Selection index is constantly unknown or tristated: lsb=7'bxxxxxxx width=32'sh47
%Error: Exiting due to.*},
);
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+92
View File
@@ -0,0 +1,92 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [6:0] mem1d;
reg [6:0] mem2d [5:0];
reg [6:0] mem3d [4:0][5:0];
integer i,j,k;
// Four different test cases for out of bounds
// =
// <=
// Continuous assigns
// Output pin interconnect (also covers cont assigns)
// Each with both bit selects and array selects
initial begin
mem1d[0] = 1'b0;
i=7;
mem1d[i] = 1'b1;
if (mem1d[0] !== 1'b0) $stop;
//
for (i=0; i<8; i=i+1) begin
for (j=0; j<8; j=j+1) begin
for (k=0; k<8; k=k+1) begin
mem1d[k] = k[0];
mem2d[j][k] = j[0]+k[0];
mem3d[i][j][k] = i[0]+j[0]+k[0];
end
end
end
for (i=0; i<5; i=i+1) begin
for (j=0; j<6; j=j+1) begin
for (k=0; k<7; k=k+1) begin
if (mem1d[k] !== k[0]) $stop;
if (mem2d[j][k] !== j[0]+k[0]) $stop;
if (mem3d[i][j][k] !== i[0]+j[0]+k[0]) $stop;
end
end
end
end
integer wi;
wire [31:0] wd = cyc;
reg [31:0] reg2d[6:0];
always @ (posedge clk) reg2d[wi[2:0]] <= wd;
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d reg2d[%0d]=%0x wd=%0x\n",$time, cyc, wi[2:0], reg2d[wi[2:0]], wd);
`endif
cyc <= cyc + 1;
if (cyc<10) begin
wi <= 0;
end
else if (cyc==10) begin
wi <= 1;
end
else if (cyc==11) begin
if (reg2d[0] !== 10) $stop;
wi <= 6;
end
else if (cyc==12) begin
if (reg2d[0] !== 10) $stop;
if (reg2d[1] !== 11) $stop;
wi <= 7; // Will be ignored
end
else if (cyc==13) begin
if (reg2d[0] !== 10) $stop;
if (reg2d[1] !== 11) $stop;
if (reg2d[6] !== 12) $stop;
end
else if (cyc==14) begin
if (reg2d[0] !== 10) $stop;
if (reg2d[1] !== 11) $stop;
if (reg2d[6] !== 12) $stop;
end
else if (cyc==99) begin
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+141
View File
@@ -0,0 +1,141 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [31:0] in = crc[31:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [63:0] out; // From test of Test.v
// End of automatics
wire reset_l = ~(cyc<15);
wire [63:0] d = crc[63:0];
wire [8:0] t_wa = crc[8:0];
wire [8:0] t_addr = {crc[18:17],3'b0,crc[13:10]};
Test test (/*AUTOINST*/
// Outputs
.out (out[63:0]),
// Inputs
.clk (clk),
.reset_l (reset_l),
.t_wa (t_wa[8:0]),
.d (d[63:0]),
.t_addr (t_addr[8: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'h421a41d1541ea652
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
clk, reset_l, t_wa, d, t_addr
);
input clk;
input reset_l;
reg [63:0] m_w0 [47:0];
reg [63:0] m_w1 [23:0];
reg [63:0] m_w2 [23:0];
reg [63:0] m_w3 [23:0];
reg [63:0] m_w4 [23:0];
reg [63:0] m_w5 [23:0];
input [8:0] t_wa;
input [63:0] d;
always @ (posedge clk) begin
if (~reset_l) begin : blk
integer i;
for (i=0; i<48; i=i+1) begin
m_w0[i] <= 64'h0;
end
for (i=0; i<24; i=i+1) begin
m_w1[i] <= 64'h0;
m_w2[i] <= 64'h0;
m_w3[i] <= 64'h0;
m_w4[i] <= 64'h0;
m_w5[i] <= 64'h0;
end
end
else begin
casez (t_wa[8:6])
3'd0: m_w0[t_wa[5:0]] <= d;
3'd1: m_w1[t_wa[4:0]] <= d;
3'd2: m_w2[t_wa[4:0]] <= d;
3'd3: m_w3[t_wa[4:0]] <= d;
3'd4: m_w4[t_wa[4:0]] <= d;
default: m_w5[t_wa[4:0]] <= d;
endcase
end
end
input [8:0] t_addr;
wire [63:0] t_w0 = m_w0[t_addr[5:0]];
wire [63:0] t_w1 = m_w1[t_addr[4:0]];
wire [63:0] t_w2 = m_w2[t_addr[4:0]];
wire [63:0] t_w3 = m_w3[t_addr[4:0]];
wire [63:0] t_w4 = m_w4[t_addr[4:0]];
wire [63:0] t_w5 = m_w5[t_addr[4:0]];
output reg [63:0] out;
always @* begin
casez (t_addr[8:6])
3'd0: out = t_w0;
3'd1: out = t_w1;
3'd2: out = t_w2;
3'd3: out = t_w3;
3'd4: out = t_w4;
default: out = t_w5;
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+74
View File
@@ -0,0 +1,74 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// verilator lint_off LITENDIAN
wire [10:41] sel2 = crc[31:0];
wire [10:100] sel3 = {crc[26:0],crc};
wire out20 = sel2[{1'b0,crc[3:0]} + 11];
wire [3:0] out21 = sel2[13 : 16];
wire [3:0] out22 = sel2[{1'b0,crc[3:0]} + 20 +: 4];
wire [3:0] out23 = sel2[{1'b0,crc[3:0]} + 20 -: 4];
wire out30 = sel3[{2'b0,crc[3:0]} + 11];
wire [3:0] out31 = sel3[13 : 16];
wire [3:0] out32 = sel3[crc[5:0] + 20 +: 4];
wire [3:0] out33 = sel3[crc[5:0] + 20 -: 4];
// Aggregate outputs into a single result vector
wire [63:0] result = {38'h0, out20, out21, out22, out23, out30, out31, out32, out33};
reg [19:50] sel1;
initial begin
// Path clearing
// 122333445
// 826048260
sel1 = 32'h12345678;
if (sel1 != 32'h12345678) $stop;
if (sel1[47 : 50] != 4'h8) $stop;
if (sel1[31 : 34] != 4'h4) $stop;
if (sel1[27 +: 4] != 4'h3) $stop; //==[27:30], in memory as [23:20]
if (sel1[26 -: 4] != 4'h2) $stop; //==[23:26], in memory as [27:24]
end
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] sels=%x,%x,%x,%x %x,%x,%x,%x\n",$time, out20,out21,out22,out23, out30,out31,out32,out33);
$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;
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;
`define EXPECTED_SUM 64'h28bf65439eb12c00
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+17
View File
@@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t;
parameter [ BMSB : BLSB ] B = A[23:20]; // 3
parameter A = 32'h12345678;
parameter BLSB = A[16+:4]; // 4
parameter BMSB = A[7:4]; // 7
initial begin
if (B !== 4'h3) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
endmodule
+18 -1
View File
@@ -9,6 +9,7 @@ module t (
);
neg neg (.clk(CLK));
little little (.clk(CLK));
glbl glbl ();
initial RESET = 1'b1;
@@ -43,5 +44,21 @@ module neg (
i48 <= ~i48;
i128 <= ~i128;
end
endmodule
module little (
input clk
);
// verilator lint_off LITENDIAN
reg [0:7] i8; initial i8 = '0;
reg [1:49] i48; initial i48 = '0;
reg [63:190] i128; initial i128 = '0;
// verilator lint_on LITENDIAN
always @ (posedge clk) begin
i8 <= ~i8;
i48 <= ~i48;
i128 <= ~i128;
end
endmodule
+35 -17
View File
@@ -1,19 +1,25 @@
$version Generated by SpTraceVcd $end
$date Thu Sep 18 07:54:41 2008
$date Sat Sep 26 15:04:50 2009
$end
$timescale 1ns $end
$scope module TOP $end
$var wire 1 , CLK $end
$var wire 1 - RESET $end
$var wire 1 3 CLK $end
$var wire 1 4 RESET $end
$scope module v $end
$var wire 1 , CLK $end
$var wire 1 3 CLK $end
$var wire 1 # RESET $end
$scope module glbl $end
$var wire 1 + GSR $end
$var wire 1 2 GSR $end
$upscope $end
$scope module little $end
$var wire 1 3 clk $end
$var wire 128 . i128 [63:190] $end
$var wire 49 , i48 [1:49] $end
$var wire 8 + i8 [0:7] $end
$upscope $end
$scope module neg $end
$var wire 1 , clk $end
$var wire 1 3 clk $end
$var wire 128 ' i128 [63:-64] $end
$var wire 48 % i48 [-1:-48] $end
$var wire 8 $ i8 [0:-7] $end
@@ -28,44 +34,56 @@ $enddefinitions $end
b00000000 $
b000000000000000000000000000000000000000000000000 %
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
1+
1-
0,
b00000000 +
b0000000000000000000000000000000000000000000000000 ,
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
12
14
03
#1
#2
#3
b11111111 $
b111111111111111111111111111111111111111111111111 %
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
1,
b11111111 +
b1111111111111111111111111111111111111111111111111 ,
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
13
#4
#5
#6
0,
03
#7
0+
02
#8
#9
0#
b00000000 $
b000000000000000000000000000000000000000000000000 %
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
0-
1,
b00000000 +
b0000000000000000000000000000000000000000000000000 ,
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
04
13
#10
#11
#12
0,
03
#13
#14
#15
b11111111 $
b111111111111111111111111111111111111111111111111 %
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
1,
b11111111 +
b1111111111111111111111111111111111111111111111111 ,
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
13
#16
#17
#18
0,
03
#19
#20
+4 -5
View File
@@ -20,10 +20,9 @@ if ($Self->{v3}) {
check_finished=>1,
);
ok(vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out"));
}
else {
ok(1);
vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out");
}
ok(1);
1;
+35 -17
View File
@@ -1,19 +1,25 @@
$version Generated by SpTraceVcd $end
$date Thu Sep 18 07:55:56 2008
$date Sat Sep 26 15:05:35 2009
$end
$timescale 1ns $end
$scope module TOP $end
$var wire 1 + CLK $end
$var wire 1 , RESET $end
$var wire 1 2 CLK $end
$var wire 1 3 RESET $end
$scope module v $end
$var wire 1 + CLK $end
$var wire 1 2 CLK $end
$var wire 1 # RESET $end
$scope module glbl $end
$var wire 1 - GSR $end
$var wire 1 4 GSR $end
$upscope $end
$scope module little $end
$var wire 1 2 clk $end
$var wire 128 . i128 [63:190] $end
$var wire 49 , i48 [1:49] $end
$var wire 8 + i8 [0:7] $end
$upscope $end
$scope module neg $end
$var wire 1 + clk $end
$var wire 1 2 clk $end
$var wire 128 ' i128 [63:-64] $end
$var wire 48 % i48 [-1:-48] $end
$var wire 8 $ i8 [0:-7] $end
@@ -28,44 +34,56 @@ $enddefinitions $end
b00000000 $
b000000000000000000000000000000000000000000000000 %
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
1,
0+
1-
b00000000 +
b0000000000000000000000000000000000000000000000000 ,
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
13
02
14
#1
#2
#3
b11111111 $
b111111111111111111111111111111111111111111111111 %
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
1+
b11111111 +
b1111111111111111111111111111111111111111111111111 ,
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
12
#4
#5
#6
0+
02
#7
0-
04
#8
#9
0#
b00000000 $
b000000000000000000000000000000000000000000000000 %
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 '
0,
1+
b00000000 +
b0000000000000000000000000000000000000000000000000 ,
b00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 .
03
12
#10
#11
#12
0+
02
#13
#14
#15
b11111111 $
b111111111111111111111111111111111111111111111111 %
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 '
1+
b11111111 +
b1111111111111111111111111111111111111111111111111 ,
b11111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 .
12
#16
#17
#18
0+
02
#19
#20
+5 -5
View File
@@ -20,10 +20,10 @@ if ($Self->{v3}) {
check_finished=>1,
);
ok(vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out"));
}
else {
ok(1);
vcd_identical ("$Self->{obj_dir}/simx.vcd",
"t/$Self->{name}.out");
# vcd_identical doesn't detect "$var a.b;" vs "$scope module a; $var b;"
file_grep ("$Self->{obj_dir}/simx.vcd", qr/module glbl/i);
}
ok(1);
1;

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