mirror of
https://github.com/verilator/verilator.git
synced 2026-10-02 16:13:34 +02:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26eb7c9375 | ||
|
|
e4d5367ead | ||
|
|
47b5157f01 | ||
|
|
39444d83c5 | ||
|
|
350028553b | ||
|
|
7392add8e0 | ||
|
|
e14695c96e | ||
|
|
b4d3806f10 | ||
|
|
996afe7d95 | ||
|
|
905cadc00e | ||
|
|
6634751303 | ||
|
|
64b57fa907 | ||
|
|
dd4059beb8 | ||
|
|
fe3b54bc2e | ||
|
|
1b5e1943f5 | ||
|
|
b1e6fe7139 | ||
|
|
92718a819c | ||
|
|
ceb2f6894f | ||
|
|
c42612abac | ||
|
|
7069d7d802 | ||
|
|
9aaa6d5df1 | ||
|
|
3eb155cf2a | ||
|
|
7c8d914711 | ||
|
|
4d1f8bd057 | ||
|
|
b883ce95b2 | ||
|
|
546e7c0c1f | ||
|
|
4f2dc0ecff | ||
|
|
03c5d06107 | ||
|
|
9499047f8e | ||
|
|
db5674cb08 | ||
|
|
66d000f4ba | ||
|
|
2c3c990019 | ||
|
|
807aecdb11 | ||
|
|
ea1b705c1c | ||
|
|
cb8b0d3597 | ||
|
|
7a86514505 |
+165
@@ -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.
|
||||
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -204,6 +204,7 @@ RAW_OBJS = \
|
||||
V3Unknown.o \
|
||||
V3Unroll.o \
|
||||
V3Width.o \
|
||||
V3WidthSel.o \
|
||||
|
||||
# Non-concatable
|
||||
OBJS += \
|
||||
|
||||
+2
-2
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -441,7 +441,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
DelayedVisitor(AstNode* nodep) {
|
||||
DelayedVisitor(AstNetlist* nodep) {
|
||||
m_inDly = false;
|
||||
m_activep=NULL;
|
||||
m_cfuncp=NULL;
|
||||
|
||||
+1
-1
@@ -156,7 +156,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
DepthVisitor(AstNode* nodep) {
|
||||
DepthVisitor(AstNetlist* nodep) {
|
||||
m_modp=NULL;
|
||||
m_funcp=NULL;
|
||||
m_stmtp=NULL;
|
||||
|
||||
@@ -126,7 +126,7 @@ private:
|
||||
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
DepthBlockVisitor(AstNode* nodep) {
|
||||
DepthBlockVisitor(AstNetlist* nodep) {
|
||||
m_modp=NULL;
|
||||
m_depth=0;
|
||||
//
|
||||
|
||||
+7
-9
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -122,7 +122,7 @@ private:
|
||||
}
|
||||
public:
|
||||
// CONSTUCTORS
|
||||
NameVisitor(AstNode* nodep) {
|
||||
NameVisitor(AstNetlist* nodep) {
|
||||
nodep->accept(*this);
|
||||
}
|
||||
virtual ~NameVisitor() {}
|
||||
|
||||
+139
-13
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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++;
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
|
||||
@@ -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
@@ -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()) {
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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,
|
||||
"<>" => \¶meter,
|
||||
)) {
|
||||
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.
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -3,17 +3,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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Regular → Executable
Executable
+19
@@ -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;
|
||||
@@ -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
|
||||
@@ -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,
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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;
|
||||
|
||||
@@ -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,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
|
||||
|
||||
@@ -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.*',
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
@@ -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};
|
||||
|
||||
|
||||
@@ -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.*},
|
||||
);
|
||||
|
||||
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+18
@@ -0,0 +1,18 @@
|
||||
#!/usr/bin/perl
|
||||
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
|
||||
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
|
||||
#
|
||||
# Copyright 2003 by Wilson Snyder. This program is free software; you can
|
||||
# redistribute it and/or modify it under the terms of either the GNU
|
||||
# Lesser General Public License Version 3 or the Perl Artistic License
|
||||
# Version 2.0.
|
||||
|
||||
compile (
|
||||
);
|
||||
|
||||
execute (
|
||||
check_finished=>1,
|
||||
);
|
||||
|
||||
ok(1);
|
||||
1;
|
||||
@@ -0,0 +1,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
|
||||
Executable
+19
@@ -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;
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user