Compare commits

...
89 Commits
Author SHA1 Message Date
Wilson Snyder 26eb7c9375 Remove version (mod) flag from releases 2009-10-26 20:26:28 -04:00
Wilson Snyder e4d5367ead Version bump 2009-10-26 20:19:23 -04:00
Wilson Snyder 47b5157f01 Support division and modulus of > 64 bit vectors. 2009-10-26 20:12:09 -04:00
Wilson Snyder 39444d83c5 Support little endian bit vectors ("reg [0:2] x;"). 2009-10-25 16:53:55 -04:00
Wilson Snyder 350028553b Fix install missing verilatedsc.h 2009-10-23 19:30:44 -04:00
Wilson Snyder 7392add8e0 Add new tests to support for future commit 2009-10-22 22:25:24 -04:00
Wilson Snyder e14695c96e Fix erroring on strings with backslashed newlines, bug168. 2009-10-22 21:46:49 -04:00
Wilson Snyder b4d3806f10 Fix carriage-returns embedded in display formats
Internals: Store all AstDisplay etc strings in un-backslashed raw format.
2009-10-22 21:29:18 -04:00
Wilson Snyder 996afe7d95 Cleanup handling DOS CRs to match preprocessor
Fix missing line number increment for `pragma
2009-10-22 16:51:34 -04:00
Wilson Snyder 905cadc00e License clarification 2009-10-22 15:46:47 -04:00
Wilson Snyder 6634751303 Verilator --version now uses git describe for tag-relative naming 2009-10-21 09:25:52 -04:00
Wilson Snyder 64b57fa907 Internals: Commentary and new select tests for future merge-in. No functional change. 2009-10-15 21:47:15 -04:00
Wilson Snyder dd4059beb8 Internals: Rework V3Param, V3Width and V3Const to return a AstNode* representing
any replacement edit they made to the passed in node.  Assure all callers use it
and/or comment on non-use.  Hopefully no function changed.
2009-10-14 20:13:04 -04:00
Wilson Snyder fe3b54bc2e Have V3Life unlink at end to prevent proposed new-iteration scheme from breaking. 2009-10-14 08:26:30 -04:00
Wilson Snyder 1b5e1943f5 Part of earlier commit; Fix execute permission 2009-10-12 20:53:21 -04:00
Wilson Snyder b1e6fe7139 Fix core dump with SystemVerilog var declarations under unnamed begins. 2009-10-11 20:50:31 -04:00
Wilson Snyder 92718a819c Fix cell port connection to unsized integer causing false width warning. 2009-10-09 22:55:37 -04:00
Wilson Snyder ceb2f6894f Fix writing to out-of-bounds arrays writing element 0. 2009-10-08 20:42:45 -04:00
Wilson Snyder c42612abac Internal: Reconnect complicated pins in V3Tristate before Unknowns. Prep for next change. 2009-10-07 07:54:30 -04:00
Wilson Snyder 7069d7d802 Internals: Remove AstAssignW::allowImplicit - dead code 2009-10-06 21:58:00 -04:00
Wilson Snyder 9aaa6d5df1 Move V3Unknown to after variable names have been begin'ed; in prep for future change 2009-10-06 21:46:24 -04:00
Wilson Snyder 3eb155cf2a V3Unknown: Don't modify tree if SEL out-of-bounds would be constant. Prep for next change. 2009-10-06 17:19:38 -04:00
Wilson Snyder 7c8d914711 V3Number::setZero can be public. No functional change. 2009-10-05 21:09:26 -04:00
Wilson Snyder 4d1f8bd057 Increase default --unroll-stmts 2009-10-05 07:49:02 -04:00
Wilson Snyder b883ce95b2 Add --gdbbt option 2009-10-04 18:04:37 -04:00
Wilson Snyder 546e7c0c1f Internals: iterateAndNext now requires backp to exist, for forward compatibility 2009-10-04 17:01:35 -04:00
Wilson Snyder 4f2dc0ecff Internals: Route abort() through vlabort(). No functional change 2009-10-04 17:01:28 -04:00
Wilson Snyder 03c5d06107 Visitors that just accept netlists should say so. No functional change 2009-10-01 22:33:11 -04:00
Wilson Snyder 9499047f8e Driver.pl support for iv 2009-10-01 22:32:40 -04:00
Wilson Snyder db5674cb08 Fix VCD files showing internal flattened hierarchy, broke in 3.714. 2009-09-26 09:31:50 -04:00
Wilson Snyder 66d000f4ba Repair new AstConst::Unsigned32 constructor 2009-09-26 06:43:06 -04:00
Wilson Snyder 2c3c990019 Move swap to V3Ast, and tell which AstUser*InUse fails assertions 2009-09-23 23:10:46 -04:00
Wilson Snyder 807aecdb11 Use parallel top level make 2009-09-23 23:10:09 -04:00
Wilson Snyder ea1b705c1c Move test_v submodule into t_case_orig. No functional change 2009-09-23 21:04:12 -04:00
Wilson Snyder cb8b0d3597 No need for V3Signed to recurse into generate if. 2009-09-22 18:58:59 -04:00
Wilson Snyder 7a86514505 Rename opRange->opSel to match AstRange. No functional change. 2009-09-20 09:30:39 -04:00
Wilson Snyder 3a0babb47d Version bump 2009-09-18 22:37:53 -04:00
Wilson Snyder b085b34a69 Commentary 2009-09-18 22:35:46 -04:00
Wilson Snyder abc738b6f1 Fix deep defines causing flex scanner overflows. 2009-09-17 22:23:18 -04:00
Wilson Snyder d37cc5a160 Fix preprocessing commas in deep parameterized macros. 2009-09-17 22:00:17 -04:00
Wilson Snyder 1a0de753e9 Don't require SYSTEMPERL_INCLUDE if SYSTEMPERL/src exists. 2009-09-17 21:31:03 -04:00
Wilson Snyder b798f4fe71 Detect selection index unknown instead of internal erroring 2009-09-16 20:52:52 -04:00
Wilson Snyder 0c0a588b55 Support generate for var++, var--, ++var, --var. 2009-09-16 10:32:14 -04:00
Wilson Snyder faa5ef193b Add --bbox-sys option to blackbox $system calls. 2009-09-16 09:28:09 -04:00
Wilson Snyder 4c7b5005a6 Give fatal instead of coredump 2009-09-15 18:11:56 -04:00
Wilson Snyder 9cf61cef9d Fix --error-limit option being ignored. 2009-09-15 18:11:21 -04:00
Wilson Snyder 28c61b548b Commentary, bug108. 2009-09-14 13:36:15 -04:00
Wilson Snyder 0b24e62d43 Fix $display with uppercase %M. 2009-09-11 19:25:42 -04:00
Wilson Snyder b19dd49fc9 Add test forgot to add earlier 2009-09-07 15:56:20 -04:00
Wilson Snyder 91b1e66933 Fix tracing escaped dotted identifiers. 2009-09-07 15:55:54 -04:00
Wilson Snyder eea2712eac Improved warning when "do" used as identifier. 2009-09-07 15:54:12 -04:00
Wilson Snyder b19a4b6956 Version bump 2009-08-04 15:23:23 -04:00
Wilson Snyder a01c995a53 Fix escaped preprocessor identifiers, bug106. 2009-07-31 12:02:43 -04:00
Wilson Snyder 59b491e3a8 Allow renaming C keywords 2009-07-22 15:21:41 -04:00
Wilson Snyder c44febe85e Remove ; from end of some function definitions. No functional change 2009-07-22 14:38:20 -04:00
Wilson Snyder 15b3c9797b Fix constant functions with and begin/end 2009-07-21 14:31:16 -04:00
Wilson Snyder 584cfa4d4a Tests: Convert t_loop into test_regress format 2009-07-21 10:42:10 -04:00
Wilson Snyder b92f57eacb Support constant function calls for parameters - missed adding tests 2009-07-20 15:08:50 -04:00
Wilson Snyder aeeaaa53d4 Support constant function calls for parameters. 2009-07-17 14:13:11 -04:00
Wilson Snyder a532fce0e4 V3Simulate now knows which node causes non-simulatable errors 2009-07-16 15:30:34 -04:00
Wilson Snyder 510fe8e634 Explicitly size all parameters, even if not used for module cells 2009-07-16 14:49:34 -04:00
Wilson Snyder 556d90a1b4 Remove implicit width 1 var creation. No functional change 2009-07-16 14:06:53 -04:00
Wilson Snyder 4dde1ede0e Support SystemVerilog "logic", bug101. 2009-07-16 09:19:15 -04:00
Wilson Snyder 1c833f8a9a Commentary 2009-07-16 08:59:08 -04:00
Wilson Snyder 6a36bd8514 Add env var test 2009-07-15 10:14:10 -04:00
Wilson Snyder 12cb819adc Split V3Simulate out of V3Table - no functional change 2009-07-14 11:24:21 -04:00
Wilson Snyder 0607edd191 Version bump 2009-07-14 08:42:01 -04:00
Wilson Snyder 96c7abdb39 On WIDTH warnings, show variable name causing error. - Missing files 2009-07-09 21:45:12 -04:00
Wilson Snyder 6835aecdce On WIDTH warnings, show variable name causing error. 2009-07-09 17:39:24 -04:00
Wilson Snyder 8174c1ad02 Patching SystemC is no longer required to trace sc_bvs. 2009-07-07 17:51:00 -04:00
Wilson Snyder 6129452681 Makefile: Rebuild only on git head change, not touching a file 2009-06-30 11:56:00 -04:00
Wilson Snyder be1a3f427e Support zero-width constants in concatenations. 2009-06-30 11:54:07 -04:00
Wilson Snyder 18dc947fa9 Part of last commit 2009-06-30 11:29:58 -04:00
Wilson Snyder 348c43de63 Add verilator --pins-uint8 option to use sc_in<uint8_t/uint16_t>. 2009-06-29 09:21:21 -04:00
Wilson Snyder cd9b15b2a6 Commentary 2009-06-26 06:47:48 -04:00
Wilson Snyder 8b20d777b0 Add verilator -V option, to show verbose version. 2009-06-25 19:53:26 -04:00
Wilson Snyder ec0947ef7e Add BLKLOOPINIT error code, and describe --unroll-count. 2009-06-24 17:24:42 -04:00
Wilson Snyder 02e6005fa9 Version bump 2009-06-23 14:09:38 -04:00
Wilson Snyder a32caac3c1 Fix error on case statement with all duplicate items, bug99. 2009-06-22 18:49:20 -04:00
Wilson Snyder 2aa618ce98 Add 'See the manual' to unsupported+internal errors 2009-06-21 19:37:15 -04:00
Wilson Snyder 96b23f6edd Make old site-specific configuration more generic,
set DIRPROJECT_PERL_BOOT to a script for bin/verilator to call to do setup.
2009-06-21 13:17:12 -04:00
Wilson Snyder 02d162858f Fix compiler errors under Fedora release candidate 11. 2009-06-12 09:56:46 -04:00
Wilson Snyder 82844a5591 Driver: Fix preproc running in parallel random fails 2009-06-12 09:50:27 -04:00
Wilson Snyder 46fb5a852f Test Driver: Detect missing system perl 2009-06-12 09:08:46 -04:00
Wilson Snyder 10a3aa18bc Fix compile warning on gcc 3.3.5 2009-06-12 08:31:11 -04:00
Wilson Snyder 3c395c26be Support decimal constants of arbitrary widths. 2009-06-12 08:27:48 -04:00
Wilson Snyder ea78520220 Fix tristates causing "Assigned pin is neither..." 2009-06-09 15:37:52 -04:00
Wilson Snyder 92fbec2294 Commentary 2009-06-08 16:38:09 -04:00
Wilson Snyder b9be4ae4e8 Fix segfault on unrolling for's with bad inits, bug90. 2009-06-08 15:59:33 -04:00
183 changed files with 6096 additions and 1559 deletions
+165
View File
@@ -0,0 +1,165 @@
GNU LESSER GENERAL PUBLIC LICENSE
Version 3, 29 June 2007
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
This version of the GNU Lesser General Public License incorporates
the terms and conditions of version 3 of the GNU General Public
License, supplemented by the additional permissions listed below.
0. Additional Definitions.
As used herein, "this License" refers to version 3 of the GNU Lesser
General Public License, and the "GNU GPL" refers to version 3 of the GNU
General Public License.
"The Library" refers to a covered work governed by this License,
other than an Application or a Combined Work as defined below.
An "Application" is any work that makes use of an interface provided
by the Library, but which is not otherwise based on the Library.
Defining a subclass of a class defined by the Library is deemed a mode
of using an interface provided by the Library.
A "Combined Work" is a work produced by combining or linking an
Application with the Library. The particular version of the Library
with which the Combined Work was made is also called the "Linked
Version".
The "Minimal Corresponding Source" for a Combined Work means the
Corresponding Source for the Combined Work, excluding any source code
for portions of the Combined Work that, considered in isolation, are
based on the Application, and not on the Linked Version.
The "Corresponding Application Code" for a Combined Work means the
object code and/or source code for the Application, including any data
and utility programs needed for reproducing the Combined Work from the
Application, but excluding the System Libraries of the Combined Work.
1. Exception to Section 3 of the GNU GPL.
You may convey a covered work under sections 3 and 4 of this License
without being bound by section 3 of the GNU GPL.
2. Conveying Modified Versions.
If you modify a copy of the Library, and, in your modifications, a
facility refers to a function or data to be supplied by an Application
that uses the facility (other than as an argument passed when the
facility is invoked), then you may convey a copy of the modified
version:
a) under this License, provided that you make a good faith effort to
ensure that, in the event an Application does not supply the
function or data, the facility still operates, and performs
whatever part of its purpose remains meaningful, or
b) under the GNU GPL, with none of the additional permissions of
this License applicable to that copy.
3. Object Code Incorporating Material from Library Header Files.
The object code form of an Application may incorporate material from
a header file that is part of the Library. You may convey such object
code under terms of your choice, provided that, if the incorporated
material is not limited to numerical parameters, data structure
layouts and accessors, or small macros, inline functions and templates
(ten or fewer lines in length), you do both of the following:
a) Give prominent notice with each copy of the object code that the
Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the object code with a copy of the GNU GPL and this license
document.
4. Combined Works.
You may convey a Combined Work under terms of your choice that,
taken together, effectively do not restrict modification of the
portions of the Library contained in the Combined Work and reverse
engineering for debugging such modifications, if you also do each of
the following:
a) Give prominent notice with each copy of the Combined Work that
the Library is used in it and that the Library and its use are
covered by this License.
b) Accompany the Combined Work with a copy of the GNU GPL and this license
document.
c) For a Combined Work that displays copyright notices during
execution, include the copyright notice for the Library among
these notices, as well as a reference directing the user to the
copies of the GNU GPL and this license document.
d) Do one of the following:
0) Convey the Minimal Corresponding Source under the terms of this
License, and the Corresponding Application Code in a form
suitable for, and under terms that permit, the user to
recombine or relink the Application with a modified version of
the Linked Version to produce a modified Combined Work, in the
manner specified by section 6 of the GNU GPL for conveying
Corresponding Source.
1) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (a) uses at run time
a copy of the Library already present on the user's computer
system, and (b) will operate properly with a modified version
of the Library that is interface-compatible with the Linked
Version.
e) Provide Installation Information, but only if you would otherwise
be required to provide such information under section 6 of the
GNU GPL, and only to the extent that such information is
necessary to install and execute a modified version of the
Combined Work produced by recombining or relinking the
Application with a modified version of the Linked Version. (If
you use option 4d0, the Installation Information must accompany
the Minimal Corresponding Source and Corresponding Application
Code. If you use option 4d1, you must provide the Installation
Information in the manner specified by section 6 of the GNU GPL
for conveying Corresponding Source.)
5. Combined Libraries.
You may place library facilities that are a work based on the
Library side by side in a single library together with other library
facilities that are not Applications and are not covered by this
License, and convey such a combined library under terms of your
choice, if you do both of the following:
a) Accompany the combined library with a copy of the same work based
on the Library, uncombined with any other library facilities,
conveyed under the terms of this License.
b) Give prominent notice with the combined library that part of it
is a work based on the Library, and explaining where to find the
accompanying uncombined form of the same work.
6. Revised Versions of the GNU Lesser General Public License.
The Free Software Foundation may publish revised and/or new versions
of the GNU Lesser General Public License from time to time. Such new
versions will be similar in spirit to the present version, but may
differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the
Library as you received it specifies that a certain numbered version
of the GNU Lesser General Public License "or any later version"
applies to it, you have the option of following the terms and
conditions either of that published version or of any later version
published by the Free Software Foundation. If the Library as you
received it does not specify a version number of the GNU Lesser
General Public License, you may choose any version of the GNU Lesser
General Public License ever published by the Free Software Foundation.
If the Library as you received it specifies that a proxy can decide
whether future versions of the GNU Lesser General Public License shall
apply, that proxy's public statement of acceptance of any version is
permanent authorization for you to choose that version for the
Library.
+72
View File
@@ -3,6 +3,78 @@ 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.
** Support generate for var++, var--, ++var, --var.
*** Improved warning when "do" used as identifier.
**** Don't require SYSTEMPERL_INCLUDE if SYSTEMPERL/src exists. [Gary Thomas]
**** Fix deep defines causing flex scanner overflows. [Brad Dobbie]
**** Fix preprocessing commas in deep parameterized macros. [Brad Dobbie]
**** Fix tracing escaped dotted identifiers, bug107.
**** Fix $display with uppercase %M.
**** Fix --error-limit option being ignored.
* Verilator 3.713 2009/08/04
** Support constant function calls for parameters. [many!]
*** Support SystemVerilog "logic", bug101. [by Alex Duller]
*** Name SYMRSVDWORD error, and allow disabling it, bug103. [Gary Thomas]
**** Fix escaped preprocessor identifiers, bug106. [Nimrod Gileadi]
* Verilator 3.712 2009/07/14
** Patching SystemC is no longer required to trace sc_bvs.
*** Support zero-width constants in concatenations. [Jeff Winston]
*** Add verilator --pins-uint8 option to use sc_in<uint8_t/uint16_t>.
*** Add verilator -V option, to show verbose version.
*** On WIDTH warnings, show variable name causing error. [Jeff Winston]
**** Add BLKLOOPINIT error code, and describe --unroll-count. [Jeff Winston]
* Verilator 3.711 2009/06/23
**** Support decimal constants of arbitrary widths. [Mark Marshall]
**** Fix error on case statement with all duplicate items, bug99. [Gary Thomas]
**** Fix segfault on unrolling for's with bad inits, bug90. [Andreas Olofsson]
**** Fix tristates causing "Assigned pin is neither...". [by Lane Brooks]
**** Fix compiler errors under Fedora release candidate 11. [Chitlesh Goorah]
* Verilator 3.710 2009/05/19
** Verilator is now licensed under LGPL v3 and/or Artistic v2.0.
+18 -4
View File
@@ -87,6 +87,9 @@ pkgdatadir = @pkgdatadir@
# Directory in which to install data across multiple architectures
datarootdir = @datarootdir@
# Compile options
CFG_WITH_DEFENV = @CFG_WITH_DEFENV@
#### End of system configuration section. ####
######################################################################
@@ -101,13 +104,13 @@ 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/* \
install-sh configure mkinstalldirs *.texi \
include/verilated.[chv]* \
include/verilatedos.[chv]* \
include/verilated*.[chv]* \
include/*.in \
include/.*ignore \
.*attributes */.*attributes */*/.*attributes \
@@ -132,6 +135,7 @@ INST_PROJ_FILES = \
include/verilated.[chv]* \
include/verilated.mk \
include/verilatedos.[chv]* \
include/verilatedsc.[chv]* \
INST_PROJ_BIN_FILES = \
verilator_bin \
@@ -141,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)
@@ -148,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:
@@ -271,6 +281,10 @@ install-project: dist
rm $(DISTNAME).tgz
install-project-quick:
ifeq ($(CFG_WITH_DEFENV),yes)
@echo "%Error: Reconfigure with './configure --disable-defenv' to avoid hardcoded paths."
false
endif
@echo "Install-project-quick (no strip) to $(DIRPROJECT)"
for p in $(INST_PROJ_FILES) ; do \
$(INST_PROJ_CVS) $$p $(DIRPROJECT)/hw/utils/verilator/$$p; \
+194 -57
View File
@@ -18,9 +18,9 @@ eval 'exec perl -wS $0 ${1+"$@"}'
require 5.006_001;
use warnings;
BEGIN {
if (my $Project=($ENV{DIRPROJECT}||$ENV{PROJECT})) {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require "$Project/hw/utils/perltools/boot.pl";
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
@@ -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));
}
#----------------------------------------------------------------------
@@ -179,6 +189,7 @@ descriptions in the next sections for more information.
--assert Enable all assertions
--autoflush Flush streams after all $displays
--bbox-sys Blackbox unknown $system calls
--bin <filename> Override Verilator binary
--cc Create C++ output
--compiler <compiler-name> Tune for specified C++ compiler
@@ -193,7 +204,7 @@ descriptions in the next sections for more information.
--debugi-<srcfile> <level> Enable debugging a source file at a level
--dump-tree Enable dumping .tree files
-E Preprocess, but do not compile
--error-limit <value> Abort after this number of errors
--error-limit <value> Abort after this number of errors
--exe Link to create executable
-f <file> Parse options from a file
--help Display this help.
@@ -214,6 +225,7 @@ descriptions in the next sections for more information.
--output-split <bytes> Split .cpp files into pieces
--output-split-cfuncs <statements> Split .ccp functions
--pins-bv <bits> Specify types for top level ports
--pins-uint8 Specify types for top level ports
--prefix <topname> Name of top level class
--profile-cfuncs Name functions for profiling
--private Debugging; see docs
@@ -227,10 +239,14 @@ descriptions in the next sections for more information.
--trace-depth <levels> Depth of tracing
-U<var> Undefine preprocessor define
--underline-zero Zero signals with leading _'s
--unroll-count <loops> Tune maximum loop iterations
--unroll-stmts <stmts> Tune maximum loop body size
-V Verbose version and config
-v <filename> Verilog library
-Werror-<message> Convert warning to error
-Wfuture-<message> Disable unknown message warnings
-Wno-<message> Disable warning
-Wno-lint Disable all lint warnings
-x-assign <mode> Initially assign Xs to this value
-y <dir> Directory to search for modules
@@ -267,6 +283,14 @@ After every $display or $fdisplay, flush the output stream. This insures
that messages will appear immediately but may reduce performance. Defaults
off, which will buffer output as provided by the normal C stdio calls.
=item --bbox-sys
Black box any unknown $system task or function calls. System tasks will be
simply NOPed, and system functions will be replaced by unsized zero.
Arguments to such functions will be parsed, but not otherwise checked.
This prevents errors when linting in the presence of company specific PLI
calls.
=item --bin I<filename>
Rarely needed. Override the default filename for Verilator itself. When a
@@ -439,6 +463,9 @@ appropriate `begin_keywords.
Check the files for lint violations only, do not create any other output.
If the design is not to be completely Verilated see also the --bbox-sys
option.
=item --MMD
Enable creation of .d dependency files, used for make dependency detection,
@@ -513,10 +540,16 @@ Backward compatible alias for "--pins-bv 65". Note that's a 65, not a 64.
=item --pins-bv I<width>
Specifies SystemC outputs of greater than or equal to I<width> bits wide
should use sc_bv's instead of uint32/uint64_t's. The default is "--pins-bv
65". Versions before Verilator 3.671 defaulted to "--pins-bv 33". The
more sc_bv is used, the worse for performance.
Specifies SystemC inputs/outputs of greater than or equal to I<width> bits
wide should use sc_bv's instead of uint32/uint64_t's. The default is
"--pins-bv 65". Versions before Verilator 3.671 defaulted to "--pins-bv
33". The more sc_bv is used, the worse for performance.
=item --pins-uint8
Specifies SystemC inputs/outputs that are smaller than the --pins-bv
setting and 8 bits or less should use uint8_t instead of uint32_t.
Likewise pins of width 9-16 will use uint16_t instead of uint32_t.
=item --prefix I<topname>
@@ -602,6 +635,16 @@ zero, as was done in Verilator 2. Default is for all signals including
those with underlines being randomized. This option may be depreciated in
future versions.
=item --unroll-count I<loops>
Rarely needed. Specifies the maximum number of loop iterations that may be
unrolled. See also BLKLOOPINIT warning.
=item --unroll-stmts I<statements>
Rarely needed. Specifies the maximum number of statements in a loop for
that loop to be unrolled. See also BLKLOOPINIT warning.
=item -Werror-I<message>
Convert the specified warning message into a error message. This is
@@ -622,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
@@ -696,6 +739,11 @@ example module I<x> is referenced, look in I<x>.I<ext>.
Undefines the given preprocessor symbol.
=item -V
Shows the verbose version, including configuration information compiled
into Verilator. (Similar to perl -V.)
=item -v I<filename>
Read the filename as a Verilog library. Any modules in the file may be
@@ -828,6 +876,27 @@ Really, you're better off using a Makefile to do all this for you. Then,
when your source changes it will automatically run all of these steps. See
the test_sp directory in the distribution for an example.
=head1 CADENCE NC-SYSTEMC EXECUTION
Similar to compiling Verilated designs with gcc, Verilated designs may be
compiled inside other simulators that support SystemC models. One such
simulator is Cadence's NC-SystemC, part of their Incisive Verification
Suite. (Highly recommended.)
Using the example files above, the following command will build the model
underneath NC:
cd obj_dir
ncsc_run \
sc_main.cpp \
Vour__ALLcls.cpp \
Vour__ALLsup.cpp \
verilated.cpp
For larger designs you'll want to automate this using makefiles, which pull
the names of the .cpp files to compile in from the make variables generated
in obj_dir/Vour_classes.mk.
=head1 BENCHMARKING & OPTIMIZATION
For best performance, run Verilator with the "-O3 -x-assign=fast
@@ -1110,8 +1179,8 @@ including function call-like preprocessor defines.
Verilator supports ==? and !=? operators, $bits, $countones, $error,
$fatal, $info, $isunknown, $onehot, $onehot0, $warning, always_comb,
always_ff, always_latch, do-while, final, priority case/if, and unique
case/if.
always_ff, always_latch, do-while, final, logic, priority case/if, and
unique case/if.
It also supports .name and .* interconnection.
@@ -1578,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
@@ -1596,17 +1659,9 @@ All specify blocks and timing checks are ignored.
=head2 Array Initialization
When initializing an array, you need to use non-delayed assignments. This
is done in the interest of speed; if delayed assignments were used, the
simulator would have to copy large arrays every cycle. (In smaller loops,
loop unrolling allows the delayed assignment to work, though it's a bit
slower than a non-delayed assignment.) Here's an example
always @ (posedge clk)
if (~reset_l) begin
for (i=0; i<`ARRAY_SIZE; i++) begin
array[i] = 0; // Non-delayed for verilator
end
When initializing a large array, you need to use non-delayed assignments.
Verilator will tell you when this needs to be fixed; see the BLKLOOPINIT
error for more information.
=head2 Array Out of Bounds
@@ -1774,6 +1829,25 @@ inside a public task.
Ignoring this warning may make Verilator simulations differ from other
simulators.
=item BLKLOOPINIT
This indicates that the initialization of an array needs to use non-delayed
assignments. This is done in the interest of speed; if delayed assignments
were used, the simulator would have to copy large arrays every cycle. (In
smaller loops, loop unrolling allows the delayed assignment to work, though
it's a bit slower than a non-delayed assignment.) Here's an example
always @ (posedge clk)
if (~reset_l) begin
for (i=0; i<`ARRAY_SIZE; i++) begin
array[i] = 0; // Non-delayed for verilator
end
This message is only seen on large or complicated loops because Verilator
generally unrolls small loops. You may want to try increasing
--unroll-count (and occasionally --unroll-stmts) which will raise the small
loop bar to avoid this error.
=item CASEINCOMPLETE
Warns that inside a case statement there is a stimulus pattern for which
@@ -1808,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.
@@ -1874,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
@@ -1921,6 +2005,13 @@ example:
Ignoring this warning may make Verilator simulations differ from other
simulators.
=item SYMRSVDWORD
Error that a symbol matches a C++ reserved word and using this as a symbol
name would result in odd C compiler errors. You may disable this error
message as you would disable warnings, but the symbol will be renamed by
Verilator to avoid the conflict.
=item TASKNSVAR
Error when a call to a task or function has a output from that task tied to
@@ -2071,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.
@@ -2139,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
@@ -2162,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?
@@ -2197,26 +2294,64 @@ untarred directory.
In your top level C code, call Verilated::traceEverOn(true). Then create a
SpTraceVcdC object, and in your main loop call "trace_object->dump(time)"
every time step, and finally call "trace_object->close()". For an example,
see the call to SpTraceVcdC in the test_c/sim_main.cpp file of the
distribution.
see below and the test_c/sim_main.cpp file of the distribution.
You also need to compile SpTraceVcdC.cpp and add it to your link. This is
done for you if using the Verilator --exe flag.
Note you can also call ->trace on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
#include "SpTraceVcdC.cpp"
...
int main(int argc, char **argv, char **env) {
...
Verilated::traceEverOn(true);
SpTraceVcdCFile* tfp = new SpTraceVcdCFile;
topp->trace (tfp, 99);
tfp->open ("obj_dir/t_trace_ena_cc/simx.vcd");
...
while (sc_time_stamp() < sim_time && !Verilated::gotFinish()) {
main_time += #;
tfp->dump (main_time);
}
tfp->close();
}
=item How do I generate waveforms (traces) in SystemC/SystemPerl?
Add the --trace switch to Verilator, and make sure the SystemPerl package
is installed.
In your top level C sc_main code, call Verilated::traceEverOn(true). Then
create a SpTraceFile object as you would create a normal SystemC trace
file. For an example, see the call to SpTraceFile in the
test_sp/sc_main.cpp file of the distribution.
In your top level C sc_main code, include SpTraceVcd.h. Then call
Verilated::traceEverOn(true). Then create a SpTraceFile object as you
would create a normal SystemC trace file. For an example, see the call to
SpTraceFile in the test_sp/sc_main.cpp file of the distribution, and below.
Alternatively you may use the C++ trace mechanism described in the previous
question, however the timescale and timeprecision will not inherited from
your SystemC settings.
You'll then need to compile in Sp.cpp, which includes SpTraceVcd.cpp among
other things.
Note you can also call ->trace on multiple Verilated objects with the same
trace file if you want all data to land in the same output file.
#include "SpTraceVcd.cpp"
...
int main(int argc, char **argv, char **env) {
...
Verilated::traceEverOn(true);
SpTraceFile* tfp = new SpTraceFile;
topp->trace (tfp, 99);
tfp->open ("obj_dir/t_trace_ena_cc/simx.vcd");
...
sc_start(1);
...
tfp->close();
}
=item How do I view waveforms (traces)?
Verilator makes standard VCD (Value Change Dump) files. They are viewable
@@ -2523,6 +2658,8 @@ License Version 2.0.
=head1 AUTHORS
When possible, please instead report bugs to L<http://www.veripool.org/>.
Wilson Snyder <[email protected]>
Major concepts by Paul Wasson and Duane Galbi.
+111
View File
@@ -136,6 +136,117 @@ WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp) {
return outwp;
}
//===========================================================================
// Slow math
WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus) {
// See Knuth Algorithm D. Computes u/v = q.r
// This isn't massively tuned, as wide division is rare
// for debug see V3Number version
// Requires clean input
int words = VL_WORDS_I(lbits);
for (int i=0; i<words; i++) owp[i]=0;
// Find MSB and check for zero.
int umsbp1 = VL_MOSTSETBITP1_W(words,lwp); // dividend
int vmsbp1 = VL_MOSTSETBITP1_W(words,rwp); // divisor
if (VL_UNLIKELY(vmsbp1==0) // rwp==0 so division by zero. Return 0.
|| VL_UNLIKELY(umsbp1==0)) { // 0/x so short circuit and return 0
return owp;
}
int uw = VL_WORDS_I(umsbp1); // aka "m" in the algorithm
int vw = VL_WORDS_I(vmsbp1); // aka "n" in the algorithm
if (vw == 1) { // Single divisor word breaks rest of algorithm
vluint64_t k = 0;
for (int j = uw-1; j >= 0; j--) {
vluint64_t unw64 = ((k<<VL_ULL(32)) + (vluint64_t)(lwp[j]));
owp[j] = unw64 / (vluint64_t)(rwp[0]);
k = unw64 - (vluint64_t)(owp[j])*(vluint64_t)(rwp[0]);
}
if (is_modulus) {
owp[0] = k;
for (int i=1; i<words; i++) owp[i]=0;
}
return owp;
}
// +1 word as we may shift during normalization
uint32_t un[VL_MULS_MAX_WORDS+1]; // Fixed size, as MSVC++ doesn't allow [words] here
uint32_t vn[VL_MULS_MAX_WORDS+1]; // v normalized
// Zero for ease of debugging and to save having to zero for shifts
for (int i=0; i<words; i++) { un[i]=vn[i]=0; }
// Algorithm requires divisor MSB to be set
// Copy and shift to normalize divisor so MSB of vn[vw-1] is set
int s = 31-VL_BITBIT_I(vmsbp1-1); // shift amount (0...31)
uint32_t shift_mask = s ? 0xffffffff : 0; // otherwise >> 32 won't mask the value
for (int i = vw-1; i>0; i--) {
vn[i] = (rwp[i] << s) | (shift_mask & (rwp[i-1] >> (32-s)));
}
vn[0] = rwp[0] << s;
// Copy and shift dividend by same amount; may set new upper word
if (s) un[uw] = lwp[uw-1] >> (32-s);
else un[uw] = 0;
for (int i=uw-1; i>0; i--) {
un[i] = (lwp[i] << s) | (shift_mask & (lwp[i-1] >> (32-s)));
}
un[0] = lwp[0] << s;
// Main loop
for (int j = uw - vw; j >= 0; j--) {
// Estimate
vluint64_t unw64 = ((vluint64_t)(un[j+vw])<<VL_ULL(32) | (vluint64_t)(un[j+vw-1]));
vluint64_t qhat = unw64 / (vluint64_t)(vn[vw-1]);
vluint64_t rhat = unw64 - qhat*(vluint64_t)(vn[vw-1]);
again:
if (qhat >= VL_ULL(0x100000000)
|| ((qhat*vn[vw-2]) > ((rhat<<VL_ULL(32)) + un[j+vw-2]))) {
qhat = qhat - 1;
rhat = rhat + vn[vw-1];
if (rhat < VL_ULL(0x100000000)) goto again;
}
vlsint64_t t = 0; // Must be signed
vluint64_t k = 0;
for (int i=0; i<vw; i++) {
vluint64_t p = qhat*vn[i]; // Multiply by estimate
t = un[i+j] - k - (p & VL_ULL(0xFFFFFFFF)); // Subtract
un[i+j] = t;
k = (p >> VL_ULL(32)) - (t >> VL_ULL(32));
}
t = un[j+vw] - k;
un[j+vw] = t;
owp[j] = qhat; // Save quotient digit
if (t < 0) {
// Over subtracted; correct by adding back
owp[j]--;
k = 0;
for (int i=0; i<vw; i++) {
t = (vluint64_t)(un[i+j]) + (vluint64_t)(vn[i]) + k;
un[i+j] = t;
k = t >> VL_ULL(32);
}
un[j+vw] = un[j+vw] + k;
}
}
if (is_modulus) { // modulus
// Need to reverse normalization on copy to output
for (int i=0; i<vw; i++) {
owp[i] = (un[i] >> s) | (shift_mask & (un[i+1] << (32-s)));
}
for (int i=vw; i<words; i++) owp[i] = 0;
return owp;
} else { // division
return owp;
}
}
//===========================================================================
// Formatting
+74 -9
View File
@@ -192,6 +192,9 @@ extern QData VL_RAND_RESET_Q(int obits); ///< Random reset a signal
extern WDataOutP VL_RAND_RESET_W(int obits, WDataOutP outwp); ///< Random reset a signal
extern WDataOutP VL_ZERO_RESET_W(int obits, WDataOutP outwp); ///< Zero reset a signal
/// Math
extern WDataOutP _vl_moddiv_w(int lbits, WDataOutP owp, WDataInP lwp, WDataInP rwp, bool is_modulus);
/// File I/O
extern IData VL_FGETS_IXQ(int sbits, void* strgp, QData fpq);
@@ -228,6 +231,7 @@ extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
#define VL_SET_WQ(owp,data) { owp[0]=(data); owp[1]=((data)>>VL_WORDSIZE); }
#define VL_SET_WI(owp,data) { owp[0]=(data); owp[1]=0; }
#define VL_SET_QW(lwp) ( ((QData)(lwp[0])) | ((QData)(lwp[1])<<((QData)(VL_WORDSIZE)) ))
#define _VL_SET_QII(ld,rd) ( ((QData)(ld)<<VL_ULL(32)) | (QData)(rd) )
// Use a union to avoid cast-to-different-size warnings
/// Return FILE* from QData
@@ -302,6 +306,11 @@ extern double sc_time_stamp();
// EMIT_RULE: VL_ASSIGNCLEAN: oclean=clean; obits==lbits;
#define VL_ASSIGNCLEAN_W(obits,owp,lwp) VL_CLEAN_WW(obits,obits,owp,lwp)
static inline WDataOutP _VL_CLEAN_INPLACE_W(int obits, WDataOutP owp) {
int words = VL_WORDS_I(obits);
owp[words-1] &= VL_MASK_I(obits);
return(owp);
}
static inline WDataOutP VL_CLEAN_WW(int obits, int, WDataOutP owp, WDataInP lwp){
int words = VL_WORDS_I(obits);
for (int i=0; (i < (words-1)); i++) owp[i] = lwp[i];
@@ -609,7 +618,7 @@ static inline IData VL_CLOG2_Q(QData lhs) {
static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
IData adjust = (VL_COUNTONES_W(words,lwp)==1) ? 0 : 1;
for (int i=words-1; i>=0; i--) {
if (lwp[i]) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + adjust;
@@ -621,6 +630,21 @@ static inline IData VL_CLOG2_W(int words, WDataInP lwp) {
return 0;
}
static inline IData VL_MOSTSETBITP1_W(int words, WDataInP lwp) {
// MSB set bit plus one; similar to FLS. 0=value is zero
for (int i=words-1; i>=0; i--) {
if (VL_UNLIKELY(lwp[i])) { // Shorter worst case if predict not taken
for (int bit=31; bit>=0; bit--) {
if (VL_UNLIKELY(VL_BITISSET_I(lwp[i],bit))) {
return i*VL_WORDSIZE + bit + 1;
}
}
// Can't get here - one bit must be set
}
}
return 0;
}
//===================================================================
// SIMPLE LOGICAL OPERATORS
@@ -759,10 +783,12 @@ static inline int _VL_CMPS_W(int lbits, WDataInP lwp, WDataInP rwp) {
// EMIT_RULE: VL_MUL: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_DIV: oclean=dirty; lclean==clean; rclean==clean;
// EMIT_RULE: VL_MODDIV: oclean=dirty; lclean==clean; rclean==clean;
#define VL_DIV_I(lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_Q(lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_MODDIV_I(lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_Q(lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_DIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)/(rhs))
#define VL_DIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,0))
#define VL_MODDIV_III(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_QQQ(lbits,lhs,rhs) (((rhs)==0)?0:(lhs)%(rhs))
#define VL_MODDIV_WWW(lbits,owp,lwp,rwp) (_vl_moddiv_w(lbits,owp,lwp,rwp,1))
static inline WDataOutP VL_ADD_W(int words, WDataOutP owp,WDataInP lwp,WDataInP rwp){
QData carry = 0;
@@ -866,31 +892,70 @@ static inline WDataOutP VL_MULS_WWW(int,int lbits,int, WDataOutP owp,WDataInP lw
return(owp);
}
static inline IData VL_DIVS_III(int,int lbits,int, IData lhs,IData rhs) {
static inline IData VL_DIVS_III(int lbits, IData lhs,IData rhs) {
if (rhs==0) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline QData VL_DIVS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
static inline QData VL_DIVS_QQQ(int lbits, QData lhs,QData rhs) {
if (rhs==0) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed / rhs_signed;
}
static inline IData VL_MODDIVS_III(int,int lbits,int, IData lhs,IData rhs) {
static inline IData VL_MODDIVS_III(int lbits, IData lhs,IData rhs) {
if (rhs==0) return 0;
vlsint32_t lhs_signed = VL_EXTENDS_II(32, lbits, lhs);
vlsint32_t rhs_signed = VL_EXTENDS_II(32, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline QData VL_MODDIVS_QQQ(int,int lbits,int, QData lhs,QData rhs) {
static inline QData VL_MODDIVS_QQQ(int lbits, QData lhs,QData rhs) {
if (rhs==0) return 0;
vlsint64_t lhs_signed = VL_EXTENDS_QQ(64, lbits, lhs);
vlsint64_t rhs_signed = VL_EXTENDS_QQ(64, lbits, rhs);
return lhs_signed % rhs_signed;
}
static inline WDataOutP VL_DIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataInP rwp) {
int words = VL_WORDS_I(lbits);
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if ((lsign && !rsign) || (!lsign && rsign)) {
IData qNoSign[VL_MULS_MAX_WORDS];
VL_DIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp;
} else {
return VL_DIV_WWW(lbits,owp,ltup,rtup);
}
}
static inline WDataOutP VL_MODDIVS_WWW(int lbits, WDataOutP owp,WDataInP lwp,WDataInP rwp) {
int words = VL_WORDS_I(lbits);
IData lsign = VL_SIGN_I(lbits,lwp[words-1]);
IData rsign = VL_SIGN_I(lbits,rwp[words-1]);
IData lwstore[VL_MULS_MAX_WORDS]; // Fixed size, as MSVC++ doesn't allow [words] here
IData rwstore[VL_MULS_MAX_WORDS];
WDataInP ltup = lwp;
WDataInP rtup = rwp;
if (lsign) { ltup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), lwstore, lwp)); }
if (rsign) { rtup = _VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), rwstore, rwp)); }
if (lsign) { // Only dividend sign matters for modulus
IData qNoSign[VL_MULS_MAX_WORDS];
VL_MODDIV_WWW(lbits,qNoSign,ltup,rtup);
_VL_CLEAN_INPLACE_W(lbits, VL_UNARYMIN_W(VL_WORDS_I(lbits), owp, qNoSign));
return owp;
} else {
return VL_MODDIV_WWW(lbits,owp,ltup,rtup);
}
}
static inline IData VL_POW_III(int, int, int rbits, IData lhs, IData rhs) {
if (lhs==0) return 0;
IData power = lhs;
+51
View File
@@ -0,0 +1,51 @@
// -*- C++ -*-
//*************************************************************************
//
// Copyright 2009-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.
//
//*************************************************************************
///
/// \file
/// \brief Verilator: Common include for all Verilated SystemC files
///
/// This file is included automatically by Verilator at the top of
/// all SystemC files it generates.
///
/// Code available from: http://www.veripool.org/verilator
///
//*************************************************************************
#ifndef _VERILATEDSC_H_
#define _VERILATEDSC_H_ 1 ///< Header Guard
#include "verilatedos.h"
#include "systemc.h"
//=============================================================================
// VL_SC_BV_DATAP
// We want to get a pointer to m_data in the sc_bv_base class,
// but it is protected. So make an exposing class, then use
// cast magic to get at it. Saves patching get_datap in SystemC.
#define VL_SC_BV_DATAP(bv) (VlScBvExposer::sp_datap(bv))
class VlScBvExposer : public sc_bv_base {
public:
static uint32_t* sp_datap(const sc_bv_base& base) {
return static_cast<const VlScBvExposer*>(&base)->sp_datatp(); }
uint32_t* sp_datatp() const { return (uint32_t*)(m_data); }
// Above reads this protected element in sc_bv_base:
// sc_digit* m_data; // data array
};
//=========================================================================
#endif // guard
+4 -5
View File
@@ -29,9 +29,9 @@ This is the Verilator Package.
This package is Copyright 2003-2009 by Wilson Snyder @email{wsnyder@@wsnyder.org}.
Verilator is free software; you can redistribute it and/or modify it
under the terms of either the GNU General Public License Version 3 or
the Perl Artistic License Version 2.0. (See the documentation for
more details.)
under the terms of either the GNU Lesser General Public License
Version 3 or the Perl Artistic License Version 2.0. (See the
documentation for more details.)
This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -121,8 +121,7 @@ If you will be using SystemC, download and install System-Perl,
@url{http://search.cpan.org/search?module=SystemC::Netlist}. Note
you'll need to set a @samp{SYSTEMPERL} environment variable to point
to the downloaded kit. Optionally also set @samp{SYSTEMPERL_INCLUDE}
to point to the installed headers. Also, make sure to do a @code{make
sc_patch}.
to point to the installed headers.
@item
@code{cd} to the Verilator directory containing this README.
+2 -2
View File
@@ -47,7 +47,7 @@ export OBJCACHE_JOBS := -j $(shell objcache --jobs "$(OBJCACHE_HOSTS)")
export OBJCACHE := @objcache --read --write
endif
UNDER_GIT = $(wildcard ../.git)
UNDER_GIT = $(wildcard ../.git/logs/HEAD)
#*********************************************************************
@@ -79,7 +79,7 @@ prefiles::
ifneq ($(UNDER_GIT),) # If local git tree... Else don't burden users
prefiles:: config_rev.h
# This output goes into srcdir, as we need to distribute it as part of the kit.
config_rev.h: config_rev.pl ../.git/index
config_rev.h: config_rev.pl ../.git/logs/HEAD
$(PERL) config_rev.pl . >$@
endif
+3 -2
View File
@@ -204,6 +204,7 @@ RAW_OBJS = \
V3Unknown.o \
V3Unroll.o \
V3Width.o \
V3WidthSel.o \
# Non-concatable
OBJS += \
@@ -228,8 +229,8 @@ $(TGT): V3Ast__gen_classes.h $(OBJS)
@echo " Linking $@..."
-rm -rf $@ [email protected]
${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
@-cp [email protected] $@
# ok if cp failes on linux, it's there to insure make works on NT
@-(cp [email protected] $@ || true)
# ok if cp failes on linux, it's there to insure executable works on NT
V3Number_test: V3Number_test.o
${LINK} ${LDFLAGS} -o $@ $^ ${LIBS}
+2 -2
View File
@@ -84,7 +84,7 @@ private:
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
// Simplify sensitivity list
V3Const::constifyTreeExpensive(nodep);
V3Const::constifyExpensiveEdit(nodep); nodep=NULL;
}
// Empty visitors, speed things up
virtual void visit(AstNodeStmt* nodep, AstNUser*) { }
@@ -364,7 +364,7 @@ private:
}
public:
// CONSTUCTORS
ActiveVisitor(AstNode* nodep) {
ActiveVisitor(AstNetlist* nodep) {
m_scopeFinalp = NULL;
m_alwaysp = NULL;
m_itemCombo = false;
+1 -1
View File
@@ -80,9 +80,9 @@ private:
}
virtual void visit(AstActive* nodep, AstNUser*) {
UINFO(4," ACTIVE "<<nodep<<endl);
V3Const::constifyExpensiveEdit(nodep); // Remove duplicate clocks and such; sensesp() may change!
AstSenTree* sensesp = nodep->sensesp();
if (!sensesp) nodep->v3fatalSrc("NULL");
V3Const::constifyTreeExpensive(nodep); // Remove duplicate clocks and such
if (sensesp->sensesp()
&& sensesp->sensesp()->castSenItem()
&& sensesp->sensesp()->castSenItem()->isNever()) {
+3 -1
View File
@@ -65,7 +65,9 @@ private:
AstNode* timesp = nodep->exprsp(); if (timesp) timesp->unlinkFrBack();
timesp = timesp->addNext(new AstTime(nodep->fileline()));
nodep->exprsp(timesp);
if (!nodep->scopeNamep() && nodep->name().find("%m") != string::npos) {
if (!nodep->scopeNamep()
&& (nodep->name().find("%m") != string::npos
|| nodep->name().find("%M") != string::npos)) {
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
}
}
+106 -3
View File
@@ -33,8 +33,8 @@
//======================================================================
// Statics
vluint64_t AstNode::s_editCntGbl=0;
vluint64_t AstNode::s_editCntLast=0;
vluint64_t AstNode::s_editCntGbl=0; // Hot cache line
// To allow for fast clearing of all user pointers, we keep a "timestamp"
// along with each userp, and thus by bumping this count we can make it look
@@ -139,6 +139,21 @@ string AstNode::dedotName(const string& namein) {
return pretty;
}
string AstNode::vcdName(const string& namein) {
// VCD tracing expects space to separate hiearchy
// Dots are reserved for dots the user put in the name
string pretty = namein;
string::size_type pos;
while ((pos=pretty.find("__DOT__")) != string::npos) {
pretty.replace(pos, 7, " ");
}
while ((pos=pretty.find(".")) != string::npos) {
pretty.replace(pos, 1, " ");
}
// Now convert escaped special characters, etc
return prettyName(pretty);
}
string AstNode::prettyName(const string& namein) {
string pretty;
pretty = "";
@@ -176,6 +191,36 @@ string AstNode::prettyName(const string& namein) {
return pretty;
}
string AstNode::prettyTypeName() const {
if (name()=="") return typeName();
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();
@@ -554,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
@@ -691,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;
@@ -699,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;
@@ -737,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() {
@@ -917,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) {
+92 -77
View File
@@ -41,10 +41,10 @@ public:
// enum en {...};
// const char* ascii() const {...};
enum en m_e;
inline AstType () {};
inline AstType (en _e) : m_e(_e) {};
explicit inline AstType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstType () {}
inline AstType (en _e) : m_e(_e) {}
explicit inline AstType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (AstType lhs, AstType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstType lhs, AstType::en rhs) { return (lhs.m_e == rhs); }
@@ -64,10 +64,10 @@ public:
PUBLIC_TASK
};
enum en m_e;
inline AstPragmaType () {};
inline AstPragmaType (en _e) : m_e(_e) {};
explicit inline AstPragmaType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstPragmaType () {}
inline AstPragmaType (en _e) : m_e(_e) {}
explicit inline AstPragmaType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (AstPragmaType lhs, AstPragmaType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstPragmaType lhs, AstPragmaType::en rhs) { return (lhs.m_e == rhs); }
@@ -87,10 +87,10 @@ public:
TRACE_CHANGE_SUB
};
enum en m_e;
inline AstCFuncType () {};
inline AstCFuncType (en _e) : m_e(_e) {};
explicit inline AstCFuncType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstCFuncType () {}
inline AstCFuncType (en _e) : m_e(_e) {}
explicit inline AstCFuncType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
// METHODS
bool isTrace() const { return (m_e==TRACE_INIT || m_e==TRACE_INIT_SUB
|| m_e==TRACE_FULL || m_e==TRACE_FULL_SUB
@@ -155,10 +155,10 @@ public:
};
return names[m_e];
};
inline AstEdgeType () {};
inline AstEdgeType (en _e) : m_e(_e) {};
explicit inline AstEdgeType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstEdgeType () {}
inline AstEdgeType (en _e) : m_e(_e) {}
explicit inline AstEdgeType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (AstEdgeType lhs, AstEdgeType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstEdgeType lhs, AstEdgeType::en rhs) { return (lhs.m_e == rhs); }
@@ -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,16 +181,16 @@ 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"
};
return names[m_e];
};
inline AstAttrType () {};
inline AstAttrType (en _e) : m_e(_e) {};
explicit inline AstAttrType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstAttrType () {}
inline AstAttrType (en _e) : m_e(_e) {}
explicit inline AstAttrType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (AstAttrType lhs, AstAttrType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstAttrType lhs, AstAttrType::en rhs) { return (lhs.m_e == rhs); }
@@ -223,17 +222,17 @@ public:
XTEMP
};
enum en m_e;
inline AstVarType () {};
inline AstVarType (en _e) : m_e(_e) {};
explicit inline AstVarType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstVarType () {}
inline AstVarType (en _e) : m_e(_e) {}
explicit inline AstVarType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
const char* ascii() const {
static const char* names[] = {
"?","GPARAM","LPARAM","GENVAR",
"INTEGER","INPUT","OUTPUT","INOUT",
"SUPPLY0","SUPPLY1","WIRE","IMPLICIT","REG","TRIWIRE","PORT",
"BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"};
return names[m_e];};
return names[m_e]; }
};
inline bool operator== (AstVarType lhs, AstVarType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstVarType lhs, AstVarType::en rhs) { return (lhs.m_e == rhs); }
@@ -252,10 +251,10 @@ public:
};
enum en m_e;
// CONSTRUCTOR - note defaults to *UNKNOWN*
inline AstBranchPred () : m_e(UNKNOWN) {};
inline AstBranchPred (en _e) : m_e(_e) {};
explicit inline AstBranchPred (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstBranchPred () : m_e(UNKNOWN) {}
inline AstBranchPred (en _e) : m_e(_e) {}
explicit inline AstBranchPred (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
AstBranchPred invert() const {
if (m_e==UNLIKELY) return LIKELY;
else if (m_e==LIKELY) return UNLIKELY;
@@ -264,7 +263,7 @@ public:
const char* ascii() const {
static const char* names[] = {
"","VL_LIKELY","VL_UNLIKELY"};
return names[m_e];};
return names[m_e]; }
};
inline bool operator== (AstBranchPred lhs, AstBranchPred rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstBranchPred lhs, AstBranchPred::en rhs) { return (lhs.m_e == rhs); }
@@ -281,10 +280,10 @@ public:
CASEZ
};
enum en m_e;
inline AstCaseType () {};
inline AstCaseType (en _e) : m_e(_e) {};
explicit inline AstCaseType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstCaseType () {}
inline AstCaseType (en _e) : m_e(_e) {}
explicit inline AstCaseType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (AstCaseType lhs, AstCaseType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstCaseType lhs, AstCaseType::en rhs) { return (lhs.m_e == rhs); }
@@ -303,16 +302,16 @@ public:
FATAL
};
enum en m_e;
inline AstDisplayType () {};
inline AstDisplayType (en _e) : m_e(_e) {};
explicit inline AstDisplayType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstDisplayType () {}
inline AstDisplayType (en _e) : m_e(_e) {}
explicit inline AstDisplayType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
bool addNewline() const { return m_e!=WRITE; }
bool needScopeTracking() const { return m_e!=DISPLAY && m_e!=WRITE; }
const char* ascii() const {
static const char* names[] = {
"display","write","info","error","warning","fatal"};
return names[m_e];};
return names[m_e]; }
};
inline bool operator== (AstDisplayType lhs, AstDisplayType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstDisplayType lhs, AstDisplayType::en rhs) { return (lhs.m_e == rhs); }
@@ -331,14 +330,14 @@ public:
_ENUM_END
};
enum en m_e;
inline AstParseRefExp() : m_e(NONE) {};
inline AstParseRefExp (en _e) : m_e(_e) {};
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline AstParseRefExp() : m_e(NONE) {}
inline AstParseRefExp (en _e) : m_e(_e) {}
explicit inline AstParseRefExp (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
const char* ascii() const {
static const char* names[] = {
"","VAR_MEM","VAR_ANY","TASK","FUNC"};
return names[m_e];};
return names[m_e]; }
};
inline bool operator== (AstParseRefExp lhs, AstParseRefExp rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (AstParseRefExp lhs, AstParseRefExp::en rhs) { return (lhs.m_e == rhs); }
@@ -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*/); }
};
//######################################################################
@@ -520,9 +519,9 @@ public:
uint32_t depth() const { return (m_both >> 24) & 255; }
uint32_t hshval() const { return m_both & M24; }
// OPERATORS
inline bool operator== (const V3Hash& rh) const { return m_both==rh.m_both; };
inline bool operator!= (const V3Hash& rh) const { return m_both!=rh.m_both; };
inline bool operator< (const V3Hash& rh) const { return m_both<rh.m_both; };
inline bool operator== (const V3Hash& rh) const { return m_both==rh.m_both; }
inline bool operator!= (const V3Hash& rh) const { return m_both!=rh.m_both; }
inline bool operator< (const V3Hash& rh) const { return m_both<rh.m_both; }
// CREATORS
class Illegal {}; // for creator type-overload selection
class FullValue {}; // for creator type-overload selection
@@ -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
@@ -640,7 +641,7 @@ protected:
public:
// ACCESSORS
virtual AstType type() const = 0;
const char* typeName() const { return type().ascii(); }
const char* typeName() const { return type().ascii(); } // See also prettyTypeName
AstNode* nextp() const { return m_nextp; }
AstNode* backp() const { return m_backp; }
AstNode* op1p() const { return m_op1p; }
@@ -669,13 +670,17 @@ public:
// ACCESSORS
virtual string name() const { return ""; }
virtual void name(const string& name) { this->v3fatalSrc("name() called on object without name() method"); }
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; }
int width() const { return m_width; }
bool width1() const { return width()==1; }
@@ -728,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(); }
@@ -745,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);
@@ -783,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; }
@@ -930,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; }
@@ -946,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 {
@@ -979,7 +995,6 @@ struct AstNodeFor : public AstNodeStmt {
AstNode* incsp() const { return op3p()->castNode(); } // op3= increment statements
AstNode* bodysp() const { return op4p()->castNode(); } // op4= body of loop
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
@@ -1058,7 +1073,7 @@ public:
virtual int instrCount() const { return widthInstrs(); }
virtual void cloneRelink();
virtual string name() const { return m_name; } // * = Var name
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
bool lvalue() const { return m_lvalue; }
void lvalue(bool lval) { m_lvalue=lval; } // Avoid using this; Set in constructor
AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
@@ -1135,7 +1150,7 @@ public:
virtual bool maybePointedTo() const { return true; }
// {AstFunc only} op1 = Range output variable
// op3 = Statements/Ports/Vars
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
AstNode* stmtsp() const { return op3p()->castNode(); } // op1 = List of statements
void addStmtsp(AstNode* nodep) { addOp3p(nodep); }
void taskPublic(bool flag) { m_taskPublic=flag; }
@@ -1168,7 +1183,7 @@ public:
void inlinedDots(const string& flag) { m_inlinedDots = flag; }
AstNodeFTask* taskp() const { return m_taskp; } // [After Link] Pointer to variable
void taskp(AstNodeFTask* taskp) { m_taskp=taskp; }
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
void dotted(const string& name) { m_dotted = name; }
// op1 = namep
AstNode* namep() const { return op1p(); }
+117 -2
View File
@@ -122,7 +122,13 @@ string AstVar::scType() const {
} else if (widthMin() == 1) {
return "bool";
} else if (widthMin() <= VL_WORDSIZE) {
return "uint32_t";
if (widthMin() <= 8 && v3Global.opt.pinsUint8()) {
return "uint8_t";
} else if (widthMin() <= 16 && v3Global.opt.pinsUint8()) {
return "uint16_t";
} else {
return "uint32_t";
}
} else {
return "uint64_t";
}
@@ -135,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()) {
@@ -143,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())
@@ -193,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
@@ -205,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) {
@@ -235,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] => ";
@@ -312,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()) {
+73 -58
View File
@@ -46,6 +46,7 @@ struct AstConst : public AstNodeMath {
private:
V3Number m_num; // Constant value
public:
class Unsized32 {}; // for creator type-overload selection
AstConst(FileLine* fl, const V3Number& num)
:AstNodeMath(fl)
,m_num(num) {
@@ -55,6 +56,9 @@ public:
AstConst(FileLine* fl, uint32_t num)
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { width(m_num.width(), m_num.sized()?0:m_num.minWidth()); }
AstConst(FileLine* fl, Unsized32, uint32_t num) // Unsized 32-bit integer of specified value
:AstNodeMath(fl)
,m_num(V3Number(fl,32,num)) { m_num.width(32,false); width(32,m_num.minWidth()); }
ASTNODE_NODE_FUNCS(Const, CONST)
virtual string name() const { return num().ascii(); } // * = Value
virtual const V3Number& num() const { return m_num; } // * = Value
@@ -72,20 +76,30 @@ public:
struct AstRange : public AstNode {
// Range specification, for use under variables and cells
private:
bool m_littleEndian:1; // Bit vector is little endian
public:
AstRange(FileLine* fl, AstNode* msbp, AstNode* lsbp)
:AstNode(fl) {
m_littleEndian = false;
setOp2p(msbp); setOp3p(lsbp); }
AstRange(FileLine* fl, int msb, int lsb)
:AstNode(fl) {
m_littleEndian = false;
setOp2p(new AstConst(fl,msb)); setOp3p(new AstConst(fl,lsb));
width(msb-lsb+1,msb-lsb+1);
}
ASTNODE_NODE_FUNCS(Range, RANGE)
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
AstNode* msbp() const { return op2p()->castNode(); } // op2 = Msb expression
AstNode* lsbp() const { return op3p()->castNode(); } // op3 = Lsb expression
AstNode* msbEndianedp() const { return littleEndian()?lsbp():msbp(); } // How to show a declaration
AstNode* lsbEndianedp() const { return littleEndian()?msbp():lsbp(); }
int msbConst() const { AstConst* constp=msbp()->castConst(); return (constp?constp->toSInt():0); }
int lsbConst() const { AstConst* constp=lsbp()->castConst(); return (constp?constp->toSInt():0); }
int elementsConst() const { return msbConst()-lsbConst()+1; }
int elementsConst() const { return (msbConst()>lsbConst()) ? msbConst()-lsbConst()+1 : lsbConst()-msbConst()+1; }
bool littleEndian() const { return m_littleEndian; }
void littleEndian(bool flag) { m_littleEndian=flag; }
virtual void dump(ostream& str);
virtual string emitC() { V3ERROR_NA; return ""; }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
@@ -116,15 +130,8 @@ struct AstArraySel : public AstNodeSel {
virtual bool same(AstNode* samep) const { return true; }
virtual int instrCount() const { return widthInstrs(); }
// Special operators
static int dimension(AstNode* nodep) { ///< How many dimensions is this reference from the base variable?
int dim = 0;
while (nodep && nodep->castArraySel()) { dim++; nodep=nodep->castArraySel()->fromp(); }
return dim;
}
static AstNode* baseFromp(AstNode* nodep) { ///< What is the base variable (or const) this dereferences?
while (nodep && nodep->castArraySel()) { nodep=nodep->castArraySel()->fromp(); }
return nodep;
}
static int dimension(AstNode* nodep); ///< How many dimensions is this reference from the base variable?
static AstNode* baseFromp(AstNode* nodep); ///< What is the base variable (or const) this dereferences?
};
struct AstWordSel : public AstNodeSel {
@@ -149,6 +156,8 @@ struct AstSelExtract : public AstNodePreSel {
AstSelExtract(FileLine* fl, AstNode* fromp, AstNode* msbp, AstNode* lsbp)
: AstNodePreSel(fl, fromp, msbp, lsbp) {}
ASTNODE_NODE_FUNCS(SelExtract, SELEXTRACT)
AstNode* msbp() const { return rhsp(); }
AstNode* lsbp() const { return thsp(); }
};
struct AstSelBit : public AstNodePreSel {
@@ -159,6 +168,7 @@ struct AstSelBit : public AstNodePreSel {
width(1,1);
}
ASTNODE_NODE_FUNCS(SelBit, SELBIT)
AstNode* bitp() const { return rhsp(); }
};
struct AstSelPlus : public AstNodePreSel {
@@ -167,6 +177,8 @@ struct AstSelPlus : public AstNodePreSel {
AstSelPlus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
:AstNodePreSel(fl, fromp, bitp, widthp) {}
ASTNODE_NODE_FUNCS(SelPlus, SELPLUS)
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
struct AstSelMinus : public AstNodePreSel {
@@ -175,6 +187,8 @@ struct AstSelMinus : public AstNodePreSel {
AstSelMinus(FileLine* fl, AstNode* fromp, AstNode* bitp, AstNode* widthp)
:AstNodePreSel(fl, fromp, bitp, widthp) {}
ASTNODE_NODE_FUNCS(SelMinus, SELMINUS)
AstNode* bitp() const { return rhsp(); }
AstNode* widthp() const { return thsp(); }
};
struct AstSel : public AstNodeTriop {
@@ -192,7 +206,7 @@ struct AstSel : public AstNodeTriop {
}
ASTNODE_NODE_FUNCS(Sel, SEL)
virtual void numberOperate(V3Number& out, const V3Number& from, const V3Number& bit, const V3Number& width) {
out.opRange(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); }
out.opSel(from, bit.toUInt()+width.toUInt()-1, bit.toUInt()); }
virtual string emitVerilog() { V3ERROR_NA; return ""; } // Implemented specially
virtual string emitC() {
return this->widthp()->isOne()
@@ -251,13 +265,6 @@ private:
m_trace=false;
}
public:
AstVar(FileLine* fl, AstVarType type, const string& name)
:AstNode(fl)
, m_name(name) {
init();
combineType(type);
width(msb()-lsb()+1,0);
}
AstVar(FileLine* fl, AstVarType type, const string& name, AstRange* rangep, AstRange* arrayp=NULL)
:AstNode(fl)
, m_name(name) {
@@ -277,7 +284,7 @@ public:
if (examplep->arraysp()) {
setOp2p(examplep->arraysp()->cloneTree(true));
}
width(msb()-lsb()+1,0);
width(examplep->width(), examplep->widthMin());
}
ASTNODE_NODE_FUNCS(Var, VAR)
virtual void dump(ostream& str);
@@ -315,7 +322,7 @@ public:
void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; }
// METHODS
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
bool isInput() const { return m_input; }
bool isOutput() const { return m_output; }
bool isInOnly() const { return m_input && !m_output; }
@@ -361,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) {
@@ -432,7 +443,7 @@ public:
virtual bool broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
string nameDotless() const;
string nameVlSym() const { return (((string)"vlSymsp->") + nameDotless()); }
AstModule* modp() const { return m_modp; }
@@ -572,7 +583,7 @@ public:
virtual void dump(ostream& str);
virtual bool broken() const { return (m_modVarp && !m_modVarp->brokeExists()); }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
int pinNum() const { return m_pinNum; }
void exprp(AstNode* nodep) { addOp1p(nodep); }
@@ -612,7 +623,7 @@ public:
void addStmtp(AstNode* nodep) { addOp2p(nodep); }
void addActivep(AstNode* nodep) { addOp3p(nodep); }
// ACCESSORS
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
string origName() const { return m_origName; }
bool inLibrary() const { return m_inLibrary; }
void inLibrary(bool flag) { m_inLibrary = flag; }
@@ -649,7 +660,7 @@ public:
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
string origName() const { return m_origName; } // * = Original name
void origName(const string& name) { m_origName = name; }
string modName() const { return m_modName; } // * = Instance name
@@ -679,7 +690,7 @@ public:
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
string origModName() const { return m_origModName; } // * = modp()->origName() before inlining
void name(const string& name) { m_name = name; }
virtual void name(const string& name) { m_name = name; }
};
struct AstPort : public AstNode {
@@ -705,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
void name(const string& flag) { m_name=flag; }
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 {
@@ -942,7 +957,7 @@ struct AstAssign : public AstNodeAssign {
}
ASTNODE_NODE_FUNCS(Assign, ASSIGN)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssign(this->fileline(), lhsp, rhsp); }
virtual string verilogKwd() const { return "="; };
virtual string verilogKwd() const { return "="; }
};
struct AstAssignAlias : public AstNodeAssign {
@@ -961,22 +976,23 @@ struct AstAssignDly : public AstNodeAssign {
ASTNODE_NODE_FUNCS(AssignDly, ASSIGNDLY)
virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignDly(this->fileline(), lhsp, rhsp); }
virtual bool isGateOptimizable() const { return false; }
virtual string verilogKwd() const { return "<="; };
virtual string verilogKwd() const { return "<="; }
};
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 {
@@ -1249,7 +1265,7 @@ struct AstFClose : public AstNodeStmt {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FClose, FCLOSE)
virtual string verilogKwd() const { return "$fclose"; };
virtual string verilogKwd() const { return "$fclose"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isSplittable() const { return false; }
@@ -1269,7 +1285,7 @@ struct AstFOpen : public AstNodeStmt {
setOp3p(modep);
}
ASTNODE_NODE_FUNCS(FOpen, FOPEN)
virtual string verilogKwd() const { return "$fclose"; };
virtual string verilogKwd() const { return "$fclose"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isSplittable() const { return false; }
@@ -1290,7 +1306,7 @@ struct AstFFlush : public AstNodeStmt {
setNOp2p(filep);
}
ASTNODE_NODE_FUNCS(FFlush, FFLUSH)
virtual string verilogKwd() const { return "$fflush"; };
virtual string verilogKwd() const { return "$fflush"; }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isSplittable() const { return false; }
@@ -1378,7 +1394,7 @@ public:
setOp1p(filenamep); setOp2p(memp); setNOp3p(lsbp); setNOp4p(msbp);
}
ASTNODE_NODE_FUNCS(ReadMem, READMEM)
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); };
virtual string verilogKwd() const { return (isHex()?"$readmemh":"$readmemb"); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isSplittable() const { return false; }
@@ -1417,8 +1433,7 @@ struct AstRepeat : public AstNodeStmt {
ASTNODE_NODE_FUNCS(Repeat, REPEAT)
AstNode* countp() const { return op2p()->castNode(); } // op2= condition to continue
AstNode* bodysp() const { return op3p()->castNode(); } // op3= body of loop
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
virtual bool isGateOptimizable() const { return false; } // Not releavant - converted to FOR
virtual int instrCount() const { return instrCountBranch(); }
virtual V3Hash sameHash() const { return V3Hash(); }
virtual bool same(AstNode* samep) const { return true; }
@@ -1436,10 +1451,11 @@ struct AstWhile : public AstNodeStmt {
void addPrecondsp(AstNode* newp) { addOp1p(newp); }
void addBodysp(AstNode* newp) { addOp3p(newp); }
virtual bool isGateOptimizable() const { return false; }
virtual bool isPredictOptimizable() const { return false; }
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 {
@@ -1618,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;
}
@@ -1632,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; }
@@ -1715,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);
};
@@ -2367,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;}
@@ -2379,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;}
@@ -2392,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;}
@@ -2404,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;}
@@ -2636,7 +2651,7 @@ public:
virtual string name() const { return m_name; } // * = Var name
virtual V3Hash sameHash() const { return V3Hash(name()); }
virtual bool same(AstNode* samep) const { return samep->name() == name(); }
void name(const string& flag) { m_name = flag; }
virtual void name(const string& name) { m_name = name; }
AstNode* propp() const { return op1p(); } // op1 = property
AstSenTree* sentreep() const { return op2p()->castSenTree(); } // op2 = clock domain
void sentreep(AstSenTree* sentreep) { addOp2p(sentreep); } // op2 = clock domain
@@ -2818,7 +2833,7 @@ public:
&& (rtnTypeVoid()==samep->castCFunc()->rtnTypeVoid())
&& (argTypes()==samep->castCFunc()->argTypes())); }
//
void name(const string& flag) { m_name = flag; }
virtual void name(const string& name) { m_name = name; }
AstScope* scopep() const { return m_scopep; }
void scopep(AstScope* nodep) { m_scopep = nodep; }
string rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); }
+35 -23
View File
@@ -25,6 +25,9 @@
// BEGIN(VAR...) -> VAR ... {renamed}
// FOR -> WHILEs
//
// There are two scopes; named BEGINs change %m and variable scopes.
// Unnamed BEGINs change only variable, not $display("%m") scope.
//
//*************************************************************************
#include "config_build.h"
@@ -47,7 +50,8 @@ private:
// STATE
AstModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
string m_beginScope; // Name of begin blocks above us
string m_namedScope; // Name of begin blocks above us
string m_unnamedScope; // Name of begin blocks, including unnamed blocks
int m_repeatNum; // Repeat counter
// METHODS
@@ -72,24 +76,31 @@ private:
virtual void visit(AstBegin* nodep, AstNUser*) {
// Begin blocks were only useful in variable creation, change names and delete
UINFO(8," "<<nodep<<endl);
string oldScope = m_beginScope;
string oldScope = m_namedScope;
string oldUnnamed = m_unnamedScope;
{
//UINFO(8,"nname "<<m_beginScope<<endl);
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0,pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (m_beginScope=="") m_beginScope = ident;
else m_beginScope = m_beginScope + "__DOT__"+ident;
// Create CellInline for dotted resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_beginScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
//UINFO(8,"nname "<<m_namedScope<<endl);
if (nodep->name() != "") { // Else unneeded unnamed block
// Create data for dotted variable resolution
string dottedname = nodep->name() + "__DOT__"; // So always found
string::size_type pos;
while ((pos=dottedname.find("__DOT__")) != string::npos) {
string ident = dottedname.substr(0,pos);
dottedname = dottedname.substr(pos+strlen("__DOT__"));
if (!nodep->unnamed()) {
if (m_namedScope=="") m_namedScope = ident;
else m_namedScope = m_namedScope + "__DOT__"+ident;
}
if (m_unnamedScope=="") m_unnamedScope = ident;
else m_unnamedScope = m_unnamedScope + "__DOT__"+ident;
// Create CellInline for dotted var resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
m_unnamedScope, "__BEGIN__");
m_modp->addInlinesp(inlinep); // Must be parsed before any AstCells
}
}
// Remap var names
// Remap var names and replace lower Begins
nodep->iterateChildren(*this);
if (AstNode* stmtsp = nodep->stmtsp()) {
@@ -100,12 +111,13 @@ private:
}
pushDeletep(nodep); nodep=NULL;
}
m_beginScope = oldScope;
m_namedScope = oldScope;
m_unnamedScope = oldUnnamed;
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (m_beginScope != "") {
if (m_unnamedScope != "") {
// Rename it
nodep->name(m_beginScope+"__DOT__"+nodep->name());
nodep->name(m_unnamedScope+"__DOT__"+nodep->name());
// Move to module
nodep->unlinkFrBack();
if (m_ftaskp) m_ftaskp->addStmtsp(nodep); // Begins under funcs just move into the func
@@ -114,9 +126,9 @@ private:
}
virtual void visit(AstCell* nodep, AstNUser*) {
UINFO(8," CELL "<<nodep<<endl);
if (m_beginScope != "") {
if (m_namedScope != "") {
// Rename it
nodep->name(m_beginScope+"__DOT__"+nodep->name());
nodep->name(m_namedScope+"__DOT__"+nodep->name());
UINFO(8," rename to "<<nodep->name()<<endl);
// Move to module
nodep->unlinkFrBack();
@@ -174,11 +186,11 @@ private:
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
// Similar code in V3Inline
if (m_beginScope != "") {
if (m_namedScope != "") {
// To keep correct visual order, must add before other Text's
AstNode* afterp = nodep->scopeAttrp();
if (afterp) afterp->unlinkFrBackWithNext();
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_beginScope)));
nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"."+AstNode::prettyName(m_namedScope)));
if (afterp) nodep->scopeAttrp(afterp);
}
nodep->iterateChildren(*this);
+3
View File
@@ -219,6 +219,7 @@ private:
if (msb<0) {
// There's no space for a IF. We know upperValue is thus down to a specific
// exact value, so just return the tree value
// Note can't clone here, as we're going to check for equivelence above
return m_valueItem[upperValue];
}
else {
@@ -284,6 +285,8 @@ private:
AstNode::user3ClearTree();
AstNode* ifrootp = replaceCaseFastRecurse(cexprp, m_caseWidth-1, 0UL);
// Case expressions can't be linked twice, so clone them
if (ifrootp && !ifrootp->user3()) ifrootp = ifrootp->cloneTree(true);
if (ifrootp) nodep->replaceWith(ifrootp);
else nodep->unlinkFrBack();
+3 -5
View File
@@ -262,11 +262,10 @@ private:
public:
// CONSTUCTORS
CleanVisitor() {}
virtual ~CleanVisitor() {}
void main(AstNetlist* nodep) {
CleanVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~CleanVisitor() {}
};
//######################################################################
@@ -274,6 +273,5 @@ public:
void V3Clean::cleanAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
CleanVisitor visitor;
visitor.main(nodep);
CleanVisitor visitor (nodep);
}
+5 -8
View File
@@ -86,7 +86,7 @@ private:
if (varp->width()!=1) varp->v3error("Unsupported: Clock edge on non-single bit signal: "<<varp->prettyName());
string newvarname = ((string)"__Vclklast__"+vscp->scopep()->nameDotless()+"__"+varp->shortName());
AstVar* newvarp
= new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname); // No range; 1 bit.
= new AstVar (vscp->fileline(), AstVarType::MODULETEMP, newvarname, NULL, NULL); // No range; 1 bit.
newvarp->width(1,1);
m_modp->addStmtp(newvarp);
AstVarScope* newvscp = new AstVarScope(vscp->fileline(), m_scopep, newvarp);
@@ -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;
+82 -47
View File
@@ -39,6 +39,7 @@
#include "V3Ast.h"
#include "V3Width.h"
#include "V3Signed.h"
#include "V3Simulate.h"
//######################################################################
// Utilities
@@ -58,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() {}
};
@@ -312,15 +313,24 @@ private:
if (m_warn
&& nodep->lsbp()->castConst()
&& nodep->widthp()->castConst()
&& (!varp->rangep() || varp->msb()) // else it's non-resolvable parameterized
&& ( ( (nodep->msbConst() > varp->msbMaxSelect())
|| (nodep->lsbConst() > varp->msbMaxSelect())))) {
// See also warning in V3Width
nodep->v3error("Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<varp->msbMaxSelect()<<":0"
<<(varp->lsb()>=0 ? ""
:" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)"));
&& (!varp->rangep() || varp->msb())) { // else it's non-resolvable parameterized
if (nodep->lsbp()->castConst()->num().isFourState()
|| nodep->widthp()->castConst()->num().isFourState()) {
nodep->v3error("Selection index is constantly unknown or tristated: "
"lsb="<<nodep->lsbp()->name()<<" width="<<nodep->widthp()->name());
// Replacing nodep will make a mess above, so we replace the offender
replaceZero(nodep->lsbp());
}
else if ((nodep->msbConst() > varp->msbMaxSelect())
|| (nodep->lsbConst() > varp->msbMaxSelect())) {
// See also warning in V3Width
nodep->v3error("Selection index out of range: "
<<nodep->msbConst()<<":"<<nodep->lsbConst()
<<" outside "<<varp->msbMaxSelect()<<":0"
<<(varp->lsb()>=0 ? ""
:" (adjusted +"+cvtToStr(-varp->lsb())+" to account for negative lsb)"));
// Don't replace with zero, we'll do it later
}
}
}
return false; // Not a transform, so NOP
@@ -366,7 +376,9 @@ private:
void replaceNum (AstNode* oldp, const V3Number& num) {
// Replace oldp node with a constant set to specified value
UASSERT (oldp, "Null old\n");
if (oldp->castConst()) oldp->v3fatalSrc("Already constant??\n");
if (oldp->castConst() && !oldp->castConst()->num().isFourState()) {
oldp->v3fatalSrc("Already constant??\n");
}
AstNode* newp = new AstConst(oldp->fileline(), num);
newp->widthSignedFrom(oldp);
if (debug()>5) oldp->dumpTree(cout," const_old: ");
@@ -827,6 +839,26 @@ private:
if (debug()>=9) newp->dumpTree(cout," _new: ");
}
void replaceWithSimulation(AstNode* nodep) {
SimulateVisitor simvis;
// Run it - may be unoptimizable due to large for loop, etc
simvis.mainParamEmulate(nodep);
if (!simvis.optimizable()) {
AstNode* errorp = simvis.whyNotNodep(); if (!errorp) errorp = nodep;
nodep->v3error("Expecting expression to be constant, but can't determine constant for "
<<nodep->prettyTypeName()<<endl
<<V3Error::msgPrefix()<<errorp->fileline()<<"... Location of non-constant "
<<errorp->prettyTypeName()<<": "<<simvis.whyNotMessage());
replaceZero(nodep); nodep=NULL;
} else {
// Fetch the result
V3Number* outnump = simvis.fetchNumberNull(nodep);
if (!outnump) nodep->v3fatalSrc("No number returned from simulation");
// Replace it
replaceNum(nodep,*outnump); nodep=NULL;
}
}
//----------------------------------------
// VISITORS
@@ -1021,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())
@@ -1047,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) {
@@ -1420,6 +1436,13 @@ private:
}
}
virtual void visit(AstFuncRef* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_params) { // Only parameters force us to do constant function call propagation
replaceWithSimulation(nodep);
}
}
virtual void visit(AstWhile* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (nodep->condp()->isZero()) {
@@ -1432,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
@@ -1674,12 +1701,11 @@ private:
// Default: Just iterate
if (m_required) {
nodep->v3error("Expecting expression to be constant, but can't convert a "
<<nodep->typeName()<<" to constant.");
<<nodep->prettyTypeName()<<" to constant.");
} 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);
}
@@ -1697,53 +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 : ");
if (!nodep->width()) {
V3Width::widthParams(nodep);
V3Signed::signedParams(nodep);
}
// 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);
visitor.main(nodep);
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.mainAcceptEdit(varp->initp());
} else {
nodep = visitor.mainAcceptEdit(nodep);
}
// Because we do edits, nodep links may get trashed and core dump this.
//if (debug()>0) nodep->dumpTree(cout," forceConDONE: ");
return nodep;
}
void V3Const::constifyAll(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,true,false,false);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyAllLint(AstNetlist* nodep) {
// Only call from Verilator.cpp, as it uses user#'s
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,true,false);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyCpp(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ConstVisitor visitor (false,false,false,true);
visitor.main(nodep);
(void)visitor.mainAcceptEdit(nodep);
}
void V3Const::constifyTree(AstNode* nodep) {
AstNode* V3Const::constifyEdit(AstNode* nodep) {
ConstVisitor visitor (false,false,false,false);
visitor.main(nodep);
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
void V3Const::constifyTreeExpensive(AstNode* nodep) {
AstNode* V3Const::constifyExpensiveEdit(AstNode* nodep) {
ConstVisitor visitor (false,true,false,false);
visitor.main(nodep);
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
+6 -3
View File
@@ -32,7 +32,8 @@
class V3Const {
public:
// Force this cell node's parameter list to become a constant
static void constifyParam(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyParamsEdit(AstNode* nodep);
// Everything that's possible
static void constifyAll(AstNetlist* nodep);
// Also, warn
@@ -40,9 +41,11 @@ public:
// C++ datatypes
static void constifyCpp(AstNetlist* nodep);
// Only the current node and lower
static void constifyTree(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyEdit(AstNode* nodep);
// Only the current node and lower, with special SenTree optimization
static void constifyTreeExpensive(AstNode* nodep);
// Return new node that may have replaced nodep
static AstNode* constifyExpensiveEdit(AstNode* nodep);
};
#endif // Guard
+1 -1
View File
@@ -215,7 +215,7 @@ private:
}
// VISITORS - LINE COVERAGE
virtual void visit(AstIf* nodep, AstNUser*) {
virtual void visit(AstIf* nodep, AstNUser*) { // Note not AstNodeIf; other types don't get covered
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
+2 -2
View File
@@ -335,7 +335,7 @@ private:
&& nodep->lhsp()->castSel()->fromp()->castArraySel())) {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
AstNode* newlhsp = createDlyArray(nodep, lhsp);
if (m_inLoop) nodep->v3error("Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
if (m_inLoop) nodep->v3warn(BLKLOOPINIT,"Unsupported: Delayed assignment to array inside for loops (non-delayed is ok - see docs)");
if (newlhsp) {
nodep->lhsp(newlhsp);
} else {
@@ -441,7 +441,7 @@ private:
public:
// CONSTUCTORS
DelayedVisitor(AstNode* nodep) {
DelayedVisitor(AstNetlist* nodep) {
m_inDly = false;
m_activep=NULL;
m_cfuncp=NULL;
+1 -1
View File
@@ -156,7 +156,7 @@ private:
public:
// CONSTUCTORS
DepthVisitor(AstNode* nodep) {
DepthVisitor(AstNetlist* nodep) {
m_modp=NULL;
m_funcp=NULL;
m_stmtp=NULL;
+1 -1
View File
@@ -126,7 +126,7 @@ private:
public:
// CONSTUCTORS
DepthBlockVisitor(AstNode* nodep) {
DepthBlockVisitor(AstNetlist* nodep) {
m_modp=NULL;
m_depth=0;
//
+18 -17
View File
@@ -227,7 +227,7 @@ public:
}
virtual void visit(AstDisplay* nodep, AstNUser*) {
string text = nodep->text();
if (nodep->addNewline()) text += "\\n";
if (nodep->addNewline()) text += "\n";
displayNode(nodep, text, nodep->exprsp(), false);
}
virtual void visit(AstFScanF* nodep, AstNUser*) {
@@ -528,9 +528,9 @@ public:
virtual void visit(AstTraceInc*, AstNUser*) {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
puts((string)"\n???? // "+nodep->typeName()+"\n");
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
nodep->iterateChildren(*this);
nodep->v3fatalSrc("Unknown node type reached emitter: "<<nodep->typeName());
nodep->v3fatalSrc("Unknown node type reached emitter: "<<nodep->prettyTypeName());
}
public:
@@ -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(",");
@@ -1410,7 +1408,7 @@ void EmitCStmts::emitVarList(AstNode* firstp, EisWhich which, const string& pref
case EVL_ALL: doit = true; break;
case EVL_IO: doit = varp->isIO(); break;
case EVL_SIG: doit = (varp->isSignal() && !varp->isIO()); break;
case EVL_TEMP: doit = varp->isTemp(); break;
case EVL_TEMP: doit = (varp->isTemp() && !varp->isIO()); break;
default: v3fatalSrc("Bad Case");
}
if (varp->isStatic() ? !isstatic : isstatic) doit=false;
@@ -1796,10 +1794,13 @@ class EmitCTrace : EmitCStmts {
puts("if (!Verilated::calcUnusedSigs()) vl_fatal(__FILE__,__LINE__,__FILE__,\"Turning on wave traces requires Verilated::traceEverOn(true) call before time 0.\");\n");
//Future; need to wait to estabilish backwards compatibility
//puts("#if defined(SPTRACEVCDC_VERSION) && SPTRACEVCDC_VERSION >= 1320\n");
//puts("vcdp->scopeEscape(' ');\n");
puts("#if defined(SPTRACEVCDC_VERSION) && SPTRACEVCDC_VERSION >= 1330\n");
puts("vcdp->scopeEscape(' ');\n");
puts("t->traceInitThis (vlSymsp, vcdp, code);\n");
//puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break
puts("vcdp->scopeEscape('.');\n"); // Restore so SystemPerl traced files won't break
puts("#else\n");
puts("t->traceInitThis (vlSymsp, vcdp, code);\n");
puts("#endif\n");
puts("}\n");
puts("void "+topClassName()+"::traceFull(SpTraceVcd* vcdp, void* userthis, uint32_t code) {\n");
@@ -1838,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 ");
@@ -1852,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(");");
}
@@ -1867,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 ");
@@ -1876,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");
@@ -1885,8 +1886,8 @@ class EmitCTrace : EmitCStmts {
if (nodep->valuep()->castVarRef()) {
AstVarRef* varrefp = nodep->valuep()->castVarRef();
AstVar* varp = varrefp->varp();
if (emitTraceIsScBv(nodep)) puts("(uint32_t*)");
puts("(");
if (emitTraceIsScBv(nodep)) puts("VL_SC_BV_DATAP(");
varrefp->iterate(*this); // Put var name out
if (varp->arraysp()) {
if (arrayindex==-2) puts("[i]");
@@ -1894,7 +1895,7 @@ class EmitCTrace : EmitCStmts {
else puts("["+cvtToStr(arrayindex)+"]");
}
if (varp->isSc()) puts(".read()");
if (emitTraceIsScBv(nodep)) puts(".get_datap()");
if (emitTraceIsScBv(nodep)) puts(")");
puts(")");
} else {
puts("(");
+14 -8
View File
@@ -43,7 +43,7 @@ public:
V3OutCFile(const string& filename) : V3OutFile(filename) {
resetPrivate();
}
virtual ~V3OutCFile() {};
virtual ~V3OutCFile() {}
virtual void putsCellDecl(const string& classname, const string& cellname) {
this->printf("%-19s\t%s;\n",
(classname + "*").c_str(),cellname.c_str());
@@ -66,30 +66,36 @@ public:
class V3OutScFile : public V3OutCFile {
public:
V3OutScFile(const string& filename) : V3OutCFile(filename) {}
virtual ~V3OutScFile() {};
virtual ~V3OutScFile() {}
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() { puts("#include \"systemc.h\"\n"); }
virtual void putsIntTopInclude() {
puts("#include \"systemc.h\"\n");
puts("#include \"verilatedsc.h\"\n");
}
};
class V3OutSpFile : public V3OutCFile {
public:
V3OutSpFile(const string& filename) : V3OutCFile(filename) {}
virtual ~V3OutSpFile() {};
virtual ~V3OutSpFile() {}
virtual void putsHeader() { puts("// Verilated -*- SystemC -*-\n"); }
virtual void putsIntTopInclude() { puts("#include \"systemperl.h\"\n"); }
virtual void putsIntTopInclude() {
puts("#include \"systemperl.h\"\n");
puts("#include \"verilatedsc.h\"\n");
}
};
class V3OutVFile : public V3OutFile {
public:
V3OutVFile(const string& filename) : V3OutFile(filename) {}
virtual ~V3OutVFile() {};
virtual ~V3OutVFile() {}
virtual void putsHeader() { puts("// Verilated -*- Verilog -*-\n"); }
};
class V3OutMkFile : public V3OutFile {
public:
V3OutMkFile(const string& filename) : V3OutFile(filename) {}
virtual ~V3OutMkFile() {};
virtual ~V3OutMkFile() {}
virtual void putsHeader() { puts("# Verilated -*- Makefile -*-\n"); }
// No automatic indentation yet.
void puts(const char* strg) { putsNoTracking(strg); }
@@ -104,7 +110,7 @@ public:
// STATE
V3OutCFile* m_ofp;
// METHODS
V3OutCFile* ofp() const { return m_ofp; };
V3OutCFile* ofp() const { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsQuoted(const string& str) { ofp()->putsQuoted(str); }
+3 -1
View File
@@ -65,7 +65,9 @@ class EmitCSyms : EmitCBaseVisitor {
if (nodep->name() != "") {
string rsvd = m_words.isKeyword(nodep->name());
if (rsvd != "") {
nodep->v3error("Unsupported: "+rsvd+": "<<nodep->name());
// Generally V3Name should find all of these and throw SYMRSVDWORD.
// We'll still check here because the compiler errors resulting if we miss this warning are SO nasty
nodep->v3error("Symbol matching "+rsvd+" reserved word reached emitter, should have hit SYMRSVDWORD: '"<<nodep->name()<<"'");
}
}
}
+6 -6
View File
@@ -109,7 +109,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
puts(";\n");
}
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
putbs("assign ");
putbs("alias ");
nodep->lhsp()->iterateAndNext(*this);
putbs(" = ");
nodep->rhsp()->iterateAndNext(*this);
@@ -368,8 +368,8 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
}
virtual void visit(AstRange* nodep, AstNUser*) {
puts("[");
nodep->msbp()->iterateAndNext(*this); puts(":");
nodep->lsbp()->iterateAndNext(*this); puts("]");
nodep->msbEndianedp()->iterateAndNext(*this); puts(":");
nodep->lsbEndianedp()->iterateAndNext(*this); puts("]");
}
virtual void visit(AstSel* nodep, AstNUser*) {
nodep->fromp()->iterateAndNext(*this); puts("[");
@@ -442,9 +442,9 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
virtual void visit(AstCell*, AstNUser*) {} // Handled outside the Visit class
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
puts((string)"\n???? // "+nodep->typeName()+"\n");
puts((string)"\n???? // "+nodep->prettyTypeName()+"\n");
nodep->iterateChildren(*this);
nodep->v3fatalSrc("Unknown node type reached emitter: "<<nodep->typeName());
nodep->v3fatalSrc("Unknown node type reached emitter: "<<nodep->prettyTypeName());
}
public:
@@ -461,7 +461,7 @@ class EmitVFileVisitor : public EmitVBaseVisitor {
// MEMBERS
V3OutFile* m_ofp;
// METHODS
V3OutFile* ofp() const { return m_ofp; };
V3OutFile* ofp() const { return m_ofp; }
void puts(const string& str) { ofp()->puts(str); }
void putbs(const string& str) { ofp()->putbs(str); }
void putsNoTracking(const string& str) { ofp()->putsNoTracking(str); }
+33 -12
View File
@@ -38,6 +38,7 @@ FileLine FileLine::s_defaultFileLine = FileLine(EmptySecret());
int V3Error::s_errCount = 0;
int V3Error::s_warnCount = 0;
int V3Error::s_debugDefault = 0;
int V3Error::s_tellManual = 0;
ostringstream V3Error::s_errorStr; // Error string being formed
V3ErrorCode V3Error::s_errorCode = V3ErrorCode::FATAL;
bool V3Error::s_describedEachWarn[V3ErrorCode::MAX];
@@ -45,7 +46,7 @@ bool V3Error::s_describedWarnings = false;
bool V3Error::s_pretendError[V3ErrorCode::MAX];
struct v3errorIniter {
v3errorIniter() { V3Error::init(); };
v3errorIniter() { V3Error::init(); }
};
v3errorIniter v3errorInit;
@@ -285,6 +286,7 @@ bool V3Error::isError(V3ErrorCode code) {
if (code==V3ErrorCode::SUPPRESS) return false;
else if (code==V3ErrorCode::INFO) return false;
else if (code==V3ErrorCode::FATAL) return true;
else if (code==V3ErrorCode::FATALSRC) return true;
else if (code==V3ErrorCode::ERROR) return true;
else if (code<V3ErrorCode::FIRST_WARN
|| s_pretendError[code]) return true;
@@ -295,11 +297,24 @@ string V3Error::msgPrefix(V3ErrorCode code) {
if (code==V3ErrorCode::SUPPRESS) return "-arning-suppressed: ";
else if (code==V3ErrorCode::INFO) return "-Info: ";
else if (code==V3ErrorCode::FATAL) return "%Error: ";
else if (code==V3ErrorCode::FATALSRC) return "%Error: Internal Error: ";
else if (code==V3ErrorCode::ERROR) return "%Error: ";
else if (isError(code)) return "%Error-"+(string)code.ascii()+": ";
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
@@ -322,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);
@@ -352,12 +363,27 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
cerr<<msgPrefix()<<"else you may end up with different sim results."<<endl;
}
}
// If first warning is not the user's fault (internal/unsupported) then give the website
// Not later warnings, as a internal may be caused by an earlier problem
if (s_tellManual == 0) {
if (s_errorCode.mentionManual()
|| sstr.str().find("Unsupported") != string::npos) {
s_tellManual = 1;
} else {
s_tellManual = 2;
}
}
if (isError(s_errorCode)) incErrors();
else incWarnings();
if (s_errorCode==V3ErrorCode::FATAL) {
if (s_errorCode==V3ErrorCode::FATAL
|| s_errorCode==V3ErrorCode::FATALSRC) {
static bool inFatal = false;
if (!inFatal) {
inFatal = true;
if (s_tellManual==1) {
cerr<<msgPrefix()<<"See the manual and http://www.veripool.org/verilator for more assistance."<<endl;
s_tellManual = 2;
}
#ifndef _V3ERROR_NO_GLOBAL_
if (debug()) {
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",99));
@@ -367,12 +393,7 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
#endif
}
if (V3Error::debugDefault()) {
cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
abort();
} else {
exit(10);
}
vlAbort();
}
}
}
+27 -17
View File
@@ -39,6 +39,7 @@ public:
SUPPRESS, // Warning suppressed by user
INFO, // General information out
FATAL, // Kill the program
FATALSRC, // Kill the program, for internal source errors
ERROR, // General error out, can't suppress
// Boolean information we track per-line, but aren't errors
I_COVERAGE, // Coverage is on/off from /*verilator coverage_on/off*/
@@ -46,6 +47,7 @@ public:
// Error codes:
MULTITOP, // Error: Multiple top level modules
TASKNSVAR, // Error: Task I/O not simple
BLKLOOPINIT, // Error: Delayed assignment to array inside for loops
// Warning codes:
FIRST_WARN, // Just a code so the program knows where to start warnings
//
@@ -57,10 +59,12 @@ public:
CMPCONST, // Comparison is constant due to limited range
COMBDLY, // Combinatorial delayed assignment
STMTDLY, // Delayed statement
SYMRSVDWORD, // Symbol is Reserved Word
GENCLK, // Generated Clock
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
@@ -75,46 +79,51 @@ public:
// ***Add new elements below also***
};
enum en m_e;
inline V3ErrorCode () {};
inline V3ErrorCode (en _e) : m_e(_e) {};
inline V3ErrorCode () {}
inline V3ErrorCode (en _e) : m_e(_e) {}
V3ErrorCode (const char* msgp); // Matching code or ERROR
explicit inline V3ErrorCode (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
explicit inline V3ErrorCode (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
const char* ascii() const {
const char* names[] = {
// Leading spaces indicate it can't be disabled.
" MIN", " SUPPRESS", " INFO", " FATAL", " ERROR",
" MIN", " SUPPRESS", " INFO", " FATAL", " FATALSRC", " ERROR",
// Boolean
" I_COVERAGE", " I_TRACING",
// Errors
"MULTITOP", "TASKNSVAR",
"MULTITOP", "TASKNSVAR", "BLKLOOPINIT",
// Warnings
" FIRST_WARN",
"BLKANDNBLK",
"CASEINCOMPLETE", "CASEOVERLAP", "CASEWITHX", "CASEX", "CMPCONST",
"COMBDLY", "STMTDLY", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
"COMBDLY", "STMTDLY", "SYMRSVDWORD", "GENCLK", "IMPERFECTSCH", "IMPLICIT", "IMPURE",
"LITENDIAN",
"MULTIDRIVEN", "REDEFMACRO",
"UNDRIVEN", "UNOPT", "UNOPTFLAT", "UNSIGNED", "UNUSED",
"VARHIDDEN", "WIDTH", "WIDTHCONCAT",
" MAX"
};
return names[m_e];
};
}
// Warnings that default to off
bool defaultsOff() const { return ( m_e==IMPERFECTSCH );};
bool defaultsOff() const { return ( m_e==IMPERFECTSCH ); }
// Warnings that warn about nasty side effects
bool dangerous() const { return ( m_e==COMBDLY );};
bool dangerous() const { return ( m_e==COMBDLY ); }
// Warnings we'll present to the user as errors
// Later -Werror- options may make more of these.
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE); };
bool pretendError() const { return ( m_e==BLKANDNBLK || m_e==IMPURE || m_e==SYMRSVDWORD); }
// Warnings to mention manual
bool mentionManual() const { return ( m_e==FATALSRC || pretendError() ); }
// Warnings that are lint only
bool lintError() const { return ( m_e==CASEINCOMPLETE || m_e==CASEOVERLAP
|| 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); };
|| m_e==WIDTH); }
};
inline bool operator== (V3ErrorCode lhs, V3ErrorCode rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (V3ErrorCode lhs, V3ErrorCode::en rhs) { return (lhs.m_e == rhs); }
@@ -132,6 +141,7 @@ class V3Error {
static int s_debugDefault; // Default debugging level
static int s_errCount; // Error count
static int s_warnCount; // Error count
static int s_tellManual; // Tell user to see manual, 0=not yet, 1=doit, 2=disable
static ostringstream s_errorStr; // Error string being formed
static V3ErrorCode s_errorCode; // Error string being formed will abort
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
@@ -165,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.
};
@@ -175,12 +185,12 @@ inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
// These allow errors using << operators: v3error("foo"<<"bar");
// Careful, you can't put () around msg, as you would in most macro definitions
#define v3info(msg) v3errorEnd(((V3Error::v3errorPrep(V3ErrorCode::INFO)<<msg),V3Error::v3errorStr()));
#define v3fatal(msg) v3errorEnd(((V3Error::v3errorPrep(V3ErrorCode::FATAL)<<msg),V3Error::v3errorStr()));
#define v3error(msg) v3errorEnd(((V3Error::v3errorPrep(V3ErrorCode::ERROR)<<msg),V3Error::v3errorStr()));
#define v3warn(code,msg) v3errorEnd(((V3Error::v3errorPrep(V3ErrorCode::code)<<msg),V3Error::v3errorStr()));
#define v3info(msg) v3warn(INFO,msg)
#define v3fatal(msg) v3warn(FATAL,msg)
#define v3error(msg) v3warn(ERROR,msg)
// Use this instead of fatal() to mention the source code line.
#define v3fatalSrc(msg) v3fatal("Internal Error: "<<__FILE__<<":"<<dec<<__LINE__<<": "<<msg)
#define v3fatalSrc(msg) v3warn(FATALSRC,__FILE__<<":"<<dec<<__LINE__<<": "<<msg)
#define UINFO(level,stmsg) {if(debug()>=(level)) { cout<<"- "<<V3Error::lineStr(__FILE__,__LINE__)<<stmsg; }}
#define UINFONL(level,stmsg) {if(debug()>=(level)) { cout<<stmsg; } }
+3 -6
View File
@@ -905,13 +905,11 @@ private:
public:
// CONSTUCTORS
ExpandVisitor() {
ExpandVisitor(AstNetlist* nodep) {
m_stmtp=NULL;
}
virtual ~ExpandVisitor() {}
void main(AstNode* nodep) {
nodep->accept(*this);
}
virtual ~ExpandVisitor() {}
};
//----------------------------------------------------------------------
@@ -922,6 +920,5 @@ public:
void V3Expand::expandAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
ExpandVisitor visitor;
visitor.main(nodep);
ExpandVisitor visitor (nodep);
}
+5 -11
View File
@@ -31,6 +31,7 @@
#include "V3Global.h"
#include "V3File.h"
#include "V3PreShell.h"
#include "V3Ast.h"
//######################################################################
// V3File Internal state
@@ -62,7 +63,7 @@ class V3FileDependImp {
}
}
}
bool operator<(const DependFile& rhs) const { return filename()<rhs.filename(); };
bool operator<(const DependFile& rhs) const { return filename()<rhs.filename(); }
};
// MEMBERS
@@ -435,16 +436,9 @@ void V3OutFile::putsQuoted(const char* strg) {
// Quote \ and " for use inside C programs
// Don't use to quote a filename for #include - #include doesn't \ escape.
putcNoTracking('"');
for (const char* cp=strg; *cp; cp++) {
if (*cp == '\\') {
putcNoTracking('\\');
putcNoTracking('\\');
} else if (*cp == '"') {
putcNoTracking('\\');
putcNoTracking('"');
} else {
putcNoTracking (*cp);
}
string quoted = AstNode::quoteName(strg);
for (const char* cp=quoted.c_str(); *cp; cp++) {
putcNoTracking (*cp);
}
putcNoTracking('"');
}
+1 -1
View File
@@ -123,7 +123,7 @@ public:
bool exceededWidth() const { return m_column > WIDTH; }
bool tokenStart(const char* cp, const char* cmp);
bool tokenEnd(const char* cp);
void indentInc() { m_indentLevel += INDBLK; };
void indentInc() { m_indentLevel += INDBLK; }
void indentDec() {
m_indentLevel -= INDBLK;
UASSERT(m_indentLevel>=0, ": "<<m_filename<<": Underflow of indentation\n");
+1 -1
View File
@@ -688,7 +688,7 @@ void GateVisitor::optimizeElimVar(AstVarScope* varscp, AstNode* substp, AstNode*
if (debug()>=9) consumerp->dumpTree(cout,"\telimUseCns: ");
//Caution: Can't let V3Const change our handle to consumerp, such as by
// optimizing away this assignment, etc.
V3Const::constifyTree(consumerp);
consumerp = V3Const::constifyEdit(consumerp);
if (debug()>=5) consumerp->dumpTree(cout,"\telimUseDne: ");
}
}
+1 -1
View File
@@ -65,7 +65,7 @@ private:
if (!nodep->user4()) {
if (nodep->backp()->castCFunc()
&& !(nodep->castNodeStmt() || nodep->castCFunc())) {
nodep->v3fatalSrc("Node "<<nodep->typeName()<<" in statement position but not marked stmt (node under function)");
nodep->v3fatalSrc("Node "<<nodep->prettyTypeName()<<" in statement position but not marked stmt (node under function)");
}
V3Hash oldHash = m_lowerHash;
{
+1 -1
View File
@@ -146,7 +146,7 @@ private:
}
// Cleanup var names, etc, to not conflict
m_cellp = nodep;
newmodp->iterateAndNext(*this);
newmodp->iterate(*this); // Not iterateAndNext because newmodp isn't linked; no back
m_cellp = NULL;
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
+1 -1
View File
@@ -87,7 +87,7 @@ private:
UINFO(4," PIN "<<nodep<<endl);
if (debug()>=9) nodep->dumpTree(cout," Pin_oldb: ");
if (nodep->modVarp()->isOutOnly() && nodep->exprp()->castConst())
nodep->v3error("Output pin is assigned to a constant, electrical short");
nodep->v3error("Output port is connected to a constant pin, electrical short");
// Use user1p on the PIN to indicate we created an assign for this pin
if (!nodep->user1()) {
nodep->user1(1);
+13 -2
View File
@@ -34,6 +34,7 @@
#include <cstdarg>
#include <unistd.h>
#include <map>
#include <vector>
#include "V3Global.h"
#include "V3Life.h"
@@ -53,13 +54,21 @@ class LifeState {
public:
V3Double0 m_statAssnDel; // Statistic tracking
V3Double0 m_statAssnCon; // Statistic tracking
vector<AstNode*> m_unlinkps;
public:
// CONSTRUCTORS
LifeState() {}
~LifeState() {
V3Stats::addStat("Optimizations, Lifetime assign deletions", m_statAssnDel);
V3Stats::addStat("Optimizations, Lifetime constant prop", m_statAssnCon);
for (vector<AstNode*>::iterator it = m_unlinkps.begin(); it != m_unlinkps.end(); ++it) {
(*it)->unlinkFrBack();
(*it)->deleteTree();
}
}
// METHODS
void pushUnlinkDeletep(AstNode* nodep) { m_unlinkps.push_back(nodep); }
};
//######################################################################
@@ -144,9 +153,11 @@ public:
if (AstNode* oldassp = entp->assignp()) {
UINFO(7," PREV: "<<oldassp<<endl);
// Redundant assignment, in same level block
// Don't delete it now as it will confuse iteration since it maybe WAY
// above our current iteration point.
if (debug()>4) oldassp->dumpTree(cout, " REMOVE/SAMEBLK ");
entp->complexAssign();
oldassp->unlinkFrBack()->deleteTree(); oldassp=NULL;
m_statep->pushUnlinkDeletep(oldassp); oldassp=NULL;
m_statep->m_statAssnDel++;
}
}
@@ -307,7 +318,7 @@ private:
if (lastEdit != AstNode::editCountGbl()) {
// We changed something, try to constant propagate, but don't delete the
// assignment as we still need nodep to remain.
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
}
// Has to be direct assignment without any EXTRACTing.
if (nodep->lhsp()->castVarRef() && !m_sideEffect) {
+20 -2
View File
@@ -72,6 +72,7 @@ private:
V3SymTable* m_curVarsp; // Symbol table of variables and tasks under table we're inserting into
V3SymTable* m_cellVarsp; // Symbol table of variables under cell's module
int m_beginNum; // Begin block number, 0=none seen
int m_modBeginNum; // Begin block number in module, 0=none seen
bool m_inGenerate; // Inside a generate
vector<V3SymTable*> m_delSymps; // Symbol tables to delete
@@ -156,7 +157,7 @@ private:
if (!forrefp->varp()) {
if (!noWarn) forrefp->v3warn(IMPLICIT,"Signal definition not found, creating implicitly: "<<forrefp->prettyName());
AstVar* newp = new AstVar (forrefp->fileline(), AstVarType::WIRE,
forrefp->name());
forrefp->name(), NULL, NULL); // width 1
newp->trace(m_modp->modTrace());
m_modp->addStmtp(newp);
// Link it to signal list
@@ -193,6 +194,7 @@ private:
m_cellVarsp = NULL;
m_paramNum = 0;
m_beginNum = 0;
m_modBeginNum = 0;
nodep->iterateChildren(*this);
// Prep for next
m_curVarsp = NULL;
@@ -328,8 +330,23 @@ private:
++m_beginNum;
nodep->name(nodep->name()+cvtToStr(m_beginNum));
}
if (m_idState==ID_FIND && nodep->name()=="" && nodep->unnamed()) {
// Unnamed blocks are only important when they contain var
// decls, so search for them. (Otherwise adding all the
// unnamed#'s would just confuse tracing variables in
// places such as tasks, where "task ...; begin ... end"
// are common.
for (AstNode* stmtp = nodep->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (stmtp->castVar()) {
++m_modBeginNum;
nodep->name("unnamedblk"+cvtToStr(m_modBeginNum));
break;
}
}
}
// Check naming (we don't really care, but some tools do, so better to warn)
if (m_idState==ID_FIND) {
if (m_idState==ID_FIND && nodep->name()!="") {
findAndInsertAndCheck(nodep, nodep->name());
}
// Recurse
@@ -480,6 +497,7 @@ public:
m_ftaskp = NULL;
m_paramNum = 0;
m_beginNum = 0;
m_modBeginNum = 0;
m_inGenerate = false;
//
rootp->accept(*this);
+3 -6
View File
@@ -258,15 +258,13 @@ private:
public:
// CONSTUCTORS
LinkCellsVisitor() {
LinkCellsVisitor(AstNetlist* rootp) {
m_modp = NULL;
m_libVertexp = NULL;
m_topVertexp = NULL;
}
virtual ~LinkCellsVisitor() {}
void main(AstNetlist* rootp) {
rootp->accept(*this);
}
virtual ~LinkCellsVisitor() {}
};
//######################################################################
@@ -274,6 +272,5 @@ public:
void V3LinkCells::link(AstNetlist* rootp) {
UINFO(4,__FUNCTION__<<": "<<endl);
LinkCellsVisitor visitor;
visitor.main(rootp);
LinkCellsVisitor visitor (rootp);
}
+20 -146
View File
@@ -160,6 +160,11 @@ private:
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
did=1;
}
if (AstNodePreSel* selp = nodep->sensp()->castNodePreSel()) {
AstNode* fromp = selp->lhsp()->unlinkFrBack();
selp->replaceWith(fromp); selp->deleteTree(); selp=NULL;
did=1;
}
}
}
if (!nodep->sensp()->castNodeVarRef()) {
@@ -171,151 +176,19 @@ private:
nodep->v3fatalSrc("SenGates shouldn't be in tree yet");
}
void iterateSelTriop(AstNodePreSel* nodep) {
nodep->iterateChildren(*this);
}
AstNode* newSubAttrOf(AstNode* underp, AstNode* fromp, AstAttrType attrType) {
// Account for a variable's LSB in bit selections
// Replace underp with a SUB(underp, ATTROF(varp, attrType))
int dimension=0;
while (fromp && !fromp->castNodeVarRef() && (fromp->castSel() || fromp->castArraySel())) {
if (fromp->castSel()) fromp = fromp->castSel()->fromp();
else fromp = fromp->castArraySel()->fromp();
dimension++;
virtual void visit(AstNodePreSel* nodep, AstNUser*) {
if (!nodep->attrp()) {
nodep->iterateChildren(*this);
// Constification may change the fromp() to a constant, which will loose the
// variable we're extracting from (to determine MSB/LSB/endianness/etc.)
// So we replicate it in another node
// Note that V3Param knows not to replace AstVarRef's under AstAttrOf's
AstNode* basefromp = AstArraySel::baseFromp(nodep);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef(); // Maybe varxref - so need to clone
if (!varrefp) nodep->v3fatalSrc("Illegal bit select; no signal being extracted from");
nodep->attrp(new AstAttrOf(nodep->fileline(), AstAttrType::VAR_BASE,
varrefp->cloneTree(false)));
}
AstNodeVarRef* varrefp = fromp->castNodeVarRef();
if (!varrefp) fromp->v3fatalSrc("Bit/array selection of non-variable");
if (!varrefp->varp()) varrefp->v3fatalSrc("Signal not linked");
AstRange* vararrayp = varrefp->varp()->arrayp(dimension);
AstRange* varrangep = varrefp->varp()->rangep();
if ((attrType==AstAttrType::ARRAY_LSB
// SUB #'s Not needed because LSB==0? (1D only, else we'll constify it later)
? (vararrayp && !vararrayp->lsbp()->isZero())
: (varrangep && !varrangep->lsbp()->isZero()))) {
AstNode* newrefp;
if (varrefp->castVarXRef()) {
newrefp = new AstVarXRef(underp->fileline(),
varrefp->varp(), varrefp->castVarXRef()->dotted(), false);
} else {
newrefp = new AstVarRef (underp->fileline(),
varrefp->varp(), false);
}
AstNode* newp = new AstSub (underp->fileline(),
underp,
new AstAttrOf(underp->fileline(),
attrType, newrefp, dimension));
return newp;
} else {
return underp;
}
}
void selCheckDimension(AstSel* nodep) {
// Perform error checks on the node
AstNode* fromp = nodep->lhsp();
AstNode* basefromp = AstArraySel::baseFromp(fromp);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
AstVar* varp = varrefp ? varrefp->varp() : NULL;
if (fromp->castSel()
|| (varp && !varp->rangep() && !varp->isParam())) {
nodep->v3error("Illegal bit select; variable already selected, or bad dimension");
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
// Couldn't tell until link time if [#] references a bit or an array
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
AstNode* basefromp = AstArraySel::baseFromp(fromp);
int dimension = AstArraySel::dimension(fromp);
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
if (varrefp
&& varrefp->varp()
&& varrefp->varp()->arrayp(dimension)) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstNode* newp = new AstArraySel
(nodep->fileline(),
fromp,
newSubAttrOf(bitp, fromp, AstAttrType::ARRAY_LSB));
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else {
// SELBIT(range, index) -> SEL(array, index, 1)
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(bitp, fromp, AstAttrType::RANGE_LSB),
new AstConst (nodep->fileline(),one));
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
AstNode* widthp;
if (msbp->castConst() && lsbp->castConst()) {
// Quite common, save V3Const some effort
V3Number widnum (msbp->fileline(),32,msbp->castConst()->toSInt() +1-lsbp->castConst()->toSInt());
widnum.width(32,false); // Unsized so width from user
widthp = new AstConst (msbp->fileline(), widnum);
pushDeletep(msbp);
} else {
V3Number one (nodep->fileline(),32,1); one.width(32,false); // Unsized so width from user
widthp = new AstSub (lsbp->fileline(),
new AstAdd(msbp->fileline(),
new AstConst(msbp->fileline(),one),
msbp),
lsbp->cloneTree(true));
}
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
// SELPLUS -> SEL
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* lsbp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(lsbp, fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelMinus* nodep, AstNUser*) {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
iterateSelTriop(nodep);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
V3Number one (msbp->fileline(),32,1); one.width(32,false); // Unsized so width from user
AstSel* newp = new AstSel
(nodep->fileline(),
fromp,
newSubAttrOf(new AstSub (msbp->fileline(),
msbp,
new AstSub (msbp->fileline(),
widthp->cloneTree(true),
new AstConst (msbp->fileline(), one))),
fromp, AstAttrType::RANGE_LSB),
widthp);
selCheckDimension(newp);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
@@ -361,7 +234,7 @@ private:
inPct = true;
} else if (inPct) {
inPct = false;
switch (ch) {
switch (tolower(ch)) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9':
inPct = true;
@@ -441,7 +314,8 @@ private:
nodep->v3error(nodep->verilogKwd()+" only allowed under a assertion.");
}
if (nodep->displayType().needScopeTracking()
|| nodep->name().find("%m") != string::npos) {
|| nodep->name().find("%m") != string::npos
|| nodep->name().find("%M") != string::npos) {
nodep->scopeNamep(new AstScopeName(nodep->fileline()));
}
}
+1 -1
View File
@@ -69,7 +69,7 @@ protected:
};
uint32_t m_flags;
VarFlags(AstNode* nodep) { m_flags = nodep->user2(); }
void setNodeFlags(AstNode* nodep) { nodep->user2(m_flags); };
void setNodeFlags(AstNode* nodep) { nodep->user2(m_flags); }
};
};
+28 -23
View File
@@ -34,6 +34,7 @@
#include "V3Global.h"
#include "V3Name.h"
#include "V3Ast.h"
#include "V3LanguageWords.h"
//######################################################################
// Name state, as a visitor of each AstNode
@@ -45,14 +46,11 @@ private:
// AstCell::user1() -> bool. Set true if already processed
// AstScope::user1() -> bool. Set true if already processed
// AstVar::user1() -> bool. Set true if already processed
//
// AstCell::user2() -> bool. Set true if was privitized
// AstVar::user2() -> bool. Set true if was privitized
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
AstModule* m_modp;
V3LanguageWords m_words; // Reserved word detector
// METHODS
static int debug() {
@@ -61,6 +59,23 @@ private:
return level;
}
void rename(AstNode* nodep, bool addPvt) {
if (!nodep->user1()) { // Not already done
if (addPvt) {
string newname = (string)"__PVT__"+nodep->name();
nodep->name(newname);
} else {
string rsvd = m_words.isKeyword(nodep->name());
if (rsvd != "") {
nodep->v3warn(SYMRSVDWORD,"Symbol matches "+rsvd+": '"<<nodep->name()<<"'");
string newname = (string)"__SYM__"+nodep->name();
nodep->name(newname);
}
}
nodep->user1(1);
}
}
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
m_modp = nodep;
@@ -70,16 +85,13 @@ private:
// Add __PVT__ to names of local signals
virtual void visit(AstVar* nodep, AstNUser*) {
// Don't iterate... Don't need temps for RANGES under the Var.
if (!nodep->user1()
&& !m_modp->isTop()
&& !nodep->isSigPublic()
&& !nodep->isTemp()) { // Don't bother to rename internal signals
// Change the name to something private...
string newname = (string)"__PVT__"+nodep->name();
nodep->name(newname);
nodep->user1(1);
nodep->user2(1);
}
rename(nodep, (!m_modp->isTop()
&& !nodep->isSigPublic()
&& !nodep->isTemp())); // Don't bother to rename internal signals
}
virtual void visit(AstCFunc* nodep, AstNUser*) {
nodep->iterateChildren(*this);
rename(nodep, false);
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (nodep->varp()) {
@@ -88,14 +100,7 @@ private:
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
if (!nodep->user1()
&& !nodep->modp()->modPublic()) {
// Change the name to something private...
string newname = (string)"__PVT__"+nodep->name();
nodep->name(newname);
nodep->user1(1);
nodep->user2(1);
}
rename(nodep, !nodep->modp()->modPublic());
nodep->iterateChildren(*this);
}
virtual void visit(AstScope* nodep, AstNUser*) {
@@ -117,7 +122,7 @@ private:
}
public:
// CONSTUCTORS
NameVisitor(AstNode* nodep) {
NameVisitor(AstNetlist* nodep) {
nodep->accept(*this);
}
virtual ~NameVisitor() {}
+164 -25
View File
@@ -131,31 +131,43 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
// Convert decimal number to hex
int olen = 0;
uint32_t val = 0;
for (const char* cp=value_startp;
*cp; cp++) {
int got_x = 0;
int got_z = 0;
int got_01 = 0;
for (const char* cp=value_startp; *cp; cp++) {
switch (tolower(*cp)) {
case '0': case '1': case '2': case '3': case '4':
case '5': case '6': case '7': case '8': case '9': {
val = val*10 + (*cp-'0');
m_value[0] = val;
if (width()>32 && olen>7/*10000000 fits in 32 bits, so ok*/) {
m_fileline->v3error("Unsupported: Conversion of decimal number over 32 bits, use hex\n");
olen=0;
if (olen<=7) { // 10000000 fits in 32 bits, so ok
// Constants are common, so for speed avoid wide math until we need it
val = val*10 + (*cp-'0');
m_value[0] = val;
} else { // Wide; all previous digits are already in m_value[0]
// this = (this * 10)/*product*/ + (*cp-'0')/*addend*/
// Assumed rare; lots of optimizations are possible here
V3Number product (fileline, width()+4); // +4 for overflow detection
V3Number ten (fileline, width()+4, 10);
V3Number addend (fileline, width(), (*cp-'0'));
product.opMul(*this,ten);
this->opAdd(product,addend);
if (product.bitsValue(width(), 4)) { // Overflowed
m_fileline->v3error("Too many digits for "<<width()<<" bit number: "<<sourcep);
while (*(cp+1)) cp++; // Skip ahead so don't get multiple warnings
}
}
olen++;
got_01 = 1;
break;
}
case 'z': case '?': {
if (olen) m_fileline->v3error("Multi-digit X/Z/? not legal in decimal constant: "<<*cp);
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
olen++;
setAllBitsZ();
got_z = 1;
break;
}
case 'x': {
if (olen) m_fileline->v3error("Multi-digit X/Z/? not legal in decimal constant: "<<*cp);
if (!m_sized) m_fileline->v3error("Unsized X/Z/? not legal in decimal constant: "<<*cp);
olen++;
got_x = 1;
setAllBitsX();
break;
}
@@ -167,6 +179,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
}
}
obit = width();
if ((got_01+got_x+got_z)>1) m_fileline->v3error("Mixing X/Z/? with digits not legal in decimal constant: "<<value_startp);
}
else {
// Convert bin/octal number to hex
@@ -174,7 +187,7 @@ V3Number::V3Number (FileLine* fileline, const char* sourcep) {
(cp>=value_startp
&& obit<=width());
cp--) {
if (*cp!='_' && obit>=width()) {
if (*cp!='_' && *cp!='0' && obit>=width()) {
m_fileline->v3error("Too many digits for "<<width()<<" bit number: "<<sourcep);
break;
}
@@ -232,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;
@@ -1074,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
@@ -1120,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();
@@ -1172,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() {
@@ -1182,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++) {
+6 -4
View File
@@ -42,12 +42,12 @@ class V3Number {
vector<uint32_t> m_valueX; // Each bit is true if it's X or Z, 10=z, 11=x
// METHODS
void init(FileLine* fileline, int width);
V3Number& setZero();
V3Number& setSingleBits(char value);
void opCleanThis();
public:
FileLine* fileline() const { return m_fileline; }
void fileline(FileLine* fl) { m_fileline=fl; }
V3Number& setZero();
V3Number& setQuad(vluint64_t value);
V3Number& setLong(uint32_t value);
void setBit (int bit, char value) { // Note must be pre-zeroed!
@@ -104,11 +104,13 @@ 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
V3Number(FileLine* fileline) { init(fileline, 1); }
V3Number(FileLine* fileline, int width) { init(fileline, width); }; // 0=unsized
V3Number(FileLine* fileline, int width) { init(fileline, width); } // 0=unsized
V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; }
V3Number(FileLine* fileline, const char* source); // Create from a verilog 32'hxxxx number.
V3Number(VerilogString, FileLine* fileline, const string& vvalue);
@@ -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);
+60 -28
View File
@@ -369,43 +369,32 @@ string V3Options::getenvSYSTEMPERLGuts() {
var = DEFENV_SYSTEMPERL;
setenvStr("SYSTEMPERL", var, "Hardcoded at build time");
}
// Only correct or check it if we really need the value
if (v3Global.opt.usingSystemPerlLibs()) {
if (var == "") {
string testdir = V3Options::getenvW() + "/hw/utils/perltools/SystemC"; // Hack for internal testing
if (V3Options::fileStatDir(testdir)) {
var = testdir;
setenvStr ("SYSTEMPERL", var, "From W");
}
}
// Test for correctness in SYSTEMPERL_INCLUDE
}
return var;
}
string V3Options::getenvSYSTEMPERL_INCLUDE() {
string var = getenvStr("SYSTEMPERL_INCLUDE","");
if (var == "" && string(DEFENV_SYSTEMPERL_INCLUDE) != "") {
// Note if SYSTEMPERL is DEFENVed, then SYSTEMPERL_INCLUDE is also DEFENVed
// So we don't need to sweat testing SYSTEMPERL also
var = DEFENV_SYSTEMPERL_INCLUDE;
setenvStr("SYSTEMPERL_INCLUDE", var, "Hardcoded at build time");
if (var == "") {
string sp_src = V3Options::getenvSYSTEMPERLGuts()+"/src";
if (V3Options::fileStatNormal(sp_src+"/systemperl.h")) {
var = sp_src;
setenvStr ("SYSTEMPERL_INCLUDE", var, "From $SYSTEMPERL/src");
} else if (string(DEFENV_SYSTEMPERL_INCLUDE) != "") {
// Note if SYSTEMPERL is DEFENVed, then SYSTEMPERL_INCLUDE is also DEFENVed
// So we don't need to sweat testing DEFENV_SYSTEMPERL also
var = DEFENV_SYSTEMPERL_INCLUDE;
setenvStr("SYSTEMPERL_INCLUDE", var, "Hardcoded at build time");
}
}
// Only correct or check it if we really need the value
if (v3Global.opt.usingSystemPerlLibs()) {
if (var == "") {
string sp = V3Options::getenvSYSTEMPERLGuts();
var = sp+"/src";
setenvStr ("SYSTEMPERL_INCLUDE", var, "From $SYSTEMPERL/src");
}
// We warn about $SYSTEMPERL instead of _INCLUDE since that's more likely
// what users will want to set.
if (var == "") {
v3fatal("Need $SYSTEMPERL in environment for --sp or --trace\n"
v3fatal("Need $SYSTEMPERL and $SYSTEMPERL_INCLUDE in environment for --sp or --trace\n"
"Probably System-Perl isn't installed, see http://www.veripool.org/systemperl\n");
}
if (var != ""
&& !V3Options::fileStatNormal(var+"/systemperl.h")) {
else if (var != "" && !V3Options::fileStatNormal(var+"/systemperl.h")) {
v3fatal("Neither $SYSTEMPERL nor $SYSTEMPERL_INCLUDE environment vars to point to System-Perl kit: "<<var<<endl);
}
}
@@ -588,7 +577,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
}
else if ( !strcmp (sw, "-error-limit") ) {
shift;
m_inlineMult = atoi(argv[i]);
m_errorLimit = atoi(argv[i]);
}
else if ( !strcmp (sw, "-inline-mult") ) {
shift;
@@ -635,9 +624,12 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
shift;
V3Options::addLibraryFile(filenameSubstitute(argv[i]));
}
else if ( !strcmp (sw, "-V") ) {
showVersion(true);
exit(0);
}
else if ( !strcmp (sw, "-version") ) {
cout <<version();
cout <<endl;
showVersion(false);
exit(0);
}
// Single switches
@@ -646,6 +638,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( onoff (sw, "-MP", flag/*ref*/) ) { m_makePhony = flag; }
else if ( onoff (sw, "-assert", flag/*ref*/) ) { m_assert = flag; m_psl = flag; }
else if ( onoff (sw, "-autoflush", flag/*ref*/) ) { m_autoflush = flag; }
else if ( onoff (sw, "-bbox-sys", flag/*ref*/) ) { m_bboxSys = flag; }
else if ( !strcmp (sw, "-cc") ) { m_outFormatOk = true; m_systemC = false; m_systemPerl = false; }
else if ( onoff (sw, "-coverage", flag/*ref*/) ) { coverage(flag); }
else if ( onoff (sw, "-coverage-line", flag/*ref*/) ){ m_coverageLine = flag; }
@@ -661,6 +654,7 @@ void V3Options::parseOptsList(FileLine* fl, int argc, char** argv) {
else if ( onoff (sw, "-lint-only", flag/*ref*/) ) { m_lintOnly = flag; }
else if ( !strcmp (sw, "-no-pins64") ) { m_pinsBv = 33; }
else if ( !strcmp (sw, "-pins64") ) { m_pinsBv = 65; }
else if ( onoff (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
else if ( !strcmp (sw, "-private") ) { m_public = false; }
else if ( onoff (sw, "-profile-cfuncs", flag/*ref*/) ) { m_profileCFuncs = flag; }
else if ( onoff (sw, "-psl", flag/*ref*/) ) { m_psl = flag; }
@@ -775,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];
}
@@ -897,6 +894,41 @@ void V3Options::parseOptsFile(FileLine* fl, const string& filename) {
//======================================================================
void V3Options::showVersion(bool verbose) {
cout <<version();
cout <<endl;
if (!verbose) return;
cout <<endl;
cout << "Copyright 2003-2009 by Wilson Snyder. Verilator is free software; you can\n";
cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
cout << "License Version 2.0.\n";
cout <<endl;
cout << "See http://www.veripool.org/verilator for documentation\n";
cout <<endl;
cout << "Summary of configuration:\n";
cout << " Compiled in defaults if not in environment:\n";
cout << " SYSTEMC = " << DEFENV_SYSTEMC<<endl;
cout << " SYSTEMC_ARCH = " << DEFENV_SYSTEMC_ARCH<<endl;
cout << " SYSTEMPERL = " << DEFENV_SYSTEMPERL<<endl;
cout << " SYSTEMPERL_INCLUDE = " << DEFENV_SYSTEMPERL_INCLUDE<<endl;
cout << " VERILATOR_ROOT = " << DEFENV_VERILATOR_ROOT<<endl;
cout <<endl;
cout << "Environment:\n";
cout << " PERL = " << getenvStr("PERL","")<<endl;
cout << " SYSTEMC = " << getenvStr("SYSTEMC","")<<endl;
cout << " SYSTEMC_ARCH = " << getenvStr("SYSTEMC_ARCH","")<<endl;
cout << " SYSTEMPERL = " << getenvStr("SYSTEMPERL","")<<endl;
cout << " SYSTEMPERL_INCLUDE = " << getenvStr("SYSTEMPERL_INCLUDE","")<<endl;
cout << " VERILATOR_ROOT = " << getenvStr("VERILATOR_ROOT","")<<endl;
}
//======================================================================
V3Options::V3Options() {
m_impp = new V3OptionsImp;
@@ -933,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;
+11 -5
View File
@@ -60,11 +60,11 @@ public:
bool legal() const { return m_e != ERROR; }
//
enum en m_e;
inline V3LangCode () : m_e(ERROR) {};
inline V3LangCode (en _e) : m_e(_e) {};
inline V3LangCode () : m_e(ERROR) {}
inline V3LangCode (en _e) : m_e(_e) {}
V3LangCode (const char* textp); // Return matching code or ERROR
explicit inline V3LangCode (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
explicit inline V3LangCode (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
//######################################################################
@@ -94,6 +94,7 @@ class V3Options {
bool m_makePhony; // main switch: -MP
bool m_assert; // main switch: --assert
bool m_autoflush; // main switch: --autoflush
bool m_bboxSys; // main switch: --bbox-sys
bool m_coverageLine; // main switch: --coverage-block
bool m_coverageToggle;// main switch: --coverage-toggle
bool m_coverageUser; // main switch: --coverage-func
@@ -105,6 +106,7 @@ class V3Options {
bool m_l2Name; // main switch: --l2name
bool m_lintOnly; // main switch: --lint-only
bool m_outFormatOk; // main switch: --cc, --sc or --sp was specified
bool m_pinsUint8; // main switch: --pins-uint8
bool m_profileCFuncs;// main switch: --profile-cfuncs
bool m_psl; // main switch: --psl
bool m_public; // main switch: --public
@@ -166,8 +168,10 @@ class V3Options {
void addIncDir(const string& incdir);
void addLibExt(const string& libext);
void optimize(int level);
void showVersion(bool verbose);
void coverage(bool flag) { m_coverageLine = m_coverageToggle = m_coverageUser = flag; }
bool onoff(const char* sw, const char* arg, bool& flag);
static bool wildmatchi(const char* s, const char* p);
static string getenvStr(const string& envvar, const string& defaultValue);
static void setenvStr(const string& envvar, const string& value, const string& why);
@@ -201,6 +205,7 @@ class V3Options {
bool stats() const { return m_stats; }
bool assertOn() const { return m_assert; } // assertOn as __FILE__ may be defined
bool autoflush() const { return m_autoflush; }
bool bboxSys() const { return m_bboxSys; }
bool coverage() const { return m_coverageLine || m_coverageToggle || m_coverageUser; }
bool coverageLine() const { return m_coverageLine; }
bool coverageToggle() const { return m_coverageToggle; }
@@ -212,6 +217,7 @@ class V3Options {
bool traceDups() const { return m_traceDups; }
bool outFormatOk() const { return m_outFormatOk; }
bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
bool pinsUint8() const { return m_pinsUint8; }
bool profileCFuncs() const { return m_profileCFuncs; }
bool psl() const { return m_psl; }
bool allPublic() const { return m_public; }
@@ -290,13 +296,13 @@ class V3Options {
// METHODS (environment)
// Most of these may be built into the executable with --enable-defenv,
// see the README. If adding new variables, also see src/Makefile_obj.in
// Also add to V3Options::showVersion()
static string getenvPERL() { return getenvStr("PERL","perl"); }
static string getenvSYSTEMC();
static string getenvSYSTEMC_ARCH();
static string getenvSYSTEMPERL();
static string getenvSYSTEMPERL_INCLUDE();
static string getenvVERILATOR_ROOT();
static string getenvW() { return getenvStr("W",""); }
// METHODS (file utilities using these options)
string fileExists (const string& filename);
+3 -2
View File
@@ -432,7 +432,7 @@ private:
}
virtual void visit(AstTopScope* nodep, AstNUser*) {
// Process the last thing we're finishing
if (m_topScopep) nodep->v3fatalSrc("Only one topscope supported");
if (m_topScopep) nodep->v3fatalSrc("Only one topscope should ever be created");
UINFO(2," Loading tree...\n");
//VV***** We reset userp()
AstNode::user1ClearTree();
@@ -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) {
+5 -5
View File
@@ -103,12 +103,12 @@ struct OrderVEdgeType {
};
return names[m_e];
};
}
enum en m_e;
inline OrderVEdgeType () {};
inline OrderVEdgeType (en _e) : m_e(_e) {};
explicit inline OrderVEdgeType (int _e) : m_e(static_cast<en>(_e)) {};
operator en () const { return m_e; };
inline OrderVEdgeType () {}
inline OrderVEdgeType (en _e) : m_e(_e) {}
explicit inline OrderVEdgeType (int _e) : m_e(static_cast<en>(_e)) {}
operator en () const { return m_e; }
};
inline bool operator== (OrderVEdgeType lhs, OrderVEdgeType rhs) { return (lhs.m_e == rhs.m_e); }
inline bool operator== (OrderVEdgeType lhs, OrderVEdgeType::en rhs) { return (lhs.m_e == rhs); }
+32 -11
View File
@@ -55,7 +55,9 @@ private:
// NODE STATE
// AstModule::user4() // bool True if parameters numbered
// AstVar::user4() // int Global parameter number (for naming new module)
// // (0=not processed, 1=iterated, but no number, 65+ parameter numbered)
AstUser4InUse m_inuser4;
// User1/2/3 used by constant function simulations
// STATE
typedef std::map<AstVar*,AstVar*> VarCloneMap;
@@ -93,7 +95,7 @@ private:
}
}
string paramSmallName(AstModule* modp, AstVar* varp) {
if (!varp->user4()) {
if (varp->user4()<=1) {
makeSmallNames(modp);
}
int index = varp->user4()/256;
@@ -127,6 +129,22 @@ private:
}
virtual void visit(AstCell* nodep, AstNUser*);
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
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*) {
if (debug()>=9) nodep->dumpTree(cout,"-genin: ");
@@ -143,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()
@@ -157,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");
}
@@ -164,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;
}
}
@@ -234,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.
+12 -4
View File
@@ -26,6 +26,8 @@
#ifndef _VPREPROCLEX_H_ // Guard
#define _VPREPROCLEX_H_ 1
#include <stack>
#include "V3Error.h"
// Token codes
@@ -105,7 +107,7 @@ class V3PreLex {
// Parse state
FILE* m_fp; // File state is for
YY_BUFFER_STATE m_yyState; // flex input state
stack<YY_BUFFER_STATE> m_bufferStack; // Stack of inserted text above current point
// State to lexer
static V3PreLex* s_currentLexp; // Current lexing point
@@ -121,14 +123,18 @@ class V3PreLex {
// CONSTRUCTORS
V3PreLex(FILE* fp) {
m_fp = fp;
m_yyState = yy_create_buffer (fp, YY_BUF_SIZE);
m_keepComments = 0;
m_pedantic = false;
m_parenLevel = 0;
m_pslParenLevel = 0;
m_pslMoreNeeded = false;
m_bufferStack.push(yy_create_buffer (fp, YY_BUF_SIZE));
yy_switch_to_buffer(m_bufferStack.top());
}
~V3PreLex() {
fclose(m_fp);
while (!m_bufferStack.empty()) { yy_delete_buffer(m_bufferStack.top()); m_bufferStack.pop(); }
}
~V3PreLex() { fclose(m_fp); yy_delete_buffer(m_yyState); }
// Called by V3PreLex.l from lexer
void appendDefValue(const char* text, int len);
@@ -139,9 +145,11 @@ class V3PreLex {
void pushStateDefForm();
void pushStateDefValue();
void pushStateIncFilename();
void unputString(const char* textp);
void scanBytes(const string& strg);
/// Called by VPreproc.cpp to get data from lexer
YY_BUFFER_STATE currentBuffer();
int currentStartState();
void dumpStack();
};
#endif // Guard
+29 -11
View File
@@ -1,4 +1,3 @@
/* -*- C++ -*- */
/**************************************************************************
* DESCRIPTION: Verilator: Flex verilog preprocessor
*
@@ -69,7 +68,7 @@ wsn [ \t\f]
crnl [\r]*[\n]
quote [\"]
backslash [\\]
symb [a-zA-Z_][a-zA-Z0-9_$]*
symb ([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
drop [\032]
psl [p]sl
@@ -108,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);
@@ -131,6 +131,7 @@ psl [p]sl
/* Note '(' must IMMEDIATELY follow definition name */
<DEFFPAR>[(] { appendDefValue("(",1); BEGIN(DEFFORM); }
<DEFFPAR>{crnl} { yy_pop_state(); unput('\n'); yyleng=0; return VP_DEFFORM; } /* DEFVAL will later grab the return */
<DEFFPAR><<EOF>> { yy_pop_state(); return VP_DEFFORM; } /* empty formals */
<DEFFPAR>. { yy_pop_state(); unput(yytext[yyleng-1]); yyleng=0; return VP_DEFFORM; } /* empty formals */
/* Reading definition formals */
@@ -204,7 +205,6 @@ psl [p]sl
<PSLONEM>[{(] { pslParenLevelInc(); return (VP_TEXT); }
<PSLONEM>[})] { pslParenLevelDec(); return (VP_TEXT); }
<PSLONEM>[;] { if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
<PSLONEM><<EOF>> { yyerrorf("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
<PSLONEM>{crnl} { linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
/* Completed psl oneline comments */
@@ -224,16 +224,17 @@ psl [p]sl
<CMTMODE>. { yymore(); }
/* Psl C-style comments. */
/* EOFs are normal because / * `foo(..) * / hits a unputString EOF */
<PSLMUL1>.|{crnl} { yyless(0); BEGIN PSLMULM; return(VP_PSL); }
<PSLMULM>"*/" { yy_pop_state(); return(VP_COMMENT); }
<PSLMULM>"//"[^\n\r]* { return (VP_COMMENT); } /* Comments inside block comments get literal inclusion (later removal) */
<PSLMULM><<EOF>> { yyerrorf("EOF in '/* ... */' psl comment\n"); yyleng=0; yyterminate(); }
/* Define calls */
<INITIAL,PSLMULM,PSLONEM>"`"{symb} { return (VP_DEFREF); }
/* Generics */
<INITIAL,PSLMULM>{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM><<EOF>> { yyterminate(); } /* A "normal" EOF */
<INITIAL,PSLMULM,PSLONEM>{symb} { return (VP_SYMBOL); }
<INITIAL,PSLMULM,PSLONEM>{wsn}+ { return (VP_WHITE); }
<INITIAL,PSLMULM,PSLONEM>{drop} { }
@@ -268,13 +269,9 @@ void V3PreLex::pushStateIncFilename() {
yymore();
}
void V3PreLex::unputString(const char* textp) {
// Add characters to input stream in back-to-front order
const char* cp;
for (cp = textp; *cp; cp++);
for (cp--; cp >= textp; cp--) {
unput(*cp);
}
void V3PreLex::scanBytes(const string& strg) {
yy_scan_bytes(strg.c_str(), strg.length());
m_bufferStack.push(currentBuffer()); // yy_scan_bytes makes new buffer
}
void V3PreLex::appendDefValue(const char* textp, int len) {
@@ -282,6 +279,10 @@ void V3PreLex::appendDefValue(const char* textp, int len) {
m_defValue.append(textp,len);
}
YY_BUFFER_STATE V3PreLex::currentBuffer() {
return YY_CURRENT_BUFFER;
}
int V3PreLex::currentStartState() {
return YY_START;
}
@@ -291,3 +292,20 @@ void V3PreLex::lineDirective(const char* textp) {
// Make sure we have a dependency on whatever file was specified
V3File::addSrcDepend(m_curFilelinep->filename());
}
void V3PreLex::dumpStack() {
// For debug use
stack<YY_BUFFER_STATE> tmpstack = m_bufferStack;
printf(" bufferStack[%p]:",this);
while (!tmpstack.empty()) {
printf(" %p",tmpstack.top());
tmpstack.pop();
}
printf("\n");
}
/*###################################################################
* Local Variables:
* mode: C++
* End:
*/
+42 -14
View File
@@ -160,6 +160,7 @@ private:
bool commentTokenMatch(string& cmdr, const char* strg);
string trimWhitespace(const string& strg);
void unputString(const string& strg);
void parsingOn() {
m_off--;
@@ -386,6 +387,18 @@ const char* V3PreProcImp::tokenName(int tok) {
}
}
void V3PreProcImp::unputString(const string& strg) {
// We used to just m_lexp->unputString(strg.c_str());
// However this can lead to "flex scanner push-back overflow"
// so instead we scan from a temporary buffer, then on EOF return.
// This is also faster than the old scheme, amazingly.
if (m_lexp->m_bufferStack.empty() || m_lexp->m_bufferStack.top()!=m_lexp->currentBuffer()) {
fileline()->v3fatalSrc("bufferStack missing current buffer; will return incorrectly");
// Hard to debug lost text as won't know till much later
}
m_lexp->scanBytes(strg);
}
string V3PreProcImp::trimWhitespace(const string& strg) {
string out = strg;
while (out.length()>0 && isspace(out[0])) {
@@ -535,7 +548,6 @@ void V3PreProcImp::openFile(FileLine* fl, const string& filename) {
addLineComment(1); // Enter
yy_flex_debug = (debug()>4)?1:0;
yy_switch_to_buffer(m_lexp->m_yyState);
}
void V3PreProcImp::insertUnreadbackAtBol(const string& text) {
@@ -560,16 +572,27 @@ void V3PreProcImp::addLineComment(int enter_exit_level) {
}
void V3PreProcImp::eof() {
// Remove current lexer
UINFO(4,fileline()<<"EOF!\n");
addLineComment(2); // Exit
delete m_lexp; m_lexp=NULL;
// Perhaps there's a parent file including us?
if (!m_includeStack.empty()) {
// Back to parent.
m_lexp = m_includeStack.top(); m_includeStack.pop();
addLineComment(0);
yy_switch_to_buffer(m_lexp->m_yyState);
// Perhaps we're completing unputString
if (m_lexp->m_bufferStack.size()>1) {
UINFO(4,fileline()<<"EOS\n");
// Switch to file or next unputString, but not a eof so don't delete lexer
yy_delete_buffer(m_lexp->currentBuffer());
m_lexp->m_bufferStack.pop(); // Must work as size>1
yy_switch_to_buffer(m_lexp->m_bufferStack.top());
} else {
// Remove current lexer
UINFO(4,fileline()<<"EOF!\n");
addLineComment(2); // Exit
// Destructor will call yy_delete_buffer
delete m_lexp; m_lexp=NULL;
// Perhaps there's a parent file including us?
if (!m_includeStack.empty()) {
// Back to parent.
m_lexp = m_includeStack.top(); m_includeStack.pop();
addLineComment(0);
if (m_lexp->m_bufferStack.empty()) fileline()->v3fatalSrc("No include buffer to return to");
yy_switch_to_buffer(m_lexp->m_bufferStack.top()); // newest buffer in older lexer
}
}
}
@@ -794,6 +817,7 @@ int V3PreProcImp::getToken() {
if (m_defRefs.empty()) v3fatalSrc("Shouldn't be in DEFARG w/o active defref");
V3DefineRef* refp = &(m_defRefs.top());
refp->nextarg(refp->nextarg()+m_lexp->m_defValue); m_lexp->m_defValue="";
UINFO(4,"defarg++ "<<refp->nextarg()<<endl);
if (tok==VP_DEFARG && yyleng==1 && yytext[0]==',') {
refp->args().push_back(refp->nextarg());
m_state = ps_DEFARG;
@@ -806,13 +830,17 @@ int V3PreProcImp::getToken() {
// Substitute in and prepare for next action
// Similar code in non-parenthesized define (Search for END_OF_DEFARG)
m_defRefs.pop();
m_lexp->unputString(out.c_str());
if (m_defRefs.empty()) {
unputString(out.c_str());
m_state = ps_TOP;
m_lexp->m_parenLevel = 0;
}
else { // Finished a defref inside a upper defref
// Can't subst now, or
// `define a(ign) x,y
// foo(`a(ign),`b) would break because a contains comma
refp = &(m_defRefs.top()); // We popped, so new top
refp->nextarg(refp->nextarg()+m_lexp->m_defValue+out); m_lexp->m_defValue="";
m_lexp->m_parenLevel = refp->parenLevel();
m_state = ps_DEFARG;
}
@@ -936,7 +964,7 @@ int V3PreProcImp::getToken() {
// Similar code in parenthesized define (Search for END_OF_DEFARG)
if (m_defRefs.empty()) {
// Just output the substitution
m_lexp->unputString(out.c_str());
unputString(out.c_str());
} else {
// Inside another define. Can't subst now, or
// `define a x,y
@@ -990,7 +1018,7 @@ int V3PreProcImp::getToken() {
string V3PreProcImp::getline() {
// Get a single line from the parse stream. Buffer unreturned text until the newline.
if (isEof()) return "";
char* rtnp;
const char* rtnp;
bool gotEof = false;
while (NULL==(rtnp=strchr(m_lineChars.c_str(),'\n')) && !gotEof) {
int tok = getToken();
+1 -1
View File
@@ -83,7 +83,7 @@ protected:
};
public:
static V3PreProc* createPreProc(FileLine* fileline);
virtual ~V3PreProc() {};
virtual ~V3PreProc() {}
};
#endif // Guard
+3 -6
View File
@@ -306,17 +306,15 @@ private:
public:
// CONSTUCTORS
PremitVisitor() {
PremitVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_funcp = NULL;
m_stmtp = NULL;
m_inWhilep = NULL;
m_inTracep = NULL;
}
virtual ~PremitVisitor() {}
void main(AstNode* nodep) {
nodep->accept(*this);
}
virtual ~PremitVisitor() {}
};
//----------------------------------------------------------------------
@@ -327,6 +325,5 @@ public:
void V3Premit::premitAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
PremitVisitor visitor;
visitor.main(nodep);
PremitVisitor visitor (nodep);
}
+1 -1
View File
@@ -103,7 +103,7 @@ public: // But for internal use only
}
// Return next token, for bison, since bison isn't class based, use a global THIS
static int yylex() { return s_readp->yylexThis(); };
static int yylex() { return s_readp->yylexThis(); }
static FileLine* fileline() { return s_readp->m_fileline; }
static AstNetlist* rootp() { return s_readp->m_rootp; }
static FileLine* copyOrSameFileLine() { return s_readp->fileline()->copyOrSameFileLine(); }
+2 -2
View File
@@ -237,7 +237,7 @@ private:
}
public:
// CONSTUCTORS
ScopeVisitor(AstNode* nodep) {
ScopeVisitor(AstNetlist* nodep) {
m_aboveCellp = NULL;
m_aboveScopep = NULL;
m_modp = NULL;
@@ -313,7 +313,7 @@ private:
}
public:
// CONSTUCTORS
ScopeCleanupVisitor(AstNode* nodep) {
ScopeCleanupVisitor(AstNetlist* nodep) {
m_scopep = NULL;
nodep->accept(*this);
}
+24 -11
View File
@@ -161,6 +161,13 @@ private:
// so, it's just
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
if (!nodep->castGenIf()) { // for m_paramsOnly
nodep->ifsp()->iterateAndNext(*this);
nodep->elsesp()->iterateAndNext(*this);
}
nodep->condp()->iterateAndNext(*this);
}
virtual void visit(AstPin* nodep, AstNUser*) {
// Same as above taskref argument.
nodep->iterateChildren(*this);
@@ -179,7 +186,7 @@ private:
if (!inPct && ch=='%') {
inPct = true;
} else if (inPct && isdigit(ch)) {
} else if (inPct) {
} else if (tolower(inPct)) {
inPct = false;
switch (tolower(ch)) {
case '%': break; // %% - just output a %
@@ -352,12 +359,14 @@ private:
public:
// CONSTRUCTORS
SignedVisitor(AstNode* nodep, bool paramsOnly) {
SignedVisitor(bool paramsOnly) {
m_paramsOnly = paramsOnly;
m_taskDepth = 0;
nodep->accept(*this);
}
virtual ~SignedVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
@@ -384,10 +393,11 @@ private:
}
public:
// CONSTRUCTORS
SignedRemoveVisitor(AstNode* nodep) {
nodep->accept(*this);
}
SignedRemoveVisitor() {}
virtual ~SignedRemoveVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
};
//######################################################################
@@ -395,12 +405,15 @@ public:
void V3Signed::signedAll(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
SignedVisitor visitor (nodep, false);
SignedRemoveVisitor rvisitor (nodep);
(void)signedParamsEdit(nodep);
}
void V3Signed::signedParams(AstNode* nodep) {
AstNode* V3Signed::signedParamsEdit(AstNode* nodep) {
// Only called from V3Width::widthParamsEdit
UINFO(4,__FUNCTION__<<": "<<endl);
SignedVisitor visitor (nodep, true);
SignedRemoveVisitor rvisitor (nodep);
SignedVisitor visitor (true);
nodep = visitor.mainAcceptEdit(nodep);
SignedRemoveVisitor rvisitor;
nodep = rvisitor.mainAcceptEdit(nodep);
return nodep;
}
+3 -1
View File
@@ -32,7 +32,9 @@
class V3Signed {
public:
static void signedAll(AstNetlist* nodep);
static void signedParams(AstNode* nodep);
protected:
friend class V3Width; // Use widthParamsEdit instead of signedParamsEdit
static AstNode* signedParamsEdit(AstNode* nodep); // May replace nodep
};
#endif // Guard
+600
View File
@@ -0,0 +1,600 @@
// -*- C++ -*-
//*************************************************************************
// DESCRIPTION: Verilator: Simulate code to determine output values/variables
//
// 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.
//
//*************************************************************************
//
// void example_usage() {
// SimulateVisitor simvis (false, false);
// simvis.clear();
// // Set all inputs to the constant
// for (deque<AstVarScope*>::iterator it = m_inVarps.begin(); it!=m_inVarps.end(); ++it) {
// simvis.newNumber(invscp, #);
// }
// // Simulate
// simvis.main(nodep);
// // Read outputs
// for (deque<AstVarScope*>::iterator it = m_outVarps.begin(); it!=m_outVarps.end(); ++it) {
// V3Number* outnump = simvis.fetchOutNumberNull(outvscp);
//
//*************************************************************************
#ifndef _V3SIMULATE_H_
#define _V3SIMULATE_H_ 1
#include "config_build.h"
#include "verilatedos.h"
#include "V3Error.h"
#include "V3Ast.h"
#include "V3Width.h"
//============================================================================
//######################################################################
// Simulate class functions
class SimulateVisitor : public AstNVisitor {
// Simulate a node tree, returning value of variables
// Two major operating modes:
// Test the tree to see if it is conformant
// Given a set of input values, find the output values
// Both are done in this same visitor to reduce risk; if a visitor
// is missing, we will simply not apply the optimization, rather then bomb.
private:
// NODE STATE
// Cleared on each always/assignw
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
// Checking:
// AstVarScope::user1() -> VarUsage. Set true to indicate tracking as lvalue/rvalue
// Simulating:
// AstVarScope::user3() -> V3Number*. Input value of variable or node (and output for non-delayed assignments)
// AstVarScope::user2() -> V3Number*. Output value of variable (delayed assignments)
enum VarUsage { VU_NONE=0, VU_LV=1, VU_RV=2, VU_LVDLY=4 };
// STATE
// Major mode
bool m_checkOnly; ///< Checking only (no simulation) mode
bool m_scoped; ///< Running with AstVarScopes instead of AstVars
bool m_params; ///< Doing parameter propagation
// Checking:
string m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
AstNode* m_whyNotNodep; ///< First node not optimizable
bool m_anyAssignDly; ///< True if found a delayed assignment
bool m_anyAssignComb; ///< True if found a non-delayed assignment
bool m_inDlyAssign; ///< Under delayed assignment
int m_instrCount; ///< Number of nodes
int m_dataCount; ///< Bytes of data
// Simulating:
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
// Note level 8&9 include debugging each simulation value
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
// Checking METHODS
public:
/// Call other-this function on all new var references
virtual void varRefCb(AstVarRef* nodep) {}
void clearOptimizable(AstNode* nodep/*null ok*/, const string& why) {
// Something bad found. optimizable() will return false,
// and fetchNumber should not be called or it may assert.
if (!m_whyNotNodep) {
m_whyNotNodep = nodep;
if (debug()>=5) {
UINFO(0,"Clear optimizable: "<<why);
if (nodep) cout<<": "<<nodep;
cout<<endl;
}
m_whyNotOptimizable = why;
}
}
inline bool optimizable() const { return m_whyNotNodep==NULL; }
string whyNotMessage() const { return m_whyNotOptimizable; }
AstNode* whyNotNodep() const { return m_whyNotNodep; }
bool isAssignDly() const { return m_anyAssignDly; }
int instrCount() const { return m_instrCount; }
int dataCount() const { return m_dataCount; }
// Simulation METHODS
private:
V3Number* allocNumber(AstNode* nodep, uint32_t value) {
// Save time - kept a list of allocated but unused V3Numbers
// It would be more efficient to do this by size, but the extra accounting
// slows things down more than we gain.
V3Number* nump;
if (!m_numFreeps.empty()) {
//UINFO(7,"Num Reuse "<<nodep->width()<<endl);
nump = m_numFreeps.back(); m_numFreeps.pop_back();
nump->width(nodep->width());
nump->fileline(nodep->fileline());
nump->setLong(value); // We do support more than 32 bit numbers, just valuep=0 in that case
} else {
//UINFO(7,"Num New "<<nodep->width()<<endl);
nump = new V3Number (nodep->fileline(), nodep->width(), value);
m_numAllps.push_back(nump);
}
return nump;
}
public:
V3Number* newNumber(AstNode* nodep, uint32_t value=0) {
// Set a constant value for this node
if (!nodep->user3p()) {
V3Number* nump = allocNumber(nodep, value);
setNumber(nodep, nump);
return nump;
} else {
return (fetchNumber(nodep));
}
}
V3Number* newOutNumber(AstNode* nodep, uint32_t value=0) {
// Set a constant value for this node
if (!nodep->user2p()) {
V3Number* nump = allocNumber(nodep, value);
setOutNumber(nodep, nump);
return nump;
} else {
return (fetchOutNumber(nodep));
}
}
V3Number* fetchNumberNull(AstNode* nodep) {
return ((V3Number*)nodep->user3p());
}
V3Number* fetchOutNumberNull(AstNode* nodep) {
return ((V3Number*)nodep->user2p());
}
V3Number* fetchNumber(AstNode* nodep) {
V3Number* nump = fetchNumberNull(nodep);
if (!nump) nodep->v3fatalSrc("No value found for node.");
//UINFO(9," fetch num "<<*nump<<" on "<<nodep<<endl);
return nump;
}
V3Number* fetchOutNumber(AstNode* nodep) {
V3Number* nump = fetchOutNumberNull(nodep);
if (!nump) nodep->v3fatalSrc("No value found for node.");
return nump;
}
private:
inline void setNumber(AstNode* nodep, const V3Number* nump) {
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
nodep->user3p((AstNUser*)nump);
}
inline void setOutNumber(AstNode* nodep, const V3Number* nump) {
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
nodep->user2p((AstNUser*)nump);
}
void checkNodeInfo(AstNode* nodep) {
if (m_checkOnly) {
m_instrCount += nodep->instrCount();
m_dataCount += nodep->width();
}
if (!nodep->isPredictOptimizable()) {
//UINFO(9," !predictopt "<<nodep<<endl);
clearOptimizable(nodep,"Isn't predictable");
}
}
void badNodeType(AstNode* nodep) {
// Call for default node types, or other node types we don't know how to handle
checkNodeInfo(nodep);
if (optimizable()) {
// Hmm, what is this then?
// In production code, we'll just not optimize. It should be fixed though.
clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in SimulateVisitor");
#ifdef VL_DEBUG
UINFO(0,"Unknown node type in SimulateVisitor: "<<nodep->prettyTypeName()<<endl);
#endif
}
}
AstNode* varOrScope(AstVarRef* nodep) {
AstNode* vscp;
if (m_scoped) vscp = nodep->varScopep();
else vscp = nodep->varp();
if (!vscp) nodep->v3fatalSrc("Not linked");
return vscp;
}
int unrollCount() {
return m_params ? v3Global.opt.unrollCount()*16
: v3Global.opt.unrollCount();
}
// VISITORS
virtual void visit(AstAlways* nodep, AstNUser*) {
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
if (!optimizable()) return; // Accelerate
AstNode* vscp = varOrScope(nodep);
// We can't have non-delayed assignments with same value on LHS and RHS
// as we don't figure out variable ordering.
// Delayed is OK though, as we'll decode the next state separately.
if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references");
if (nodep->lvalue()) {
if (m_inDlyAssign) {
if (!(vscp->user1() & VU_LVDLY)) {
vscp->user1( vscp->user1() | VU_LVDLY);
if (m_checkOnly) varRefCb (nodep);
}
} else { // nondly asn
if (!(vscp->user1() & VU_LV)) {
if (!m_params && (vscp->user1() & VU_RV)) clearOptimizable(nodep,"Var read & write");
vscp->user1( vscp->user1() | VU_LV);
if (m_checkOnly) varRefCb (nodep);
}
}
} else {
if (!(vscp->user1() & VU_RV)) {
if (!m_params && (vscp->user1() & VU_LV)) clearOptimizable(nodep,"Var write & read");
vscp->user1( vscp->user1() | VU_RV);
if (m_checkOnly) varRefCb (nodep);
}
}
if (!m_checkOnly && optimizable()) { // simulating
if (nodep->lvalue()) {
nodep->v3fatalSrc("LHS varref should be handled in AstAssign visitor.");
} else {
// Return simulation value - copy by reference instead of value for speed
V3Number* nump = fetchNumberNull(vscp);
if (!nump) {
if (m_params) {
clearOptimizable(nodep,"Language violation: reference to non-function-local variable");
} else {
nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
}
nump = allocNumber(nodep, 0); // Any value; just so recover from error
}
setNumber(nodep, nump);
}
}
}
virtual void visit(AstVarXRef* nodep, AstNUser*) {
if (m_scoped) { badNodeType(nodep); return; }
else { clearOptimizable(nodep,"Language violation: Dotted hierarchical references not allowed in constant functions"); }
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
if (!m_params) { badNodeType(nodep); return; }
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
UINFO(5," IF "<<nodep<<endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else {
nodep->condp()->iterateAndNext(*this);
if (optimizable()) {
if (fetchNumber(nodep->condp())->isNeqZero()) {
nodep->ifsp()->iterateAndNext(*this);
} else {
nodep->elsesp()->iterateAndNext(*this);
}
}
}
}
virtual void visit(AstConst* nodep, AstNUser*) {
checkNodeInfo(nodep);
if (!m_checkOnly && optimizable()) {
setNumber(nodep, &(nodep->num()));
}
}
virtual void visit(AstNodeUniop* nodep, AstNUser*) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()));
}
}
virtual void visit(AstNodeBiop* nodep, AstNUser*) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()), *fetchNumber(nodep->rhsp()));
}
}
virtual void visit(AstNodeTriop* nodep, AstNUser*) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
if (!m_checkOnly && optimizable()) {
nodep->numberOperate(*newNumber(nodep),
*fetchNumber(nodep->lhsp()),
*fetchNumber(nodep->rhsp()),
*fetchNumber(nodep->thsp()));
}
}
virtual void visit(AstNodeCond* nodep, AstNUser*) {
// We could use above visit(AstNodeTriop), but it's slower even O(n^2) to evaluate
// both sides when we really only need to evaluate one side.
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else {
nodep->condp()->accept(*this);
if (optimizable()) {
if (fetchNumber(nodep->condp())->isNeqZero()) {
nodep->expr1p()->accept(*this);
newNumber(nodep)->opAssign(*fetchNumber(nodep->expr1p()));
} else {
nodep->expr2p()->accept(*this);
newNumber(nodep)->opAssign(*fetchNumber(nodep->expr2p()));
}
}
}
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (!optimizable()) return; // Accelerate
if (nodep->castAssignDly()) {
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
m_anyAssignDly = true;
m_inDlyAssign = true;
} else {
if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non dly assigns");
m_anyAssignComb = true;
}
if (!nodep->lhsp()->castVarRef()) {
clearOptimizable(nodep, "LHS isn't simple variable");
}
else if (m_checkOnly) {
nodep->iterateChildren(*this);
}
else if (optimizable()) {
nodep->rhsp()->iterateAndNext(*this);
if (optimizable()) {
AstNode* vscp = varOrScope(nodep->lhsp()->castVarRef());
// Copy by value, not reference, as we don't want a=a+1 to get right results
if (nodep->castAssignDly()) {
// Don't do setNumber, as value isn't yet visible to following statements
newOutNumber(vscp)->opAssign(*fetchNumber(nodep->rhsp()));
} else {
newNumber(vscp)->opAssign(*fetchNumber(nodep->rhsp()));
newOutNumber(vscp)->opAssign(*fetchNumber(nodep->rhsp()));
}
}
}
m_inDlyAssign = false;
}
virtual void visit(AstBegin* nodep, AstNUser*) {
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstNodeCase* nodep, AstNUser*) {
UINFO(5," CASE "<<nodep<<endl);
checkNodeInfo(nodep);
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else if (optimizable()) {
nodep->exprp()->iterateAndNext(*this);
bool hit = false;
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
if (!itemp->isDefault()) {
for (AstNode* ep = itemp->condsp(); ep; ep=ep->nextp()) {
if (hit) break;
ep->iterateAndNext(*this);
if (optimizable()) {
V3Number match (nodep->fileline(), 1);
match.opEq(*fetchNumber(nodep->exprp()), *fetchNumber(ep));
if (match.isNeqZero()) {
itemp->bodysp()->iterateAndNext(*this);
hit = true;
}
}
}
}
}
// Else default match
for (AstCaseItem* itemp = nodep->itemsp(); itemp; itemp=itemp->nextp()->castCaseItem()) {
if (hit) break;
if (!hit && itemp->isDefault()) {
itemp->bodysp()->iterateAndNext(*this);
hit = true;
}
}
}
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
// Real handling is in AstNodeCase
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstComment*, AstNUser*) {}
virtual void visit(AstStop* nodep, AstNUser*) {
if (m_params) { // This message seems better than an obscure $stop
// The spec says $stop is just ignored, it seems evil to ignore assertions
clearOptimizable(nodep,"$stop executed during function constification; maybe indicates assertion firing");
}
checkNodeInfo(nodep);
}
virtual void visit(AstNodeFor* nodep, AstNUser*) {
// Doing lots of Whiles is slow, so only for parameters
UINFO(5," FOR "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
checkNodeInfo(nodep);
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else if (optimizable()) {
int loops = 0;
nodep->initsp()->iterateAndNext(*this);
while (1) {
UINFO(5," FOR-ITER "<<nodep<<endl);
nodep->condp()->iterateAndNext(*this);
if (!optimizable()) break;
if (!fetchNumber(nodep->condp())->isNeqZero()) {
break;
}
nodep->bodysp()->iterateAndNext(*this);
nodep->incsp()->iterateAndNext(*this);
if (loops++ > unrollCount()*16) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
break;
}
}
}
}
virtual void visit(AstWhile* nodep, AstNUser*) {
// Doing lots of Whiles is slow, so only for parameters
UINFO(5," WHILE "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
checkNodeInfo(nodep);
if (m_checkOnly) {
nodep->iterateChildren(*this);
} else if (optimizable()) {
int loops = 0;
while (1) {
UINFO(5," WHILE-ITER "<<nodep<<endl);
nodep->precondsp()->iterateAndNext(*this);
nodep->condp()->iterateAndNext(*this);
if (!optimizable()) break;
if (!fetchNumber(nodep->condp())->isNeqZero()) {
break;
}
nodep->bodysp()->iterateAndNext(*this);
if (loops++ > unrollCount()*16) {
clearOptimizable(nodep, "Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above "+cvtToStr(unrollCount()));
break;
}
}
}
}
virtual void visit(AstFuncRef* nodep, AstNUser*) {
UINFO(5," FUNCREF "<<nodep<<endl);
if (!m_params) { badNodeType(nodep); return; }
AstFunc* funcp = nodep->taskp()->castFunc(); if (!funcp) nodep->v3fatalSrc("Not linked");
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;
for (AstNode* stmtp = funcp->stmtsp(); stmtp; pinp=nextpinp, stmtp=stmtp->nextp()) {
if (AstVar* portp = stmtp->castVar()) {
if (portp->isIO()) {
if (pinp==NULL) {
nodep->v3error("Too few arguments in function call");
} else {
nextpinp = pinp->nextp();
if (portp->isOutput()) {
clearOptimizable(portp,"Language violation: Outputs not allowed in constant functions");
return;
}
// Evaluate pin value
pinp->accept(*this);
// Apply value to the function
if (!m_checkOnly && optimizable()) {
newNumber(stmtp)->opAssign(*fetchNumber(pinp));
}
}
}
}
}
// Evaluate the function
funcp->accept(*this);
if (!m_checkOnly && optimizable()) {
// Grab return value from output variable
newNumber(nodep)->opAssign(*fetchNumber(funcp->fvarp()));
}
}
virtual void visit(AstVar* nodep, AstNUser*) {
if (!m_params) { badNodeType(nodep); return; }
}
// default
// These types are definately not reducable
// AstCoverInc, AstNodePli, AstArraySel, AstStop, AstFinish,
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
virtual void visit(AstNode* nodep, AstNUser*) {
badNodeType(nodep);
}
public:
// CONSTRUCTORS
SimulateVisitor() {
setMode(false,false,false);
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
}
void setMode(bool scoped, bool checkOnly, bool params) {
m_checkOnly = checkOnly;
m_scoped = scoped;
m_params = params;
}
void clear() {
m_whyNotOptimizable = "";
m_whyNotNodep = NULL;
m_anyAssignComb = false;
m_anyAssignDly = false;
m_inDlyAssign = false;
m_instrCount = 0;
m_dataCount = 0;
AstNode::user1ClearTree(); // user1p() used on entire tree
AstNode::user2ClearTree(); // user2p() used on entire tree
AstNode::user3ClearTree(); // user3p() used on entire tree
// Move all allocated numbers to the free pool
m_numFreeps = m_numAllps;
}
void mainTableCheck (AstNode* nodep) {
setMode(true/*scoped*/,true/*checking*/, false/*params*/);
nodep->accept(*this);
}
void mainTableEmulate (AstNode* nodep) {
setMode(true/*scoped*/,false/*checking*/, false/*params*/);
nodep->accept(*this);
}
void mainParamEmulate (AstNode* nodep) {
setMode(false/*scoped*/,false/*checking*/, true/*params*/);
nodep->accept(*this);
}
virtual ~SimulateVisitor() {
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
delete (*it);
}
m_numFreeps.clear();
m_numAllps.clear();
}
};
#endif // Guard
+1 -1
View File
@@ -548,7 +548,7 @@ private:
public:
// CONSTUCTORS
SplitVisitor(AstNode* nodep, bool reorder)
SplitVisitor(AstNetlist* nodep, bool reorder)
: m_reorder(reorder) {
scoreboardClear();
nodep->accept(*this);
+8 -8
View File
@@ -34,19 +34,19 @@ class V3Double0 {
double m_d; ///< Count of occurrences/ value
public:
// METHODS
V3Double0() : m_d(0) {};
V3Double0() : m_d(0) {}
~V3Double0() {}
// Implicit conversion operators:
inline V3Double0 (const vluint64_t v) : m_d(v) { };
inline operator double () const { return m_d; };
inline V3Double0 (const vluint64_t v) : m_d(v) { }
inline operator double () const { return m_d; }
// Explicit operators:
inline V3Double0& operator++() { ++m_d; return *this; }; // prefix
inline V3Double0 operator++(int) { V3Double0 old=*this; m_d++; return old; }; // postfix
inline V3Double0& operator= (const double v) { m_d = v; return *this; };
inline V3Double0& operator+=(const double v) { m_d += v; return *this; };
inline V3Double0& operator-=(const double v) { m_d -= v; return *this; };
inline V3Double0& operator++() { ++m_d; return *this; } // prefix
inline V3Double0 operator++(int) { V3Double0 old=*this; m_d++; return old; } // postfix
inline V3Double0& operator= (const double v) { m_d = v; return *this; }
inline V3Double0& operator+=(const double v) { m_d += v; return *this; }
inline V3Double0& operator-=(const double v) { m_d -= v; return *this; }
};
//============================================================================
+26 -352
View File
@@ -36,6 +36,7 @@
#include "V3Global.h"
#include "V3Table.h"
#include "V3Simulate.h"
#include "V3Stats.h"
#include "V3Ast.h"
@@ -48,365 +49,31 @@ static const double TABLE_TOTAL_BYTES = 64*1024*1024; // 64MB is close to max me
static const double TABLE_SPACE_TIME_MULT = 8; // Worth 8 bytes of data to replace a instruction
static const int TABLE_MIN_NODE_COUNT = 32; // If < 32 instructions, not worth the effort
//######################################################################
class TableVisitor;
//######################################################################
class TableBaseVisitor : public AstNVisitor {
public:
// Note level 8&9 include debugging each simulation value
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
};
//######################################################################
class TableSimulateVisitor : public TableBaseVisitor {
// Simulate a node tree, returning value of variables
// Two major operating modes:
// Test the tree to see if it is conformant
// Given a set of input values, find the output values
// Both are done in this same visitor to reduce risk; if a visitor
// is missing, we will simply not apply the optimization, rather then bomb.
private:
// NODE STATE
// Cleared on each always/assignw
// Checking:
// AstVarScope::user1() -> VarUsage. Set true to indicate tracking as lvalue/rvalue
// Simulating:
// AstVarScope::user3() -> V3Number*. Input value of variable or node (and output for non-delayed assignments)
// AstVarScope::user4() -> V3Number*. Output value of variable (delayed assignments)
enum VarUsage { VU_NONE=0, VU_LV=1, VU_RV=2, VU_LVDLY=4 };
// STATE
bool m_checking; ///< Checking vs. simulation mode
// Checking:
class TableSimulateVisitor : public SimulateVisitor {
// MEMBERS
TableVisitor* m_cbthis; ///< Class for callback
const char* m_whyNotOptimizable; ///< String explaining why not optimizable or NULL to optimize
bool m_anyAssignDly; ///< True if found a delayed assignment
bool m_anyAssignComb; ///< True if found a non-delayed assignment
bool m_inDlyAssign; ///< Under delayed assignment
int m_instrCount; ///< Number of nodes
int m_dataCount; ///< Bytes of data
// Simulating:
deque<V3Number*> m_numFreeps; ///< List of all numbers free and not in use
deque<V3Number*> m_numAllps; ///< List of all numbers free and in use
// Checking METHODS
public:
void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references
void clearOptimizable(AstNode* nodep/*null ok*/, const char* why) {
if (!m_whyNotOptimizable) {
if (debug()>=5) {
UINFO(0,"Clear optimizable: "<<why);
if (nodep) cout<<": "<<nodep;
cout<<endl;
}
m_whyNotOptimizable = why;
}
}
bool optimizable() const { return m_whyNotOptimizable==NULL; }
bool isAssignDly() const { return m_anyAssignDly; }
int instrCount() const { return m_instrCount; }
int dataCount() const { return m_dataCount; }
// Simulation METHODS
private:
V3Number* allocNumber(AstNode* nodep, uint32_t value) {
// Save time - kept a list of allocated but unused V3Numbers
// It would be more efficient to do this by size, but the extra accounting
// slows things down more than we gain.
V3Number* nump;
if (!m_numFreeps.empty()) {
//UINFO(7,"Num Reuse "<<nodep->width()<<endl);
nump = m_numFreeps.back(); m_numFreeps.pop_back();
nump->width(nodep->width());
nump->fileline(nodep->fileline());
nump->setLong(value); // We do support more than 32 bit numbers, just valuep=0 in that case
} else {
//UINFO(7,"Num New "<<nodep->width()<<endl);
nump = new V3Number (nodep->fileline(), nodep->width(), value);
m_numAllps.push_back(nump);
}
return nump;
}
public:
V3Number* newNumber(AstNode* nodep, uint32_t value=0) {
// Set a constant value for this node
if (!nodep->user3p()) {
V3Number* nump = allocNumber(nodep, value);
setNumber(nodep, nump);
}
return (fetchNumber(nodep));
}
V3Number* newOutNumber(AstNode* nodep, uint32_t value=0) {
// Set a constant value for this node
if (!nodep->user4p()) {
V3Number* nump = allocNumber(nodep, value);
setOutNumber(nodep, nump);
}
return (fetchOutNumber(nodep));
}
V3Number* fetchNumberNull(AstNode* nodep) {
return ((V3Number*)nodep->user3p());
}
V3Number* fetchOutNumberNull(AstNode* nodep) {
return ((V3Number*)nodep->user4p());
}
V3Number* fetchNumber(AstNode* nodep) {
V3Number* nump = fetchNumberNull(nodep);
if (!nump) nodep->v3fatalSrc("No value found for node.");
return nump;
}
V3Number* fetchOutNumber(AstNode* nodep) {
V3Number* nump = fetchOutNumberNull(nodep);
if (!nump) nodep->v3fatalSrc("No value found for node.");
return nump;
}
private:
void setNumber(AstNode* nodep, const V3Number* nump) {
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
nodep->user3p((AstNUser*)nump);
}
void setOutNumber(AstNode* nodep, const V3Number* nump) {
UINFO(9," set num "<<*nump<<" on "<<nodep<<endl);
nodep->user4p((AstNUser*)nump);
}
void checkNodeInfo(AstNode* nodep) {
m_instrCount += nodep->instrCount();
m_dataCount += nodep->width();
if (!nodep->isPredictOptimizable()) {
//UINFO(9," !predictopt "<<nodep<<endl);
clearOptimizable(nodep,"!predictOptimzable");
}
}
// VISITORS
virtual void visit(AstAlways* nodep, AstNUser*) {
if (m_checking) checkNodeInfo(nodep);
nodep->iterateChildren(*this);
}
virtual void visit(AstSenTree* nodep, AstNUser*) {
// Sensitivities aren't inputs per se; we'll keep our tree under the same sens.
}
virtual void visit(AstVarRef* nodep, AstNUser*) {
AstVarScope* vscp = nodep->varScopep();
if (!vscp) nodep->v3fatalSrc("Not linked");
if (m_checking) {
if (m_checking && !optimizable()) return; // Accelerate
// We can't have non-delayed assignments with same value on LHS and RHS
// as we don't figure out variable ordering.
// Delayed is OK though, as we'll decode the next state separately.
if (nodep->varp()->arraysp()) clearOptimizable(nodep,"Array references");
if (nodep->lvalue()) {
if (m_inDlyAssign) {
if (!(vscp->user1() & VU_LVDLY)) {
vscp->user1( vscp->user1() | VU_LVDLY);
varRefCb (nodep);
}
} else { // nondly asn
if (!(vscp->user1() & VU_LV)) {
if (vscp->user1() & VU_RV) clearOptimizable(nodep,"Var read & write");
vscp->user1( vscp->user1() | VU_LV);
varRefCb (nodep);
}
}
} else {
if (!(vscp->user1() & VU_RV)) {
if (vscp->user1() & VU_LV) clearOptimizable(nodep,"Var write & read");
vscp->user1( vscp->user1() | VU_RV);
varRefCb (nodep);
}
}
}
else { // simulating
if (nodep->lvalue()) {
nodep->v3fatalSrc("LHS varref should be handled in AstAssign visitor.");
} else {
// Return simulation value
V3Number* nump = fetchNumberNull(vscp);
if (!nump) nodep->v3fatalSrc("Variable value should have been set before any visitor called.");
setNumber(nodep, nump);
}
}
}
virtual void visit(AstNodeIf* nodep, AstNUser*) {
if (m_checking) {
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
} else {
nodep->condp()->iterateAndNext(*this);
if (fetchNumber(nodep->condp())->isNeqZero()) {
nodep->ifsp()->iterateAndNext(*this);
} else {
nodep->elsesp()->iterateAndNext(*this);
}
}
}
virtual void visit(AstConst* nodep, AstNUser*) {
if (m_checking) {
checkNodeInfo(nodep);
} else {
setNumber(nodep, &(nodep->num()));
}
}
virtual void visit(AstNodeUniop* nodep, AstNUser*) {
if (m_checking) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
} else {
nodep->iterateChildren(*this);
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()));
}
}
virtual void visit(AstNodeBiop* nodep, AstNUser*) {
if (m_checking) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
} else {
nodep->iterateChildren(*this);
nodep->numberOperate(*newNumber(nodep), *fetchNumber(nodep->lhsp()), *fetchNumber(nodep->rhsp()));
}
}
virtual void visit(AstNodeTriop* nodep, AstNUser*) {
if (m_checking) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
} else {
nodep->iterateChildren(*this);
nodep->numberOperate(*newNumber(nodep),
*fetchNumber(nodep->lhsp()),
*fetchNumber(nodep->rhsp()),
*fetchNumber(nodep->thsp()));
}
}
virtual void visit(AstNodeCond* nodep, AstNUser*) {
// We could use above visit(AstNodeTriop), but it's slower to evaluate
// both sides when we really only need to evaluate one side.
if (m_checking) {
if (!optimizable()) return; // Accelerate
checkNodeInfo(nodep);
nodep->iterateChildren(*this);
} else {
nodep->condp()->accept(*this);
if (fetchNumber(nodep->condp())->isNeqZero()) {
nodep->expr1p()->accept(*this);
newNumber(nodep)->opAssign(*fetchNumber(nodep->expr1p()));
} else {
nodep->expr2p()->accept(*this);
newNumber(nodep)->opAssign(*fetchNumber(nodep->expr2p()));
}
}
}
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
if (m_checking) {
if (!optimizable()) return; // Accelerate
if (nodep->castAssignDly()) {
if (m_anyAssignComb) clearOptimizable(nodep, "Mix of dly/non dly assigns");
m_anyAssignDly = true;
m_inDlyAssign = true;
} else {
if (m_anyAssignDly) clearOptimizable(nodep, "Mix of dly/non dly assigns");
m_anyAssignComb = true;
}
nodep->iterateChildren(*this);
}
if (!nodep->lhsp()->castVarRef()) {
clearOptimizable(nodep, "LHS isn't simple variable");
}
else if (!m_checking) {
nodep->rhsp()->iterateAndNext(*this);
AstVarScope* vscp = nodep->lhsp()->castVarRef()->varScopep();
if (nodep->castAssignDly()) {
// Don't do setNumber, as value isn't visible to new statements
setOutNumber(vscp, fetchNumber(nodep->rhsp()));
} else {
setNumber(vscp, fetchNumber(nodep->rhsp()));
setOutNumber(vscp, fetchNumber(nodep->rhsp()));
}
}
m_inDlyAssign = false;
}
virtual void visit(AstComment*, AstNUser*) {}
// default
// These types are definately not reducable
// AstCoverInc, AstNodePli, AstArraySel, AstStop, AstFinish,
// AstRand, AstTime, AstUCFunc, AstCCall, AstCStmt, AstUCStmt
// In theory, we could follow the loop, but might be slow
// AstFor, AstWhile
virtual void visit(AstNode* nodep, AstNUser*) {
if (m_checking) {
checkNodeInfo(nodep);
if (optimizable()) {
// Hmm, what is this then?
// In production code, we'll just not optimize. It should be fixed though.
clearOptimizable(nodep, "Unknown node type, perhaps missing visitor in TableSimulateVisitor");
#ifdef VL_DEBUG
UINFO(0,"Unknown node type in TableSimulateVisitor: "<<nodep->typeName()<<endl);
#endif
}
} else { // simulating
nodep->v3fatalSrc("Optimizable should have been cleared in check step, and never reach simulation.");
}
}
public:
virtual void varRefCb(AstVarRef* nodep); ///< Call other-this function on all new var references
// CONSTRUCTORS
TableSimulateVisitor(TableVisitor* cbthis, bool checking) {
TableSimulateVisitor(TableVisitor* cbthis) {
m_cbthis = cbthis;
m_checking = checking;
clear(); // We reuse this structure in the main loop, so put initializers inside clear()
}
void clear() {
m_whyNotOptimizable = NULL;
m_anyAssignComb = false;
m_anyAssignDly = false;
m_inDlyAssign = false;
m_instrCount = 0;
m_dataCount = 0;
AstNode::user1ClearTree(); // user1p() used on entire tree
AstNode::user3ClearTree(); // user3p() used on entire tree
AstNode::user4ClearTree(); // user4p() used on entire tree
// Move all allocated numbers to the free pool
m_numFreeps = m_numAllps;
}
void main (AstNode* nodep) {
nodep->accept(*this);
}
virtual ~TableSimulateVisitor() {
for (deque<V3Number*>::iterator it = m_numAllps.begin(); it != m_numAllps.end(); ++it) {
delete (*it);
}
m_numFreeps.clear();
m_numAllps.clear();
}
virtual ~TableSimulateVisitor() {}
};
//######################################################################
// Table class functions
class TableVisitor : public TableBaseVisitor {
class TableVisitor : public AstNVisitor {
private:
// NODE STATE
// Cleared on each always/assignw
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
AstUser3InUse m_inuser3;
AstUser4InUse m_inuser4;
// STATE
double m_totalBytes; // Total bytes in tables created
@@ -432,6 +99,12 @@ private:
deque<AstVarScope*> m_tableVarps; // Table being created
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
bool treeTest(AstAlways* nodep) {
// Process alw/assign tree
m_inWidth = 0;
@@ -441,8 +114,8 @@ private:
m_outNotSet.clear();
// Collect stats
TableSimulateVisitor chkvis (this, true);
chkvis.main(nodep);
TableSimulateVisitor chkvis (this);
chkvis.mainTableCheck(nodep);
m_assignDly = chkvis.isAssignDly();
// Also sets m_inWidth
// Also sets m_outWidth
@@ -458,19 +131,19 @@ private:
double bytesPerInst = 4;
double time = (chkvis.instrCount()*bytesPerInst + chkvis.dataCount()) + 1; // +1 so won't div by zero
if (chkvis.instrCount() < TABLE_MIN_NODE_COUNT) {
chkvis.clearOptimizable(nodep,"Too few nodes involved");
chkvis.clearOptimizable(nodep,"Table has too few nodes involved");
}
if (space > TABLE_MAX_BYTES) {
chkvis.clearOptimizable(nodep,"Too much space");
chkvis.clearOptimizable(nodep,"Table takes too much space");
}
if (space > time * TABLE_SPACE_TIME_MULT) {
chkvis.clearOptimizable(nodep,"Bad tradeoff");
chkvis.clearOptimizable(nodep,"Table has bad tradeoff");
}
if (m_totalBytes > TABLE_TOTAL_BYTES) {
chkvis.clearOptimizable(nodep,"Out of memory");
chkvis.clearOptimizable(nodep,"Table out of memory");
}
if (!m_outWidth || !m_inWidth) {
chkvis.clearOptimizable(nodep,"No I/O");
chkvis.clearOptimizable(nodep,"Table has no outputs");
}
UINFO(4, " Test: Opt="<<(chkvis.optimizable()?"OK":"NO")
<<", Instrs="<<chkvis.instrCount()<<" Data="<<chkvis.dataCount()
@@ -599,7 +272,7 @@ private:
m_outNotSet.push_back(false);
}
uint32_t inValueNextInitArray=0;
TableSimulateVisitor simvis (this, false);
TableSimulateVisitor simvis (this);
for (uint32_t inValue=0; inValue <= VL_MASK_I(m_inWidth); inValue++) {
// Make a new simulation structure so we can set new input values
UINFO(8," Simulating "<<hex<<inValue<<endl);
@@ -621,7 +294,8 @@ private:
}
// Simulate
simvis.main(nodep);
simvis.mainTableEmulate(nodep);
if (!simvis.optimizable()) simvis.whyNotNodep()->v3fatalSrc("Optimizable cleared, even though earlier test run said not: "<<simvis.whyNotMessage());
// If a output changed, add it to table
int outnum = 0;
+18 -14
View File
@@ -191,11 +191,7 @@ private:
// Wire assigns must become always statements to deal with insertion
// of multiple statements. Perhaps someday make all wassigns into always's?
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
AstNode* lhsp = m_assignwp->lhsp()->unlinkFrBack();
AstNode* rhsp = m_assignwp->rhsp()->unlinkFrBack();
AstNode* assignp = new AstAssign (m_assignwp->fileline(), lhsp, rhsp);
AstNode* alwaysp = new AstAlways (m_assignwp->fileline(), NULL, assignp);
m_assignwp->replaceWith(alwaysp); pushDeletep(m_assignwp); m_assignwp=NULL;
m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL;
}
// We make multiple edges if a task is called multiple times from another task.
new TaskEdge (&m_callGraph, m_curVxp, getFTaskVertex(nodep->taskp()));
@@ -243,7 +239,7 @@ public:
AstNode::user3ClearTree();
AstNode::user4ClearTree();
//
nodep->iterateAndNext(*this, NULL);
nodep->accept(*this);
//
m_callGraph.removeRedundantEdgesSum(&TaskEdge::followAlwaysTrue);
m_callGraph.dumpDotFilePrefixed("task_call");
@@ -280,8 +276,8 @@ private:
}
public:
// CONSTUCTORS
TaskRelinkVisitor(AstNode* nodep) {
nodep->iterateAndNext(*this, NULL);
TaskRelinkVisitor(AstBegin* nodep) { // Passed temporary tree
nodep->accept(*this);
}
virtual ~TaskRelinkVisitor() {}
};
@@ -430,7 +426,12 @@ private:
refp->taskp()->castFunc()->fvarp()->user2p(outvscp);
}
// Replace variable refs
TaskRelinkVisitor visit (beginp);
// Iteration requires a back, so put under temporary node
{
AstBegin* tempp = new AstBegin(beginp->fileline(),"[EditWrapper]",beginp);
TaskRelinkVisitor visit (tempp);
tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
}
//
if (debug()>=9) { beginp->dumpTree(cout,"-iotask: "); }
return beginp;
@@ -582,7 +583,12 @@ private:
new AstVarRef(rtnvscp->fileline(), rtnvscp, false)));
}
// Replace variable refs
TaskRelinkVisitor visit (cfuncp);
// Iteration requires a back, so put under temporary node
{
AstBegin* tempp = new AstBegin(cfuncp->fileline(),"[EditWrapper]",cfuncp);
TaskRelinkVisitor visit (tempp);
tempp->stmtsp()->unlinkFrBackWithNext(); tempp->deleteTree(); tempp=NULL;
}
// Delete rest of cloned task and return new func
pushDeletep(nodep); nodep=NULL;
if (debug()>=9 && forUser) { cfuncp->dumpTree(cout,"-userFunc: "); }
@@ -599,16 +605,14 @@ private:
m_scopep = oldscopep;
}
void insertBeforeStmt(AstNode* nodep, AstNode* newp) {
// See also AstNode::addBeforeStmt; this predates that function
if (debug()>=9) { nodep->dumpTree(cout,"-newstmt:"); }
if (!m_insStmtp) nodep->v3fatalSrc("Function not underneath a statement");
if (m_insMode == IM_BEFORE) {
// Add the whole thing before insertAt
UINFO(5," IM_Before "<<m_insStmtp<<endl);
AstNRelinker handle;
m_insStmtp->unlinkFrBackWithNext(&handle);
if (debug()>=9) { newp->dumpTree(cout,"-newfunc:"); }
newp->addNext(m_insStmtp);
handle.relink(newp);
m_insStmtp->addHereThisAsNext(newp);
}
else if (m_insMode == IM_AFTER) {
UINFO(5," IM_After "<<m_insStmtp);
+1 -1
View File
@@ -89,7 +89,7 @@ public:
virtual ~TraceActivityVertex() {}
// Accessors
AstNode* insertp() const {
if (!m_insertp) v3fatal("Null insertp; probably called on a special always/slow.");
if (!m_insertp) v3fatalSrc("Null insertp; probably called on a special always/slow.");
return m_insertp;
}
virtual string name() const {
+4 -2
View File
@@ -125,8 +125,10 @@ private:
AstVar* varp = nodep->varp();
AstScope* scopep = nodep->scopep();
// Compute show name
string showname = scopep->prettyName() + "." + varp->prettyName();
if (showname.substr(0,4) == "TOP.") showname.replace(0,4,"");
// This code assumes SPTRACEVCDC_VERSION >= 1330;
// it uses spaces to separate hierarchy components.
string showname = AstNode::vcdName(scopep->name() + " " + varp->name());
if (showname.substr(0,4) == "TOP ") showname.replace(0,4,"");
if (!m_initSubFuncp) nodep->v3fatalSrc("NULL");
if (varIgnoreTrace(varp)) {
m_statIgnSigs++;
+6
View File
@@ -58,6 +58,7 @@
#include "V3Ast.h"
#include "V3Const.h"
#include "V3Stats.h"
#include "V3Inst.h"
//######################################################################
@@ -207,6 +208,7 @@ private:
AstVarType::MODULETEMP,
outrefp->name() + "__en" + suffix + cvtToStr(m_unique++),
(width>1) ? new AstRange(outp->fileline(), width-1, 0) : (AstRange *) NULL);
enp->varType2Out();
if (enp->width() != enrhsp->width()) {
if (enrhsp->width()==1) { // it seems from my futzing that the linter guarantees this condition
@@ -544,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
@@ -649,6 +654,7 @@ private:
if (nodep->modVarp()->user1p()) {
// create the input pin
AstVarRef* refp = nodep->exprp()->castVarRef();
if (!refp) nodep->v3fatal("Unsupported: Tristate pin not connected to simple net");
AstVar* inp;
if (refp->varp()->user1p()) { // this is a tristate
inp = (AstVar*) refp->varp()->user1p();
+154 -80
View File
@@ -51,13 +51,18 @@ class UnknownVisitor : public AstNVisitor {
private:
// NODE STATE
// Cleared on Netlist
// AstSel::user() -> bool. Set true if already processed
// AstArraySel::user() -> bool. Set true if already processed
// AstNode::user2p() -> AstIf* Inserted if assignment for conditional
AstUser1InUse m_inuser1;
AstUser2InUse m_inuser2;
// STATE
AstModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
V3Double0 m_statUnkVars; // Statistic tracking
AstModule* m_modp; // Current module
bool m_constXCvt; // Convert X's
V3Double0 m_statUnkVars; // Statistic tracking
AstAssignW* m_assignwp; // Current assignment
AstAssignDly* m_assigndlyp; // Current assignment
// METHODS
static int debug() {
@@ -66,6 +71,80 @@ private:
return level;
}
void replaceBoundLvalue(AstNode* nodep, AstNode* condp) {
// Spec says a out-of-range LHS SEL results in a NOP.
// This is a PITA. We could:
// 1. IF(...) around an ASSIGN,
// but that would break a "foo[TOO_BIG]=$fopen(...)".
// 2. Hack to extend the size of the output structure
// by one bit, and write to that temporary, but never read it.
// That makes there be two widths() and is likely a bug farm.
// 3. Make a special SEL to choose between the real lvalue
// and a temporary NOP register.
// 4. Assign to a temp, then IF that assignment.
// This is suspected to be nicest to later optimizations.
// 4 seems best but breaks later optimizations. 3 was tried,
// but makes a mess in the emitter as lvalue switching is needed. So 4.
// SEL(...) -> temp
// if (COND(LTE(bit<=maxlsb))) ASSIGN(SEL(...)),temp)
if (m_assignwp) {
// Wire assigns must become always statements to deal with insertion
// of multiple statements. Perhaps someday make all wassigns into always's?
UINFO(5," IM_WireRep "<<m_assignwp<<endl);
m_assignwp->convertToAlways(); pushDeletep(m_assignwp); m_assignwp=NULL;
}
bool needDly = m_assigndlyp;
if (m_assigndlyp) {
// Delayed assignments become normal assignments,
// then the temp created becomes the delayed assignment
AstNode* newp = new AstAssign(m_assigndlyp->fileline(),
m_assigndlyp->lhsp()->unlinkFrBackWithNext(),
m_assigndlyp->rhsp()->unlinkFrBackWithNext());
m_assigndlyp->replaceWith(newp); pushDeletep(m_assigndlyp); m_assigndlyp=NULL;
}
AstNode* prep = nodep;
// Scan back to put the condlvalue above all selects (IE top of the lvalue)
while (prep->backp()->castNodeSel()
|| prep->backp()->castSel()) {
prep=prep->backp();
}
FileLine* fl = nodep->fileline();
nodep=NULL; // Zap it so we don't use it by mistake - use prep
// Already exists; rather than IF(a,... IF(b... optimize to IF(a&&b,
// Saves us teaching V3Const how to optimize, and it won't be needed again.
if (AstIf* ifp = prep->user2p()->castNode()->castIf()) {
if (needDly) prep->v3fatalSrc("Should have already converted to non-delay");
AstNRelinker replaceHandle;
AstNode* earliercondp = ifp->condp()->unlinkFrBack(&replaceHandle);
AstNode* newp = new AstLogAnd (condp->fileline(),
condp,
earliercondp);
UINFO(4, "Edit BOUNDLVALUE "<<newp<<endl);
replaceHandle.relink(newp);
}
else {
string name = ((string)"__Vlvbound"+cvtToStr(m_modp->varNumGetInc()));
AstVar* varp = new AstVar(fl, AstVarType::MODULETEMP, name,
new AstRange(fl, prep->width()-1, 0));
m_modp->addStmtp(varp);
AstNode* abovep = prep->backp(); // Grab above point before loose it w/ next replace
prep->replaceWith(new AstVarRef(fl, varp, true));
AstNode* newp = new AstIf(fl, condp,
(needDly
? ((new AstAssignDly(fl, prep,
new AstVarRef(fl, varp, false)))->castNode())
: ((new AstAssign (fl, prep,
new AstVarRef(fl, varp, false)))->castNode())),
NULL);
if (debug()>=9) newp->dumpTree(cout," _new: ");
abovep->addNextStmt(newp,abovep);
prep->user2p(newp); // Save so we may LogAnd it next time
}
}
// VISITORS
virtual void visit(AstModule* nodep, AstNUser*) {
UINFO(4," MOD "<<nodep<<endl);
@@ -74,6 +153,16 @@ private:
nodep->iterateChildren(*this);
m_modp = NULL;
}
virtual void visit(AstAssignDly* nodep, AstNUser*) {
m_assigndlyp = nodep;
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assigndlyp = NULL;
}
virtual void visit(AstAssignW* nodep, AstNUser*) {
m_assignwp = nodep;
nodep->iterateChildren(*this); nodep=NULL; // May delete nodep.
m_assignwp = NULL;
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
m_constXCvt = false; // Avoid loosing the X's in casex
nodep->condsp()->iterateAndNext(*this);
@@ -82,11 +171,11 @@ private:
}
void visitEqNeqCase(AstNodeBiop* nodep) {
UINFO(4," N/EQCASE->EQ "<<nodep<<endl);
V3Const::constifyTree(nodep->lhsp());
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) {
// Both sides are constant, node can be constant
V3Const::constifyTree(nodep); nodep=NULL;
V3Const::constifyEdit(nodep); nodep=NULL;
return;
} else {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
@@ -112,11 +201,11 @@ private:
}
void visitEqNeqWild(AstNodeBiop* nodep) {
UINFO(4," N/EQWILD->EQ "<<nodep<<endl);
V3Const::constifyTree(nodep->lhsp());
V3Const::constifyTree(nodep->rhsp());
V3Const::constifyEdit(nodep->lhsp()); // lhsp may change
V3Const::constifyEdit(nodep->rhsp()); // rhsp may change
if (nodep->lhsp()->castConst() && nodep->rhsp()->castConst()) {
// Both sides are constant, node can be constant
V3Const::constifyTree(nodep); nodep=NULL;
V3Const::constifyEdit(nodep); nodep=NULL;
return;
} else {
AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
@@ -249,52 +338,35 @@ private:
int maxlsb = maxmsb - nodep->widthMin() + 1;
if (debug()>=9) nodep->dumpTree(cout,"sel_old: ");
V3Number maxlsbnum (nodep->fileline(), nodep->lsbp()->width(), maxlsb);
if (!lvalue) {
// See if the condition is constant true
AstNode* condp = new AstLte (nodep->fileline(),
nodep->lsbp()->cloneTree(false),
new AstConst(nodep->fileline(), maxlsbnum));
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
condp->deleteTree();
}
else if (!lvalue) {
// SEL(...) -> COND(LTE(bit<=maxlsb), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
xnum.setAllBitsX();
// Put the new nodes under a temporary XOR operator we'll rip up in a moment.
// This way when we constify, if the expression
// is a constant it will still be under the XOR.
AstXor* newp = new AstXor (
nodep->fileline(),
new AstCondBound (nodep->fileline(),
new AstLte (nodep->fileline(),
nodep->lsbp()->cloneTree(false),
new AstConst(nodep->fileline(), maxlsbnum)),
nodep,
new AstConst(nodep->fileline(), xnum)),
new AstConst (nodep->fileline(), 0)); // Just so it's a valid XOR
AstNode* newp = new AstCondBound (nodep->fileline(),
condp,
nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout," _new: ");
V3Const::constifyTree(newp->lhsp()); // Just the conditional
if (debug()>=9) newp->dumpTree(cout," _con: ");
// Link in conditional, can blow away temp xor
AstNode* nnp = newp->lhsp()->unlinkFrBack();
replaceHandle.relink(nnp); nodep=NULL;
newp->deleteTree(); newp=NULL;
// Added X's, tristate them too
nnp->accept(*this);
}
else {
// SEL(...) -> SEL(COND(LTE(bit<=maxlsb), bit, 0))
AstNRelinker replaceHandle;
AstNode* lsbp = nodep->lsbp()->unlinkFrBack(&replaceHandle);
V3Number zeronum (nodep->fileline(), lsbp->width(), 0);
AstCondBound* newp = new AstCondBound
(lsbp->fileline(),
new AstLte (lsbp->fileline(),
lsbp->cloneTree(false),
new AstConst(lsbp->fileline(), maxlsbnum)),
lsbp,
new AstConst(lsbp->fileline(), zeronum));
// Link in conditional
replaceHandle.relink(newp);
// Added X's, tristate them too
if (debug()>=9) nodep->dumpTree(cout," _new: ");
V3Const::constifyTree(nodep);
if (debug()>=9) nodep->dumpTree(cout," _con: ");
nodep->iterateChildren(*this);
newp->accept(*this);
}
else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
}
@@ -303,6 +375,7 @@ private:
nodep->iterateChildren(*this);
if (!nodep->user1()) {
nodep->user1(1);
if (debug()==9) nodep->dumpTree(cout,"-in: ");
// Guard against reading/writing past end of arrays
AstNode* basefromp = AstArraySel::baseFromp(nodep->fromp());
int dimension = AstArraySel::dimension(nodep->fromp());
@@ -319,53 +392,50 @@ private:
}
if (debug()>=9) nodep->dumpTree(cout,"arraysel_old: ");
V3Number widthnum (nodep->fileline(), nodep->bitp()->width(), maxmsb);
if (!lvalue
// See if the condition is constant true
AstNode* condp = new AstLte (nodep->fileline(),
nodep->bitp()->cloneTree(false),
new AstConst(nodep->fileline(), widthnum));
// Note below has null backp(); the Edit function knows how to deal with that.
condp = V3Const::constifyEdit(condp);
if (condp->isOne()) {
// We don't need to add a conditional; we know the existing expression is ok
condp->deleteTree();
}
else if (!lvalue
&& !nodep->backp()->castArraySel()) { // Too complicated and slow if mid-multidimension
// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
AstNRelinker replaceHandle;
nodep->unlinkFrBack(&replaceHandle);
V3Number xnum (nodep->fileline(), nodep->width());
xnum.setAllBitsX();
// Put the new nodes under a temporary XOR operator we'll rip up in a moment.
// This way when we constify, if the expression
// is a constant it will still be under the XOR.
AstXor* newp = new AstXor (
nodep->fileline(),
new AstCondBound (nodep->fileline(),
new AstLte (nodep->fileline(),
nodep->bitp()->cloneTree(false),
new AstConst(nodep->fileline(), widthnum)),
nodep,
new AstConst(nodep->fileline(), xnum)),
new AstConst (nodep->fileline(), 0)); // Just so it's a valid XOR
AstNode* newp = new AstCondBound (nodep->fileline(),
condp,
nodep,
new AstConst(nodep->fileline(), xnum));
if (debug()>=9) newp->dumpTree(cout," _new: ");
V3Const::constifyTree(newp->lhsp()); // Just the conditional
if (debug()>=9) newp->dumpTree(cout," _con: ");
// Link in conditional, can blow away temp xor
AstNode* nnp = newp->lhsp()->unlinkFrBack();
replaceHandle.relink(nnp); nodep=NULL;
newp->deleteTree(); newp=NULL;
replaceHandle.relink(newp);
// Added X's, tristate them too
nnp->accept(*this);
newp->accept(*this);
}
else {
else if (!lvalue) { // Mid-multidimension read, just use zero
// ARRAYSEL(...) -> ARRAYSEL(COND(LT(bit<maxbit), bit, 0))
AstNRelinker replaceHandle;
AstNode* bitp = nodep->bitp()->unlinkFrBack(&replaceHandle);
V3Number zeronum (nodep->fileline(), bitp->width(), 0);
AstCondBound* newp = new AstCondBound
(bitp->fileline(),
new AstLte (bitp->fileline(),
bitp->cloneTree(false),
new AstConst(bitp->fileline(), widthnum)),
bitp,
new AstConst(bitp->fileline(), zeronum));
replaceHandle.relink(newp);
AstNode* newp = new AstCondBound (bitp->fileline(),
condp,
bitp,
new AstConst(bitp->fileline(), zeronum));
// Added X's, tristate them too
if (debug()>=9) nodep->dumpTree(cout," _new: ");
V3Const::constifyTree(nodep);
if (debug()>=9) nodep->dumpTree(cout," _con: ");
nodep->iterateChildren(*this);
if (debug()>=9) newp->dumpTree(cout," _new: ");
replaceHandle.relink(newp);
newp->accept(*this);
}
else { // lvalue
replaceBoundLvalue(nodep, condp);
}
}
}
@@ -377,7 +447,11 @@ private:
public:
// CONSTUCTORS
UnknownVisitor(AstNode* nodep) {
UnknownVisitor(AstNetlist* nodep) {
m_modp = NULL;
m_assigndlyp = NULL;
m_assignwp = NULL;
m_constXCvt = false;
nodep->accept(*this);
}
virtual ~UnknownVisitor() {
+22 -15
View File
@@ -102,12 +102,13 @@ private:
AstAssign* initAssp = initp->castAssign();
if (!initAssp) return cantUnroll(nodep, "no initial assignment");
if (initp->nextp() && initp->nextp()!=nodep) nodep->v3fatalSrc("initial assignment shouldn't be a list");
if (!initAssp->lhsp()->castVarRef()) return cantUnroll(nodep, "no initial assignment to simple variable");
m_forVarp = initAssp->lhsp()->castVarRef()->varp();
m_forVscp = initAssp->lhsp()->castVarRef()->varScopep();
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");
//
@@ -141,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);
@@ -160,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);
@@ -256,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;
@@ -293,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,
@@ -320,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.
@@ -382,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);
+185 -90
View File
@@ -52,6 +52,7 @@
#include "V3Global.h"
#include "V3Width.h"
#include "V3Signed.h"
#include "V3Number.h"
#include "V3Const.h"
@@ -66,7 +67,7 @@
int m_minWidth; // Minimum width, for (2+2), it's 2 bits, for 32'2+32'2 it's 32 bits
Stage m_stage; // If true, report errors
public:
WidthVP(int width, int minWidth, Stage stage) : m_width(width), m_minWidth(minWidth), m_stage(stage) {};
WidthVP(int width, int minWidth, Stage stage) : m_width(width), m_minWidth(minWidth), m_stage(stage) {}
int width() const { return m_width; }
int widthMin() const { return m_minWidth?m_minWidth:m_width; }
bool prelim() const { return m_stage&1; }
@@ -202,6 +203,22 @@ private:
nodep->rhsp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
nodep->width(nodep->lhsp()->width() + nodep->rhsp()->width(),
nodep->lhsp()->widthMin() + nodep->rhsp()->widthMin());
// Cleanup zero width Verilog2001 {x,{0{foo}}} now,
// otherwise having width(0) will cause later assertions to fire
if (AstReplicate* repp=nodep->lhsp()->castReplicate()) {
if (repp->width()==0) { // Keep rhs
nodep->replaceWith(nodep->rhsp()->unlinkFrBack());
pushDeletep(nodep); nodep=NULL;
return;
}
}
if (AstReplicate* repp=nodep->rhsp()->castReplicate()) {
if (repp->width()==0) { // Keep lhs
nodep->replaceWith(nodep->lhsp()->unlinkFrBack());
pushDeletep(nodep); nodep=NULL;
return;
}
}
}
if (vup->c()->final()) {
if (!nodep->widthSized()) {
@@ -214,11 +231,13 @@ 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();
if (times==0) { nodep->v3error("Replication value is 0."); times=1; }
if (times==0 && !nodep->backp()->castConcat()) { // Concat Visitor will clean it up.
nodep->v3error("Replication value of 0 is only legal under a concatenation."); times=1;
}
nodep->width((nodep->lhsp()->width() * times),
(nodep->lhsp()->widthMin() * times));
}
@@ -230,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");
@@ -304,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 "
@@ -322,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);
}
}
@@ -329,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();
@@ -350,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 "
@@ -362,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.
}
@@ -376,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()) {
@@ -410,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
}
@@ -424,6 +476,8 @@ private:
virtual void visit(AstVar* nodep, AstNUser* vup) {
//if (debug()) nodep->dumpTree(cout," InitPre: ");
// Must have deterministic constant width
// We can't skip this step when width()!=0, as creating a AstVar
// with non-constant range gets size 1, not size 0.
int width=1; int mwidth=1;
nodep->arraysp()->iterateAndNext(*this,WidthVP(ANYSIZE,0,BOTH).p());
if (nodep->rangep()) {
@@ -438,9 +492,15 @@ private:
width = mwidth = 0; // But see below later.
}
if (nodep->initp()) {
nodep->initp()->iterateAndNext(*this,WidthVP(width,0,BOTH).p());
if (nodep->isParam() && !nodep->rangep()) {
if (nodep->initp()->widthSized()) {
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
mwidth = nodep->initp()->widthMin();
} else if (nodep->initp()->widthSized()) {
width = mwidth = nodep->initp()->width();
} else {
if (nodep->initp()->width()>32) nodep->initp()->v3warn(WIDTH,"Assigning >32 bit to unranged parameter (defaults to 32 bits)\n");
@@ -457,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: ");
@@ -494,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();
@@ -520,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()) {
@@ -553,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);
}
@@ -702,17 +767,16 @@ private:
// (Because we need to know if to connect to one or all instants)
nodep->v3error("Port connection "<<nodep->prettyName()<<" as part of a module instance array "
<<" requires "<<pinwidth<<" or "<<pinwidth*numInsts
<<" bits, but connection's "<<nodep->exprp()->typeName()
<<" bits, but connection's "<<nodep->exprp()->prettyTypeName()
<<" generates "<<expwidth<<" bits.");
awidth = expwidth;
}
nodep->width(awidth,awidth);
} else {
if (nodep->modVarp()->isTristate()) {
if (pinwidth != expwidth) {
nodep->v3error("Unsupported: Port connection "<<nodep->prettyName()<<" to inout signal "
<<" requires "<<pinwidth
<<" bits, but connection's "<<nodep->exprp()->typeName()
<<" bits, but connection's "<<nodep->exprp()->prettyTypeName()
<<" generates "<<expwidth<<" bits.");
// otherwise would need some mess to force both sides to proper size
}
@@ -725,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: ");
}
@@ -771,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;
}
}
}
}
@@ -813,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);
}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this, WidthVP(ANYSIZE,0,BOTH).p());
}
virtual ~WidthVisitor() {}
};
@@ -838,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;
@@ -858,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;
@@ -894,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 {
@@ -946,11 +1012,11 @@ void WidthVisitor::widthCheck (AstNode* nodep, const char* side,
}
if (bad && !ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Operator "<<nodep->typeName()
nodep->v3warn(WIDTH,"Operator "<<nodep->prettyTypeName()
<<" expects "<<expWidth
<<(expWidth!=expWidthMin?" or "+cvtToStr(expWidthMin):"")
<<" bits on the "<<side<<", but "<<side<<"'s "
<<underp->typeName()<<" generates "<<underp->width()
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
@@ -963,15 +1029,16 @@ 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);
if (bad) {
if (!ignoreWarn) {
if (debug()>4) nodep->backp()->dumpTree(cout," back: ");
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->typeName()
nodep->v3warn(WIDTH,"Logical Operator "<<nodep->prettyTypeName()
<<" expects 1 bit on the "<<side<<", but "<<side<<"'s "
<<underp->typeName()<<" generates "<<underp->width()
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
@@ -981,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) {
@@ -988,7 +1056,7 @@ void WidthVisitor::widthCheckPin (AstNode* nodep, AstNode* underp, int expWidth,
<<" port connection "<<nodep->prettyName()
<<" expects "<<expWidth
<<" bits but connection's "
<<underp->typeName()<<" generates "<<underp->width()
<<underp->prettyTypeName()<<" generates "<<underp->width()
<<(underp->width()!=underp->widthMin()
?" or "+cvtToStr(underp->widthMin()):"")
<<" bits.");
@@ -1147,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() {}
};
@@ -1165,17 +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::widthCommit(AstNode* nodep) {
AstNode* V3Width::widthParamsEditIfNeed(AstNode* nodep) {
if (!nodep->width()) {
nodep = V3Width::widthParamsEdit(nodep);
}
return nodep;
}
void V3Width::widthCommit(AstNetlist* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
WidthCommitVisitor visitor (nodep);
}
+8 -2
View File
@@ -33,9 +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 AstNode* widthParamsEdit(AstNode* nodep);
static AstNode* widthParamsEditIfNeed(AstNode* nodep);
// Final step... Mark all widths as equal
static void widthCommit(AstNode* nodep);
static void widthCommit(AstNetlist* nodep);
// For use only in WidthVisitor
// Replace AstSelBit, etc with AstSel/AstArraySel
// Returns replacement node if nodep was deleted, or null if none.
static AstNode* widthSelNoIterEdit(AstNode* nodep);
};
#endif // Guard
+345
View File
@@ -0,0 +1,345 @@
//*************************************************************************
// DESCRIPTION: Verilator: Expression width calculations
//
// Code available from: http://www.veripool.org/verilator
//
// AUTHORS: Wilson Snyder with Paul Wasson, Duane Gabli
//
//*************************************************************************
//
// Copyright 2003-2009 by Wilson Snyder. This program is free software; you can
// redistribute it and/or modify it under the terms of either the GNU
// Lesser General Public License Version 3 or the Perl Artistic License
// Version 2.0.
//
// Verilator is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
//*************************************************************************
// V3WidthSel's Transformations:
// Top down traversal:
// Replace SELPLUS/SELMINUS with SEL
// Replace SELEXTRACT with SEL
// Replace SELBIT with SEL or ARRAYSEL
//
// This code was once in V3LinkResolve, but little endian bit vectors won't
// work that early. It was considered for V3Width and V3Param, but is
// fairly ugly both places as the nodes change in too strongly
// interconnected ways.
//
//*************************************************************************
#include "config_build.h"
#include "verilatedos.h"
#include <cstdio>
#include <cstdarg>
#include <unistd.h>
#include "V3Global.h"
#include "V3Width.h"
#include "V3Const.h"
//######################################################################
// Width state, as a visitor of each AstNode
class WidthSelVisitor : public AstNVisitor {
private:
// IMPORTANT
//**** This is not a normal visitor, in that all iteration is instead
// done by the caller (V3Width). This avoids duplicating much of the
// complicated GenCase/GenFor/Cell/Function call logic that all depends
// on if widthing top-down or just for parameters.
#define iterateChildren DO_NOT_iterateChildern_IN_V3WidthSel
//
// NODE STATE
// isBelowSeled() used insead of userp, as we're out of
// non-conflicting users, and having a persistent variable means this
// code can be skipped during most later stage constification calls.
// METHODS
static int debug() {
static int level = -1;
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
void checkConstantOrReplace(AstNode* nodep, const string& message) {
// Note can't call V3Const::constifyParam(nodep) here, as constify may change nodep on us!
if (!nodep->castConst()) {
nodep->v3error(message);
nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Unsized32(), 1));
pushDeletep(nodep); nodep=NULL;
}
}
void selCheckDimension(AstNode* nodep, AstNode* basefromp, int dimension, bool rangedSelect) {
// Perform error checks on the node
AstVar* varp = varFromBasefrom(basefromp);
//UINFO(9,"SCD\n"); if (debug()>=9) nodep->backp()->dumpTree(cout,"-selcheck: ");
int dimensions = varp->arrayDimensions();
if (dimension < dimensions) {
if (rangedSelect) {
nodep->v3error("Illegal bit select; can't bit extract from arrayed dimension: "<<varp->prettyName());
}
} else if (dimension > dimensions) { // Too many indexes provided
nodep->v3error("Illegal bit or array select; variable already selected, or bad dimension: "<<varp->prettyName());
} else if (dimension == dimensions) { // Right number, but...
if (!varp->rangep()) {
nodep->v3error("Illegal bit select; variable does not have a bit range, or bad dimension: "<<varp->prettyName());
}
}
}
AstNode* newSubNeg(AstNode* lhsp, vlsint32_t rhs) {
// Return lhs-rhs, but if rhs is negative use an add, so we won't
// have to deal with signed math and related 32bit sign extension problems
if (rhs == 0) {
return lhsp;
} else if (rhs > 0) {
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), rhs));
newp->signedFrom(lhsp);
return newp;
} else { // rhs < 0;
AstNode* newp = new AstAdd(lhsp->fileline(), lhsp,
new AstConst(lhsp->fileline(), AstConst::Unsized32(), -rhs));
newp->signedFrom(lhsp);
return newp;
}
}
AstNode* newSubNeg(vlsint32_t lhs, AstNode* rhsp) {
// Return lhs-rhs
// We must make sure sub gets sign of original value
AstNode* newp = new AstSub(rhsp->fileline(),
new AstConst(rhsp->fileline(), AstConst::Unsized32(), lhs),
rhsp);
newp->signedFrom(rhsp); // Important as AstSub default is lhs's sign
return newp;
}
AstVar* varFromBasefrom(AstNode* basefromp) {
AstNodeVarRef* varrefp = basefromp->castNodeVarRef();
if (!varrefp) basefromp->v3fatalSrc("Bit/array selection of non-variable");
AstVar* varp = varrefp->varp(); if (!varp) varrefp->v3fatalSrc("Signal not linked");
return varp;
}
AstNode* newSubLsbOf(AstNode* underp, AstNode* basefromp) {
// Account for a variable's LSB in bit selections
// Will likely become SUB(underp, lsb_of_signal)
// Don't report WIDTH warnings etc here, as may be inside a generate branch that will be deleted
AstVar* varp = varFromBasefrom(basefromp);
// SUB #'s Not needed when LSB==0 and MSB>=0 (ie [0:-13] must still get added!)
if (!varp->rangep()) {
// vector without range is ok, for example a INTEGER x; y = x[21:0];
return underp;
} else {
if (!varp->rangep()->msbp()->castConst()
|| !varp->rangep()->lsbp()->castConst())
varp->v3fatalSrc("Non-constant variable range; errored earlier"); // in constifyParam(varp)
if (varp->littleEndian()) {
// reg [1:3] was swapped to [3:1] (lsbEndianedp==3) and needs a SUB(3,under)
AstNode* newp = newSubNeg(varp->msb(), underp);
return newp;
} else {
// reg [3:1] needs a SUB(under,1)
AstNode* newp = newSubNeg(underp, varp->lsb());
return newp;
}
}
}
// VISITORS
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
virtual void visit(AstRange* nodep, AstNUser*) {
// Convert all range values to constants
UINFO(6,"RANGE "<<nodep<<endl);
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
checkConstantOrReplace(nodep->msbp(), "MSB of bit range isn't a constant");
checkConstantOrReplace(nodep->lsbp(), "LSB of bit range isn't a constant");
int msb = nodep->msbConst();
int lsb = nodep->lsbConst();
if (msb<lsb) {
// If it's an array, ok to have either ordering, we'll just correct
// So, see if we're sitting under a variable's arrayp.
AstNode* huntbackp = nodep;
while (huntbackp->backp()->castRange()) huntbackp=huntbackp->backp();
if (huntbackp->backp()->castVar()
&& huntbackp->backp()->castVar()->arraysp()==huntbackp) {
} else {
// Little endian bits are legal, just remember to swap
// Warning is in V3Width to avoid false warnings when in "off" generate if's
nodep->littleEndian(!nodep->littleEndian());
}
// Internally we'll always have msb() be the greater number
// We only need to correct when doing [] AstSel extraction,
// and when tracing the vector.
nodep->msbp()->swapWith(nodep->lsbp());
}
}
virtual void visit(AstSelBit* nodep, AstNUser*) {
UINFO(6,"SELBIT "<<nodep<<endl);
if (debug()>=9) nodep->backp()->dumpTree(cout,"-vsbin(-1): ");
// lhsp/rhsp do not need to be constant
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
selCheckDimension(nodep, basefromp, dimension, false);
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* bitp = nodep->rhsp()->unlinkFrBack();
AstVar* varp = varFromBasefrom(basefromp);
if (debug()>=9) nodep->dumpTree(cout,"-vsbmd: ");
if (varp->arrayp(dimension)) {
// SELBIT(array, index) -> ARRAYSEL(array, index)
AstRange* arrayp = varp->arrayp(dimension); // NULL checked above
AstNode* subp = bitp;
if (!arrayp->lsbp()->isZero() || arrayp->msbConst()<0) {
subp = newSubNeg (subp, arrayp->lsbConst());
}
AstArraySel* newp = new AstArraySel
(nodep->fileline(),
fromp,
subp);
UINFO(6," newd"<<dimension<<" "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else {
// SELBIT(range, index) -> SEL(array, index, 1)
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(bitp, basefromp),
// Unsized so width from user
new AstConst (nodep->fileline(),AstConst::Unsized32(),1));
UINFO(6," new "<<newp<<endl); if (debug()>=9) newp->dumpTree(cout,"-vsbnw: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
}
virtual void visit(AstSelExtract* nodep, AstNUser*) {
// SELEXTRACT(from,msb,lsb) -> SEL(from, lsb, 1+msb-lsb)
UINFO(6,"SELEXTRACT "<<nodep<<endl);
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX0: ");
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->lsbp()); // May relink pointed to node
V3Const::constifyParamsEdit(nodep->msbp()); // May relink pointed to node
//if (debug()>=9) nodep->dumpTree(cout,"--SLEX3: ");
checkConstantOrReplace(nodep->lsbp(), "First value of [a:b] isn't a constant, maybe you want +: or -:");
checkConstantOrReplace(nodep->msbp(), "Second value of [a:b] isn't a constant, maybe you want +: or -:");
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* msbp = nodep->rhsp()->unlinkFrBack();
AstNode* lsbp = nodep->thsp()->unlinkFrBack();
AstVar* varp = varFromBasefrom(basefromp);
vlsint32_t msb = msbp->castConst()->toSInt();
vlsint32_t lsb = lsbp->castConst()->toSInt();
selCheckDimension(nodep, basefromp, dimension, msb!=lsb);
if (varp->rangep() && varp->rangep()->littleEndian()) {
// Below code assumes big bit endian; just works out if we swap
int x = msb; msb = lsb; lsb = x;
}
if (lsb > msb) {
nodep->v3error("["<<msb<<":"<<lsb<<"] Range extract has backward bit ordering, perhaps you wanted ["<<lsb<<":"<<msb<<"]");
int x = msb; msb = lsb; lsb = x;
}
AstNode* widthp = new AstConst (msbp->fileline(), AstConst::Unsized32(), // Unsized so width from user
msb +1-lsb);
AstSel* newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(lsbp, basefromp),
widthp);
UINFO(6," new "<<newp<<endl);
//if (debug()>=9) newp->dumpTree(cout,"--SLEXnew: ");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
pushDeletep(msbp); msbp=NULL;
}
void replaceSelPlusMinus(AstNodePreSel* nodep) {
UINFO(6,"SELPLUS/MINUS "<<nodep<<endl);
// Below 2 lines may change nodep->widthp()
V3Const::constifyParamsEdit(nodep->thsp()); // May relink pointed to node
checkConstantOrReplace(nodep->thsp(), "Width of :+ or :- bit extract isn't a constant");
// Now replace it with a AstSel
AstNode* basefromp = AstArraySel::baseFromp(nodep->attrp());
int dimension = AstArraySel::dimension(nodep->fromp()); // Not attrp as need hierarchy
AstNode* fromp = nodep->lhsp()->unlinkFrBack();
AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
AstNode* widthp = nodep->thsp()->unlinkFrBack();
int width = widthp->castConst()->toSInt();
AstVar* varp = varFromBasefrom(basefromp);
if (width > (1<<28)) nodep->v3error("Width of :+ or :- is huge; vector of over 1billion bits: "<<widthp->prettyName());
if (width<0) nodep->v3error("Width of :+ or :- is < 0: "<<widthp->prettyName());
selCheckDimension(nodep, basefromp, dimension, width!=1);
AstSel* newp = NULL;
if (nodep->castSelPlus()) {
if (varp->rangep() && varp->rangep()->littleEndian()) {
// SELPLUS(from,lsb,width) -> SEL(from, (vector_msb-width+1)-sel, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg((varp->msb()-width+1), rhsp),
widthp);
} else {
// SELPLUS(from,lsb,width) -> SEL(from, lsb-vector_lsb, width)
newp = new AstSel (nodep->fileline(),
fromp,
newSubLsbOf(rhsp, basefromp),
widthp);
}
} else if (nodep->castSelMinus()) {
if (varp->rangep() && varp->rangep()->littleEndian()) {
// SELMINUS(from,msb,width) -> SEL(from, msb-[bit])
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(varp->msb(), rhsp),
widthp);
} else {
// SELMINUS(from,msb,width) -> SEL(from, msb-(width-1)-lsb#)
newp = new AstSel (nodep->fileline(),
fromp,
newSubNeg(rhsp, varp->lsb()+(width-1)),
widthp);
}
} else {
nodep->v3fatalSrc("Bad Case");
}
UINFO(6," new "<<newp<<endl);
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
virtual void visit(AstSelPlus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);
}
virtual void visit(AstSelMinus* nodep, AstNUser*) {
replaceSelPlusMinus(nodep);
}
// If adding new visitors, insure V3Width's visit(TYPE) calls into here
//--------------------
// Default
virtual void visit(AstNode* nodep, AstNUser*) {
// See notes above; we never iterate
}
public:
// CONSTUCTORS
WidthSelVisitor() {}
AstNode* mainAcceptEdit(AstNode* nodep) {
return nodep->acceptSubtreeReturnEdits(*this);
}
virtual ~WidthSelVisitor() {}
};
//######################################################################
// Width class functions
AstNode* V3Width::widthSelNoIterEdit(AstNode* nodep) {
WidthSelVisitor visitor;
nodep = visitor.mainAcceptEdit(nodep);
return nodep;
}
#undef iterateChildren
+9 -8
View File
@@ -193,19 +193,21 @@ void process () {
V3Inst::dearrayAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("dearray.tree"));
// Expand inouts, stage 2
// Also simplify pin connections to always be AssignWs in prep for V3Unknown
V3Tristate::tristateAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("tristate.tree"));
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
// Task inlining & pushing BEGINs names to variables/cells
// Begin processing must be after Param, before module inlining
V3Begin::debeginAll(v3Global.rootp()); // Flatten cell names, before inliner
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("begin.tree"));
// Move assignments from X into MODULE temps.
// (Before flattening, so each new X variable is shared between all scopes of that module.)
V3Unknown::unknownAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unknown.tree"));
// Module inlining
// Cannot remove dead variables after this, as alias information for final
// V3Scope's V3LinkDot is in the AstVar.
@@ -265,7 +267,7 @@ void process () {
// Loop unrolling & convert FORs to WHILEs
V3Unroll::unrollAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("unroll.tree"));
// Convert case statements to if() blocks. Must be after V3Unknown
V3Case::caseAll(v3Global.rootp());
@@ -273,13 +275,12 @@ void process () {
// Push constants across variables and remove redundant assignments
V3Const::constifyAll(v3Global.rootp());
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
if (v3Global.opt.oLife()) {
V3Life::lifeAll(v3Global.rootp());
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("life.tree"));
}
//v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("const.tree"));
// Make large low-fanin logic blocks into lookup tables
// This should probably be done much later, once we have common logic elimination.
if (v3Global.opt.oTable()) {
+1 -1
View File
@@ -25,7 +25,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.710 2009/05/19"
#define DTVERSION "Verilator 3.720 2009/10/26"
//**********************************************************************
//**** Functions
+4 -3
View File
@@ -19,13 +19,14 @@ my $dir = $ARGV[0]; defined $dir or die "%Error: No directory argument,";
chdir $dir;
my $rev = 'UNKNOWN_REV';
my $data = `git log | head -1`;
if ($data =~ /commit\s*([a-z0-9]+)/i) {
my $data = `git describe`;
if ($data =~ /(verilator.*)/i) {
$rev = $1;
}
$data = `git status`;
if ($data !~ /nothing to commit/i) {
if ($data =~ /Changed but not updated/i
|| $data =~ /Changes to be committed/i) {
$rev .= " (mod)";
}
+38 -32
View File
@@ -44,6 +44,10 @@ extern void yyerrorf(const char* format, ...);
#define FL { yylval.fileline = CRELINE(); }
#define RETURN_BBOX_SYS_OR_MSG(msg,yytext) { \
if (v3Global.opt.bboxSys()) return yD_aIGNORE; \
else yyerrorf(msg,yytext); }
void V3Read::ppline (const char* textp) {
// Handle `line directive
fileline()->lineDirective(textp);
@@ -132,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 */
@@ -144,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 */
@@ -239,18 +244,18 @@ escid \\[^ \t\f\r\n]+
"xnor" { FL; return yXNOR; }
"xor" { FL; return yXOR; }
/* Special errors */
"$displayb" { yyerrorf("Unsupported: Use $display with %%b format instead: %s",yytext); }
"$displayh" { yyerrorf("Unsupported: Use $display with %%x format instead: %s",yytext); }
"$displayo" { yyerrorf("Unsupported: Use $display with %%o format instead: %s",yytext); }
"$fdisplayb" { yyerrorf("Unsupported: Use $fdisplay with %%b format instead: %s",yytext); }
"$fdisplayh" { yyerrorf("Unsupported: Use $fdisplay with %%x format instead: %s",yytext); }
"$fdisplayo" { yyerrorf("Unsupported: Use $fdisplay with %%o format instead: %s",yytext); }
"$fwriteb" { yyerrorf("Unsupported: Use $fwrite with %%b format instead: %s",yytext); }
"$fwriteh" { yyerrorf("Unsupported: Use $fwrite with %%x format instead: %s",yytext); }
"$fwriteo" { yyerrorf("Unsupported: Use $fwrite with %%o format instead: %s",yytext); }
"$writeb" { yyerrorf("Unsupported: Use $write with %%b format instead: %s",yytext); }
"$writeh" { yyerrorf("Unsupported: Use $write with %%x format instead: %s",yytext); }
"$writeo" { yyerrorf("Unsupported: Use $write with %%o format instead: %s",yytext); }
"$displayb" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%b format instead: %s",yytext); }
"$displayh" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%x format instead: %s",yytext); }
"$displayo" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $display with %%o format instead: %s",yytext); }
"$fdisplayb" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%b format instead: %s",yytext); }
"$fdisplayh" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%x format instead: %s",yytext); }
"$fdisplayo" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fdisplay with %%o format instead: %s",yytext); }
"$fwriteb" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%b format instead: %s",yytext); }
"$fwriteh" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%x format instead: %s",yytext); }
"$fwriteo" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $fwrite with %%o format instead: %s",yytext); }
"$writeb" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%b format instead: %s",yytext); }
"$writeh" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%x format instead: %s",yytext); }
"$writeo" { RETURN_BBOX_SYS_OR_MSG("Unsupported: Use $write with %%o format instead: %s",yytext); }
/* Generic unsupported warnings */
"cmos" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
"deassign" { yyerrorf("Unsupported: Verilog 1995 reserved word not implemented: %s",yytext); }
@@ -358,6 +363,7 @@ escid \\[^ \t\f\r\n]+
"endproperty" { FL; return yENDPROPERTY; }
"final" { FL; return yFINAL; }
"iff" { FL; return yIFF; }
"logic" { FL; return yLOGIC; }
"priority" { FL; return yPRIORITY; }
"static" { FL; return ySTATIC; }
"timeprecision" { FL; return yTIMEPRECISION; }
@@ -407,7 +413,6 @@ escid \\[^ \t\f\r\n]+
"join_any" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"join_none" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"local" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"logic" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"longint" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -461,7 +466,7 @@ escid \\[^ \t\f\r\n]+
/* Default PLI rule */
<V95,V01,V05,S05,PSL>{
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { yyerrorf("Unsupported or unknown PLI call: %s",yytext); }
"$"[a-zA-Z_$][a-zA-Z0-9_$]* { FL; RETURN_BBOX_SYS_OR_MSG("Unsupported or unknown PLI call: %s",yytext); }
}
/************************************************************************/
@@ -761,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 (*");
@@ -791,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
@@ -802,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
@@ -810,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
@@ -823,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); }
@@ -834,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(); }
}
/************************************************************************/
+75 -44
View File
@@ -113,6 +113,12 @@ static AstNode* newVarInit(FileLine* fileline, AstNode* varp, AstNode* initp) {
#define INSTPREP(modname,paramsp) { V3Parse::s_impliedDecl = true; V3Parse::s_instModule = modname; V3Parse::s_instParamp = paramsp; }
static void ERRSVKWD(FileLine* fileline, const string& tokname) {
static int toldonce = 0;
fileline->v3error((string)"Unexpected \""+tokname+"\": \""+tokname+"\" is a SystemVerilog keyword misused as an identifier.");
if (!toldonce++) fileline->v3error("Modify the Verilog-2001 code to avoid SV keywords, or use `begin_keywords or --language.");
}
//======================================================================
class AstSenTree;
@@ -246,6 +252,7 @@ class AstSenTree;
%token<fileline> yGENVAR "genvar"
%token<fileline> yIF "if"
%token<fileline> yIFF "iff"
%token<fileline> yLOGIC "logic"
%token<fileline> yINITIAL "initial"
%token<fileline> yINOUT "inout"
%token<fileline> yINPUT "input"
@@ -320,6 +327,7 @@ class AstSenTree;
%token<fileline> yD_UNSIGNED "$unsigned"
%token<fileline> yD_WARNING "$warning"
%token<fileline> yD_WRITE "$write"
%token<fileline> yD_aIGNORE "${ignored-bbox-sys}"
%token<fileline> yPSL "psl"
%token<fileline> yPSL_ASSERT "PSL assert"
@@ -656,6 +664,7 @@ port_declNetE: // IEEE: part of port_declaration, optional net type
portSig<portp>:
id/*port*/ { $$ = new AstPort(CRELINE(),PINNUMINC(),*$1); }
| idSVKwd { $$ = new AstPort(CRELINE(),PINNUMINC(),*$1); }
;
//**********************************************************************
@@ -823,6 +832,7 @@ data_type<rangep>: // ==IEEE: data_type
data_typeNoRef<rangep>: // ==IEEE: data_type, excluding class_type etc references
yINTEGER { VARDECL(INTEGER); $$ = new AstRange($1,31,0); $$->isSigned(true); }
| yREG signingE rangeListE { VARDECL(REG); $$ = $3; }
| yLOGIC signingE rangeListE { VARDECL(REG); $$ = $3; }
//UNSUP: above instead of integer_type
//
//UNSUP integer_type signingE regArRangeE { UNSUP }
@@ -852,6 +862,7 @@ variable_decl_assignment<varp>: // ==IEEE: variable_decl_assignment
| id variable_dimensionListE sigAttrListE '=' variable_declExpr
{ $$ = VARDONEA(*$1,$2,$3);
$$->addNext(new AstInitial($4,new AstAssign($4, new AstVarRef($4, *$1, true), $5))); }
| idSVKwd { $$ = NULL; }
//
// // IEEE: "dynamic_array_variable_identifier '[' ']' [ '=' dynamic_array_new ]"
// // Matches above with variable_dimensionE = "[]"
@@ -1094,24 +1105,23 @@ genvar_initialization<nodep>: // ==IEEE: genvar_initalization
;
genvar_iteration<nodep>: // ==IEEE: genvar_iteration
varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); }
//UNSUP id '=' expr { UNSUP }
//UNSUP id yP_PLUSEQ expr { UNSUP }
//UNSUP id yP_MINUSEQ expr { UNSUP }
//UNSUP id yP_TIMESEQ expr { UNSUP }
//UNSUP id yP_DIVEQ expr { UNSUP }
//UNSUP id yP_MODEQ expr { UNSUP }
//UNSUP id yP_ANDEQ expr { UNSUP }
//UNSUP id yP_OREQ expr { UNSUP }
//UNSUP id yP_XOREQ expr { UNSUP }
//UNSUP id yP_SLEFTEQ expr { UNSUP }
//UNSUP id yP_SRIGHTEQ expr { UNSUP }
//UNSUP id yP_SSRIGHTEQ expr { UNSUP }
varRefBase '=' expr { $$ = new AstAssign($2,$1,$3); }
| varRefBase yP_PLUSEQ expr { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_MINUSEQ expr { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_TIMESEQ expr { $$ = new AstAssign($2,$1,new AstMul ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_DIVEQ expr { $$ = new AstAssign($2,$1,new AstDiv ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_MODEQ expr { $$ = new AstAssign($2,$1,new AstModDiv ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_ANDEQ expr { $$ = new AstAssign($2,$1,new AstAnd ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_OREQ expr { $$ = new AstAssign($2,$1,new AstOr ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_XOREQ expr { $$ = new AstAssign($2,$1,new AstXor ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_SLEFTEQ expr { $$ = new AstAssign($2,$1,new AstShiftL ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_SRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftR ($2,$1->cloneTree(true),$3)); }
| varRefBase yP_SSRIGHTEQ expr { $$ = new AstAssign($2,$1,new AstShiftRS($2,$1->cloneTree(true),$3)); }
// // inc_or_dec_operator
//UNSUP yP_PLUSPLUS id { UNSUP }
//UNSUP yP_MINUSMINUS id { UNSUP }
//UNSUP id yP_PLUSPLUS { UNSUP }
//UNSUP id yP_MINUSMINUS { UNSUP }
| yP_PLUSPLUS varRefBase { $$ = new AstAssign($1,$2,new AstAdd ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
| yP_MINUSMINUS varRefBase { $$ = new AstAssign($1,$2,new AstSub ($1,$2->cloneTree(true),new AstConst($1,V3Number($1,"'b1")))); }
| varRefBase yP_PLUSPLUS { $$ = new AstAssign($2,$1,new AstAdd ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
| varRefBase yP_MINUSMINUS { $$ = new AstAssign($2,$1,new AstSub ($2,$1->cloneTree(true),new AstConst($2,V3Number($2,"'b1")))); }
;
case_generate_itemListE<nodep>: // IEEE: [{ case_generate_itemList }]
@@ -1187,6 +1197,7 @@ netSig<varp>: // IEEE: net_decl_assignment - one element from list_of_port_id
netId<strp>:
id/*new-net*/ { $$ = $1; }
| idSVKwd { $$ = $1; }
;
sigId<varp>:
@@ -1313,6 +1324,7 @@ cellpinItList<pinp>: // IEEE: list_of_port_connections + list_of_parameter_assi
cellpinItemE<pinp>: // IEEE: named_port_connection + named_parameter_assignment + empty
/* empty: ',,' is legal */ { $$ = NULL; PINNUMINC(); }
| yP_DOTSTAR { $$ = new AstPin($1,PINNUMINC(),".*",NULL); }
| '.' idSVKwd { $$ = NULL; PINNUMINC(); }
| '.' idAny { $$ = new AstPin($1,PINNUMINC(),*$2,new AstVarRef($1,*$2,false)); $$->svImplicit(true);}
| '.' idAny '(' ')' { $$ = NULL; PINNUMINC(); }
| '.' idAny '(' expr ')' { $$ = new AstPin($1,PINNUMINC(),*$2,$4); }
@@ -1383,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); }
@@ -1651,7 +1664,10 @@ function_subroutine_callNoMethod<nodep>: // IEEE: function_subroutine_call (as f
system_t_call<nodep>: // IEEE: system_tf_call (as task)
//
yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
yD_aIGNORE '(' ')' { $$ = NULL; }
| yD_aIGNORE '(' exprList ')' { $$ = NULL; }
//
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCStmt($1,$3)); }
| yD_FCLOSE '(' idClassSel ')' { $$ = new AstFClose($1, $3); }
| yD_FFLUSH { $1->v3error("Unsupported: $fflush of all handles does not map to C++.\n"); }
| yD_FFLUSH '(' ')' { $1->v3error("Unsupported: $fflush of all handles does not map to C++.\n"); }
@@ -1661,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); }
@@ -1685,15 +1701,18 @@ system_t_call<nodep>: // IEEE: system_tf_call (as task)
;
system_f_call<nodep>: // IEEE: system_tf_call (as func)
yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::BITS,$3); }
yD_aIGNORE '(' ')' { $$ = new AstConst($1,V3Number($1,"'b0")); } // Unsized 0
| yD_aIGNORE '(' exprList ')' { $$ = new AstConst($1,V3Number($1,"'b0")); } // Unsized 0
//
| yD_BITS '(' expr ')' { $$ = new AstAttrOf($1,AstAttrType::BITS,$3); }
| yD_C '(' cStrList ')' { $$ = (v3Global.opt.ignc() ? NULL : new AstUCFunc($1,$3)); }
| yD_CLOG2 '(' expr ')' { $$ = new AstCLog2($1,$3); }
| yD_COUNTONES '(' expr ')' { $$ = new AstCountOnes($1,$3); }
| 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); }
@@ -2173,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)); }
@@ -2182,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))); }
@@ -2191,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); }
@@ -2284,6 +2303,12 @@ idAny<strp>: // Any kind of identifier
yaID__ETC { $$ = $1; }
;
idSVKwd<strp>: // Warn about non-forward compatible Verilog 2001 code
// // yBIT, yBYTE won't work here as causes conflicts
yDO { static string s = "do" ; $$ = &s; ERRSVKWD($1,*$$); }
| yFINAL { static string s = "final"; $$ = &s; ERRSVKWD($1,*$$); }
;
variable_lvalue<nodep>: // IEEE: variable_lvalue or net_lvalue
// // Note many variable_lvalue's must use exprOkLvalue when arbitrary expressions may also exist
idClassSel { $$ = $1; }
@@ -2347,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)));}
;
@@ -2568,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;
+1
View File
@@ -10,3 +10,4 @@ simx*
ncverilog.*
INCA_libs
logs
.vcsmx_rebuild
+4 -2
View File
@@ -24,11 +24,13 @@ include $(VERILATOR_ROOT)/include/verilated.mk
######################################################################
ifneq ($(VCS_HOME),)
PRODUCTS += --vcs
#Default to off, even with vcs; not all tests are insured to be working
#PRODUCTS += --vcs
endif
ifneq ($(NC_ROOT),)
PRODUCTS += --nc
#Default to off, even with vcs; not all tests are insured to be working
#PRODUCTS += --nc
endif
PRODUCTS += --v3
+118 -28
View File
@@ -4,16 +4,16 @@
require 5.006_001;
BEGIN {
if (my $Project=($ENV{DIRPROJECT}||$ENV{PROJECT})) {
if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
# Magic to allow author testing of perl packages in local directory
require "$Project/hw/utils/perltools/boot.pl";
require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
}
}
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);
@@ -25,6 +25,9 @@ $Fork = Forker->new(use_sig_child=>1) if !$Fork;
$SIG{CHLD} = sub { $Fork->sig_child() if $Fork; };
$SIG{TERM} = sub { $Fork->kill_tree_all('TERM') if $Fork; die "Quitting...\n"; };
our $Have_System_Perl;
eval "use SystemC::Netlist; \$Have_System_Perl=1;";
#======================================================================
#======================================================================
@@ -39,33 +42,37 @@ our @Orig_ARGV_Sw; foreach (@Orig_ARGV) { push @Orig_ARGV_Sw, $_ if /^-/ && !/^
$Debug = 0;
my $opt_benchmark;
my @opt_tests;
my $opt_nc;
my $opt_vcs;
my $opt_v3;
my $opt_stop;
my $opt_optimize;
my $opt_trace;
my $opt_gdb;
my $opt_gdbbt;
my $opt_iv;
my $opt_jobs = 1;
my $opt_nc;
my $opt_optimize;
my $opt_stop;
my $opt_trace;
my $opt_v3;
my $opt_vcs;
my $opt_verbose;
my $Opt_Verilated_Debug;
our @Opt_Driver_Verilator_Flags;
Getopt::Long::config ("pass_through");
if (! GetOptions (
"help" => \&usage,
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
"debug" => \&debug,
"vcs!" => \$opt_vcs,
"verilated_debug!" => \$Opt_Verilated_Debug,
"j=i" => \$opt_jobs,
"v3!" => \$opt_v3,
"nc!" => \$opt_nc,
"benchmark:i" => sub { $opt_benchmark = $_[1] ? $_[1] : 1; },
"gdb!" => \$opt_gdb,
"gdbbt!" => \$opt_gdbbt,
"help" => \&usage,
"iverilog!" => \$opt_iv,
"j=i" => \$opt_jobs,
"nc!" => \$opt_nc,
"optimize:s" => \$opt_optimize,
"stop!" => \$opt_stop,
"trace!" => \$opt_trace,
"v3!" => \$opt_v3,
"vcs!" => \$opt_vcs,
"verbose!" => \$opt_verbose,
"verilated_debug!" => \$Opt_Verilated_Debug,
"<>" => \&parameter,
)) {
die "%Error: Bad usage, try '$0 --help'\n";
@@ -75,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;
}
@@ -90,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;
}
@@ -233,16 +241,21 @@ sub new {
sim_time => 1000,
benchmark => $opt_benchmark,
# All compilers
v_flags => [split(/\s+/,(" -f input.vc --debug-check"
v_flags => [split(/\s+/,(" -f input.vc "
.($opt_verbose ? " +define+TEST_VERBOSE=1":"")
.($opt_benchmark ? " +define+TEST_BENCHMARK=$opt_benchmark":"")
.($opt_trace ? " +define+WAVES=1":"")
))],
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 +v2k")],
vcs_flags => [split(/\s+/,"+cli -I +define+vcs+1 -q -sverilog")],
vcs_flags2 => [], # Overridden in some sim files
# NC
nc => 0,
@@ -252,7 +265,8 @@ sub new {
# Verilator
'v3' => 0,
verilator_flags => ["-cc",
"-Mdir $self->{obj_dir}"],
"-Mdir $self->{obj_dir}",
"--debug-check"],
verilator_flags2 => [],
verilator_make_gcc => 1,
verilated_debug => $Opt_Verilated_Debug,
@@ -263,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";
@@ -384,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;
@@ -419,6 +451,10 @@ sub compile {
$self->error("Test requires SystemC; ignore error since not installed\n");
return 1;
}
elsif ($self->{trace} && !$Have_System_Perl) {
$self->error("Test requires SystemPerl; ignore error since not installed\n");
return 1;
}
$self->_run(logfile=>"$self->{obj_dir}/vl_compile.log",
fails=>$param{fails},
@@ -454,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},
@@ -895,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;
@@ -1024,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.
+2 -7
View File
@@ -87,13 +87,8 @@ module Test (/*AUTOARG*/
// merge the output values into the result vector.
input clk;
input [31:0] in;
output [31:0] out;
/*AUTOREG*/
// Beginning of automatic regs (for this module's undeclared outputs)
reg [31:0] out;
// End of automatics
input [31:0] in;
output reg [31:0] out;
always @(posedge clk) begin
out <= in;
+4 -4
View File
@@ -9,13 +9,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
top_filename("t/t_math_synmul.v");
my $cycles = $Self->{benchmark}||0;
$cycles = 100 if $cycles<100;
$Self->{cycles} = $Self->{benchmark}||0;
$Self->{cycles} = 100 if $Self->{cycles}<100;
$Self->{sim_time} = $cycles*100;
$Self->{sim_time} = $Self->{cycles}*100;
compile (
v_flags2 => ["+define+SIM_CYCLES=${cycles}"],
v_flags2 => ["+define+SIM_CYCLES=$Self->{cycles}"],
);
execute (
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+81
View File
@@ -0,0 +1,81 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module t (/*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 [1:0] in = crc[1:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [1:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[1:0]),
// Inputs
.in (in[1:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {62'h0, out};
// What checksum will we end up with
`define EXPECTED_SUM 64'hbb2d9709592f64bd
// 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;
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;
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
in
);
input [1:0] in;
output reg [1:0] out;
always @* begin
// bug99: Internal Error: ../V3Ast.cpp:495: New node already linked?
case (in[1:0])
2'd0, 2'd1, 2'd2, 2'd3: begin
out = in;
end
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+95
View File
@@ -0,0 +1,95 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
reg [63:0] crc;
reg [63:0] sum;
// Take CRC data and apply to testblock inputs
wire [2:0] in = (crc[1:0]==0 ? 3'd0
: crc[1:0]==0 ? 3'd1
: crc[1:0]==0 ? 3'd2 : 3'd4);
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [31:0] out; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.out (out[31:0]),
// Inputs
.clk (clk),
.in (in[2:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {32'h0, out};
// Test loop
always @ (posedge clk) begin
`ifdef TEST_VERBOSE
$write("[%0t] cyc==%0d crc=%x result=%x\n",$time, cyc, crc, result);
`endif
cyc <= cyc + 1;
crc <= {crc[62:0], crc[63]^crc[2]^crc[0]};
sum <= result ^ {sum[62:0],sum[63]^sum[2]^sum[0]};
if (cyc==0) begin
// Setup
crc <= 64'h5aef0c8d_d70a4497;
sum <= 64'h0;
end
else if (cyc<10) begin
sum <= 64'h0;
end
else if (cyc<90) begin
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
if (crc !== 64'hc77bb9b3784ea091) $stop;
// What checksum will we end up with (above print should match)
`define EXPECTED_SUM 64'h704ca23e2a83e1c5
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
out,
// Inputs
clk, in
);
// Replace this module with the device under test.
//
// Change the code in the t module to apply values to the inputs and
// merge the output values into the result vector.
input clk;
input [2:0] in;
output reg [31:0] out;
localparam ST_0 = 0;
localparam ST_1 = 1;
localparam ST_2 = 2;
always @(posedge clk) begin
case (1'b1) // synopsys parallel_case
in[ST_0]: out <= 32'h1234;
in[ST_1]: out <= 32'h4356;
in[ST_2]: out <= 32'h9874;
default: out <= 32'h1;
endcase
end
endmodule
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
@@ -3,17 +3,12 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
`include "verilated.v"
module t_case(/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
output passed; reg passed; initial passed = 0;
reg _ranit;
reg rnd;
@@ -111,17 +106,11 @@ module t_case(/*AUTOARG*/
//
if (rnd) begin
// This gets covered
$write("");
end
if (rnd) begin
// This doesn't
// verilator coverage_block_off
$write("");
end
//
$write("[%0t] t_case: Passed\n", $time);
passed <= 1'b1;
$write("*-* All Finished *-*\n");
$finish;
end
end
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003-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.
compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_const_dec_mixed_bad.v:\d+: Mixing X/Z/\? with digits not legal in decimal constant: x_1
%Error: Exiting due to.*',
);
ok(1);
1;
+10
View File
@@ -0,0 +1,10 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005-2007 by Wilson Snyder.
module t (/*AUTOARG*/);
parameter [200:0] MIXED = 32'dx_1;
endmodule
+22
View File
@@ -0,0 +1,22 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# 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.
compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_const_overflow_bad.v:\d+: Too many digits for 94 bit number: 94\'d123456789012345678901234567890
%Error: t/t_const_overflow_bad.v:\d+: Too many digits for 8 bit number: 8\'habc
%Error: t/t_const_overflow_bad.v:\d+: Too many digits for 6 bit number: 6\'o1234
%Error: t/t_const_overflow_bad.v:\d+: Too many digits for 3 bit number: 3\'b1111
%Error: Exiting due to.*',
);
ok(1);
1;
+17
View File
@@ -0,0 +1,17 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2005-2007 by Wilson Snyder.
module t (/*AUTOARG*/);
parameter [200:0] TOO_SMALL = 94'd123456789012345678901234567890; // One to many digits
parameter [200:0] SMALLH = 8'habc; // One to many digits
parameter [200:0] SMALLO = 6'o1234; // One to many digits
parameter [200:0] SMALLB = 3'b1111; // One to many digits
// We'll allow this though; no reason to be cruel
parameter [200:0] OKH = 8'h000000001;
endmodule
+9 -2
View File
@@ -12,7 +12,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@@ -26,9 +26,16 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
[0] Embedded
multiline
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;
+4 -1
View File
@@ -37,6 +37,9 @@ module t;
$display("[%0t] %s%s%s", $time,
"hel", "lo, fr", "om a very long string. Percent %s are literally substituted in.");
$write("[%0t] Embedded \r return\n", $time);
$display("[%0t] Embedded\
multiline", $time);
// Str check
`ifndef nc // NC-Verilog 5.3 chokes on this test
@@ -52,7 +55,7 @@ module sub;
begin
$write("[%0t] In %m\n", $time);
begin : subblock
$write("[%0t] In %m\n", $time);
$write("[%0t] In %M\n", $time); // Uppercase %M test
end
end
endtask
+9 -2
View File
@@ -15,7 +15,7 @@ compile (
execute (
check_finished=>1,
expect=>quotemeta(
expect=>quotemeta(dequote(
'[0] In TOP.v: Hi
[0] In TOP.v.sub
[0] In TOP.v.sub.subblock
@@ -29,9 +29,16 @@ execute (
[0] %s=! %s= what! %s= hmmm!1234
[0] hello, from a very long string. Percent %s are literally substituted in.
[0] Embedded <#013> return
[0] Embedded
multiline
*-* All Finished *-*
'),
')),
);
ok(1);
# Don't put control chars into our source repository, pre-compress instead
sub dequote { my $s = shift; $s =~ s/<#013>/\r/g; $s; }
1;
+19
View File
@@ -0,0 +1,19 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2008 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--bbox-sys"],
) if $Self->{v3};
execute (
check_finished=>1,
) if $Self->{v3};
ok(1);
1;
+14
View File
@@ -0,0 +1,14 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2008 by Wilson Snyder.
module a;
reg a;
initial begin
$unknown_sys_task_call_to_be_bbox("blah");
a = $unknown_sys_func_call(23);
$write("*-* All Finished *-*\n");
$finish;
end
endmodule

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