Compare commits

...
53 Commits
Author SHA1 Message Date
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
113 changed files with 2485 additions and 758 deletions
+56
View File
@@ -3,6 +3,62 @@ 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.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.
+8 -2
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. ####
######################################################################
@@ -106,8 +109,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING *.in *.ac \
MANIFEST.SKIP \
bin/* \
install-sh configure mkinstalldirs *.texi \
include/verilated.[chv]* \
include/verilatedos.[chv]* \
include/verilated*.[chv]* \
include/*.in \
include/.*ignore \
.*attributes */.*attributes */*/.*attributes \
@@ -271,6 +273,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; \
+141 -26
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};
}
}
@@ -179,6 +179,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 +194,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 +215,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 +229,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 +273,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 +453,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 +530,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 +625,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
@@ -696,6 +729,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 +866,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 +1169,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.
@@ -1596,17 +1655,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 +1825,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
@@ -1921,6 +1991,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
@@ -2197,26 +2274,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
+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
+1 -2
View File
@@ -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
+2 -2
View File
@@ -228,8 +228,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}
+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()));
}
}
+5
View File
@@ -176,6 +176,11 @@ string AstNode::prettyName(const string& namein) {
return pretty;
}
string AstNode::prettyTypeName() const {
if (name()=="") return typeName();
return string(typeName())+" '"+prettyName()+"'";
}
int AstNode::widthPow2() const {
// I.e. width 30 returns 32, width 32 returns 32.
uint32_t width = this->width();
+53 -52
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); }
@@ -188,10 +188,10 @@ public:
};
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 +223,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 +252,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 +264,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 +281,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 +303,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 +331,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); }
@@ -520,9 +520,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
@@ -640,7 +640,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,6 +669,7 @@ 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
@@ -676,6 +677,7 @@ public:
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
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; }
@@ -979,7 +981,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 +1059,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 +1136,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 +1169,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(); }
+7 -1
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";
}
+17 -26
View File
@@ -251,13 +251,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 +270,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 +308,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; }
@@ -432,7 +425,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 +565,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 +605,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 +642,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 +672,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 {
@@ -714,7 +707,7 @@ public:
}
ASTNODE_NODE_FUNCS(Begin, BEGIN)
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); }
@@ -942,7 +935,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,7 +954,7 @@ 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 {
@@ -1249,7 +1242,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 +1262,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 +1283,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 +1371,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 +1410,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,7 +1428,6 @@ 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; }
@@ -2636,7 +2627,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 +2809,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); }
+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();
+1 -1
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);
+59 -16
View File
@@ -39,6 +39,7 @@
#include "V3Ast.h"
#include "V3Width.h"
#include "V3Signed.h"
#include "V3Simulate.h"
//######################################################################
// Utilities
@@ -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
@@ -1420,6 +1452,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()) {
@@ -1674,7 +1713,7 @@ 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()) {
@@ -1708,12 +1747,16 @@ public:
void V3Const::constifyParam(AstNode* nodep) {
//if (debug()>0) nodep->dumpTree(cout," forceConPRE : ");
if (!nodep->width()) {
V3Width::widthParams(nodep);
V3Signed::signedParams(nodep);
}
V3Width::widthSignedIfNotAlready(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.main(varp->initp());
} else {
visitor.main(nodep);
}
// Because we do edits, nodep links may get trashed and core dump this.
//if (debug()>0) nodep->dumpTree(cout," forceConDONE: ");
}
+1 -1
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 {
+11 -8
View File
@@ -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:
@@ -1410,7 +1410,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 +1796,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");
@@ -1885,8 +1888,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 +1897,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()<<"'");
}
}
}
+3 -3
View File
@@ -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); }
+20 -2
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,6 +297,7 @@ 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()+": ";
@@ -352,12 +355,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));
+23 -16
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,6 +59,7 @@ 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
@@ -75,38 +78,41 @@ 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",
"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
@@ -114,7 +120,7 @@ public:
|| m_e==IMPLICIT
|| 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 +138,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
@@ -175,12 +182,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; } }
+1 -1
View File
@@ -62,7 +62,7 @@ class V3FileDependImp {
}
}
}
bool operator<(const DependFile& rhs) const { return filename()<rhs.filename(); };
bool operator<(const DependFile& rhs) const { return filename()<rhs.filename(); }
};
// MEMBERS
+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
@@ -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
@@ -156,7 +156,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
+3 -2
View File
@@ -361,7 +361,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 +441,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); }
};
};
+27 -22
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*) {
+25 -12
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;
}
+1 -1
View File
@@ -108,7 +108,7 @@ 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);
+56 -27
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; }
@@ -897,6 +891,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;
+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);
+1 -1
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();
+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); }
+8
View File
@@ -127,6 +127,14 @@ private:
}
virtual void visit(AstCell* nodep, AstNUser*);
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
if (nodep->isParam()) {
if (!nodep->hasSimpleInit()) { nodep->v3fatalSrc("Parameter without initial value"); }
V3Const::constifyParam(nodep); // The variable, not just the var->init()
}
}
// Generate Statements
virtual void visit(AstGenerate* nodep, AstNUser*) {
if (debug()>=9) nodep->dumpTree(cout,"-genin: ");
+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
+28 -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
@@ -131,6 +130,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 +204,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 +223,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 +268,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 +278,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 +291,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
+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(); }
+1 -1
View File
@@ -179,7 +179,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 %
+599
View File
@@ -0,0 +1,599 @@
// -*- 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");
V3Width::widthSignedIfNotAlready(funcp); // Make sure we've sized the function
// 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
+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;
+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 {
+2
View File
@@ -207,6 +207,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
@@ -649,6 +650,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();
+1
View File
@@ -102,6 +102,7 @@ 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()) {
+43 -12
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()) {
@@ -218,7 +235,9 @@ private:
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));
}
@@ -424,6 +443,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()) {
@@ -439,8 +460,11 @@ private:
}
if (nodep->initp()) {
nodep->initp()->iterateAndNext(*this,WidthVP(width,0,BOTH).p());
if (nodep->isParam() && !nodep->rangep()) {
if (nodep->initp()->widthSized()) {
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");
@@ -702,7 +726,7 @@ 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;
}
@@ -712,7 +736,7 @@ private:
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
}
@@ -829,7 +853,7 @@ public:
m_taskDepth = 0;
m_cellRangep = NULL;
m_casep = NULL;
nodep->accept(*this);
nodep->accept(*this, WidthVP(ANYSIZE,0,BOTH).p());
}
virtual ~WidthVisitor() {}
};
@@ -946,11 +970,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.");
@@ -969,9 +993,9 @@ void WidthVisitor::widthCheckReduce (AstNode* nodep, const char* side,
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.");
@@ -988,7 +1012,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.");
@@ -1174,6 +1198,13 @@ void V3Width::widthParams(AstNode* nodep) {
WidthVisitor visitor (nodep, true);
}
void V3Width::widthSignedIfNotAlready(AstNode* nodep) {
if (!nodep->width()) {
V3Width::widthParams(nodep);
V3Signed::signedParams(nodep);
}
}
void V3Width::widthCommit(AstNode* nodep) {
UINFO(2,__FUNCTION__<<": "<<endl);
WidthCommitVisitor visitor (nodep);
+1
View File
@@ -34,6 +34,7 @@ public:
static void width(AstNetlist* nodep);
// Smaller step... Only do a single node for parameter propagation
static void widthParams(AstNode* nodep);
static void widthSignedIfNotAlready(AstNode* nodep);
// Final step... Mark all widths as equal
static void widthCommit(AstNode* nodep);
};
+1 -1
View File
@@ -25,7 +25,7 @@
//**********************************************************************
//**** Version and host name
#define DTVERSION "Verilator 3.710 2009/05/19"
#define DTVERSION "Verilator 3.714 2009/09/18"
//**********************************************************************
//**** Functions
+18 -14
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);
@@ -239,18 +243,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 +362,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 +412,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 +465,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); }
}
/************************************************************************/
+43 -19
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); }
@@ -1651,7 +1663,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"); }
@@ -1685,7 +1700,10 @@ 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); }
@@ -2284,6 +2302,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; }
+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
+13 -5
View File
@@ -4,9 +4,9 @@
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};
}
}
@@ -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;";
#======================================================================
#======================================================================
@@ -233,7 +236,7 @@ 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":"")
@@ -242,7 +245,7 @@ sub new {
v_other_filenames => [], # After the filename so we can spec multiple files
# 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 +255,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,
@@ -419,6 +423,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},
+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
+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
+1 -1
View File
@@ -52,7 +52,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
+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
+3
View File
@@ -8,6 +8,9 @@ module t;
`ifndef GOT_DEF2
$write("%%Error: NO GOT_DEF2\n"); $stop;
`endif
`ifndef GOT_DEF3
$write("%%Error: NO GOT_DEF3\n"); $stop;
`endif
`ifdef NON_DEF
$write("%%Error: NON_DEF\n"); $stop;
`endif
+2
View File
@@ -1,2 +1,4 @@
// Test that environment substitutions work
-f $VERILATOR_ROOT/test_regress/t/t_flag_f__2.vc
// Env var with .v file
$VERILATOR_ROOT/test_regress/t/t_flag_f__3.v
+1
View File
@@ -0,0 +1 @@
`define GOT_DEF3 1
+2 -2
View File
@@ -13,9 +13,9 @@ compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Warning-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
q{%Warning-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST '6'h2e' generates 6 bits.
%Warning-WIDTH: Use .* and lint_on around source to disable this message.
%Error: Exiting due to',
%Error: Exiting due to},
) if $Self->{v3};
ok(1);
+2 -2
View File
@@ -14,8 +14,8 @@ compile (
fails=>$Self->{v3},
verilator_flags=> [qw(-sp -Werror-WIDTH)],
expect=>
'%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST generates 6 bits.
%Error: Exiting due to',
q{%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST '6'h2e' generates 6 bits.
%Error: Exiting due to},
) if $Self->{v3};
ok(1);
+16
View File
@@ -0,0 +1,16 @@
#!/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 ()
ok(1);
1;
+37
View File
@@ -0,0 +1,37 @@
// 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*/
// Outputs
priority_mask,
// Inputs
muxed_requests
);
parameter ARW = 7;
// verilator lint_off UNOPTFLAT
integer i,j;
output reg [ARW-1:0] priority_mask;
input [ARW-1:0] muxed_requests;
always @* begin
for (i=ARW-1;i>0;i=i-1) begin
priority_mask[i]=1'b0;
// vvvv=== note j=j not j=i; was bug
for( j=j;j>=0;j=j-1)
priority_mask[i]=priority_mask[j] | muxed_requests[j];
end
//Bit zero is always enabled
priority_mask[0]=1'b0;
end
endmodule
// Local Variables:
// verilog-auto-inst-param-value: t
// End:
+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,15 +3,12 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2003 by Wilson Snyder.
module t_loop (/*AUTOARG*/
// Outputs
passed,
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
output passed; reg passed; initial passed = 0;
reg [7:0] cyc; initial cyc=0;
reg [31:0] loops;
@@ -53,8 +50,8 @@ module t_loop (/*AUTOARG*/
end
if (loops !== 100000) $stop;
//
$write("[%0t] t_loop: Passed\n",$time);
passed <= 1'b1;
$write("*-* All Finished *-*\n");
$finish;
end
end
+3 -3
View File
@@ -11,10 +11,10 @@ compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Warning-WIDTH: t/t_func_bad_width.v:\d+: Operator FUNCREF expects 40 bits on the Function Argument, but Function Argument.s VARREF generates 39 bits.
q{%Warning-WIDTH: t/t_func_bad_width.v:\d+: Operator FUNCREF 'MUX' expects 40 bits on the Function Argument, but Function Argument's VARREF 'in' generates 39 bits.
%Warning-WIDTH: Use [^\n]+
%Warning-WIDTH: t/t_func_bad_width.v:\d+: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS.s FUNCREF generates 32 bits.
%Error: Exiting due to',
%Warning-WIDTH: t/t_func_bad_width.v:\d+: Operator ASSIGN expects 4 bits on the Assign RHS, but Assign RHS.s FUNCREF 'MUX' generates 32 bits.
%Error: Exiting due to},
);
ok(1);
+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;
+72
View File
@@ -0,0 +1,72 @@
// 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;
localparam P4 = f_add(P3,1);
localparam P8 = f_add2(P3,P3,f_add(1,1));
localparam P5 = f_while(7);
localparam P16 = f_for(P4);
localparam P18 = f_case(P4);
localparam P3 = 3;
initial begin
`ifdef TEST_VERBOSE
$display("P5=%0d P8=%0d P16=%0d P18=%0d",P5,P8,P16,P18);
`endif
if (P3 !== 3) $stop;
if (P4 !== 4) $stop;
if (P5 !== 5) $stop;
if (P8 !== 8) $stop;
if (P16 !== 16) $stop;
if (P18 !== 18) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
function integer f_add(input [31:0] a, input [31:0] b);
f_add = a+b;
endfunction
// Speced ok: function called from function
function integer f_add2(input [31:0] a, input [31:0] b, input [31:0] c);
f_add2 = f_add(a,b)+c;
endfunction
// Speced ok: local variables
function integer f_for(input [31:0] a);
integer i;
integer times;
begin
times = 1;
for (i=0; i<a; i=i+1) times = times*2;
f_for = times;
end
endfunction
function integer f_while(input [31:0] a);
integer i;
begin
i=0;
begin : named
f_while = 1;
end : named
while (i<=a) begin
if (i[0]) f_while = f_while + 1;
i = i + 1;
end
end
endfunction
// Speced ok: local variables
function integer f_case(input [31:0] a);
case(a)
32'd1: f_case = 1;
32'd0, 32'd4: f_case = 18;
32'd1234: begin $display("never get here"); $stop; end
default: f_case = 99;
endcase
endfunction
endmodule
+28
View File
@@ -0,0 +1,28 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
q{%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_output'
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VAR 'o': Language violation: Outputs not allowed in constant functions
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_dotted'
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARXREF 'EIGHT': Language violation: Dotted hierarchical references not allowed in constant functions
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_nonparam'
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant VARREF 'modvar': Language violation: reference to non-function-local variable
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_infinite'
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant WHILE: Loop unrolling took too long; probably this is an infinite loop, or set --unroll-count above 1024
%Error: t/t_func_const_bad.v:\d+: Expecting expression to be constant, but can't determine constant for FUNCREF 'f_bad_stop'
%Error: t/t_func_const_bad.v:\d+: ... Location of non-constant STOP: .stop executed during function constification; maybe indicates assertion firing
%Error: Exiting due to.*},
);
ok(1);
1;
+48
View File
@@ -0,0 +1,48 @@
// 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;
// Speced ignored: system calls. I think this is nasty, so we error instead.
// Speced Illegal: inout/output/ref not allowed
localparam B1 = f_bad_output(1,2);
function integer f_bad_output(input [31:0] a, output [31:0] o);
f_bad_output = 0;
endfunction
// Speced Illegal: void
// Speced Illegal: dotted
localparam EIGHT = 8;
localparam B2 = f_bad_dotted(2);
function integer f_bad_dotted(input [31:0] a);
f_bad_dotted = t.EIGHT;
endfunction
// Speced Illegal: ref to non-local var
integer modvar;
localparam B3 = f_bad_nonparam(3);
function integer f_bad_nonparam(input [31:0] a);
f_bad_nonparam = modvar;
endfunction
// Speced Illegal: needs constant function itself
// Our own - infinite loop
localparam B4 = f_bad_infinite(3);
function integer f_bad_infinite(input [31:0] a);
while (1) begin
f_bad_infinite = 0;
end
endfunction
// Our own - stop
localparam BSTOP = f_bad_stop(3);
function integer f_bad_stop(input [31:0] a);
$stop;
endfunction
endmodule
+14 -8
View File
@@ -18,19 +18,21 @@ module t (/*AUTOARG*/
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [2:0] pos; // From test of Test.v
wire [2:0] pos1; // From test of Test.v
wire [2:0] pos2; // From test of Test.v
// End of automatics
Test test (
// Outputs
.pos (pos[2:0]),
.pos1 (pos1[2:0]),
.pos2 (pos2[2:0]),
/*AUTOINST*/
// Inputs
.clk (clk),
.rst_n (rst_n));
// Aggregate outputs into a single result vector
wire [63:0] result = {61'h0, pos};
wire [63:0] result = {61'h0, pos1};
// What checksum will we end up with
`define EXPECTED_SUM 64'h039ea4d039c2e70b
@@ -54,6 +56,7 @@ module t (/*AUTOARG*/
rst_n <= ~1'b1;
end
else if (cyc<90) begin
if (pos1 !== pos2) $stop;
end
else if (cyc==99) begin
$write("[%0t] cyc==%0d crc=%x sum=%x\n",$time, cyc, crc, sum);
@@ -69,11 +72,12 @@ endmodule
module Test
#(parameter SAMPLE_WIDTH = 5 )
(
`ifdef verilator // UNSUPPORTED
output reg [$clog2(SAMPLE_WIDTH)-1:0] pos,
`ifdef verilator // Some simulators don't support clog2
output reg [$clog2(SAMPLE_WIDTH)-1:0] pos1,
`else
output reg [log2(SAMPLE_WIDTH-1)-1:0] pos,
output reg [log2(SAMPLE_WIDTH-1)-1:0] pos1,
`endif
output reg [log2(SAMPLE_WIDTH-1)-1:0] pos2,
// System
input clk,
input rst_n
@@ -88,9 +92,11 @@ module Test
always @ (posedge clk or negedge rst_n)
if (!rst_n) begin
pos <= 0;
pos1 <= 0;
pos2 <= 0;
end
else begin
pos <= pos + 1;
pos1 <= pos1 + 1;
pos2 <= pos2 + 1;
end
endmodule
+2 -2
View File
@@ -86,14 +86,14 @@ module tpub (
$c("publicNoArgs();");
$c("publicSetBool(true);");
$c("publicSetLong(0x11bca);");
$c("publicSetQuad(0x66655554444);");
$c("publicSetQuad(VL_ULL(0x66655554444));");
$c("publicSetFlop(0x321);");
//Unsupported: $c("WData w[3] = {0x12, 0x5678_9123, 0x1245_2352}; publicSetWide(w);");
end
if (cyc==12) begin
$c("got_bool = publicGetSetBool(true);");
$c("got_long = publicGetSetLong(0x11bca);");
$c("got_quad = publicGetSetQuad(0xaaaabbbbcccc);");
$c("got_quad = publicGetSetQuad(VL_ULL(0xaaaabbbbcccc));");
end
if (cyc==13) begin
$c("{ bool gb; publicGetBool(gb); got_bool=gb; }");
+18
View File
@@ -0,0 +1,18 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 2003 by Wilson Snyder. This program is free software; you can
# redistribute it and/or modify it under the terms of either the GNU
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
compile (
);
execute (
check_finished=>1,
);
ok(1);
1;
+93
View File
@@ -0,0 +1,93 @@
// DESCRIPTION: Verilator: Verilog Test module
//
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2009 by Wilson Snyder.
module t (/*AUTOARG*/
// Inputs
clk
);
input clk;
integer cyc=0;
genvar g;
reg [31:0] gen_pre_PLUSPLUS = 32'h0;
reg [31:0] gen_pre_MINUSMINUS = 32'h0;
reg [31:0] gen_post_PLUSPLUS = 32'h0;
reg [31:0] gen_post_MINUSMINUS = 32'h0;
reg [31:0] gen_PLUSEQ = 32'h0;
reg [31:0] gen_MINUSEQ = 32'h0;
reg [31:0] gen_TIMESEQ = 32'h0;
reg [31:0] gen_DIVEQ = 32'h0;
reg [31:0] gen_MODEQ = 32'h0;
reg [31:0] gen_ANDEQ = 32'h0;
reg [31:0] gen_OREQ = 32'h0;
reg [31:0] gen_XOREQ = 32'h0;
reg [31:0] gen_SLEFTEQ = 32'h0;
reg [31:0] gen_SRIGHTEQ = 32'h0;
reg [31:0] gen_SSRIGHTEQ = 32'h0;
generate
for (g=8; g<=16; ++g) always @(posedge clk) gen_pre_PLUSPLUS[g] = 1'b1;
for (g=16; g>=8; --g) always @(posedge clk) gen_pre_MINUSMINUS[g] = 1'b1;
for (g=8; g<=16; g++) always @(posedge clk) gen_post_PLUSPLUS[g] = 1'b1;
for (g=16; g>=8; g--) always @(posedge clk) gen_post_MINUSMINUS[g] = 1'b1;
for (g=8; g<=16; g+=2) always @(posedge clk) gen_PLUSEQ[g] = 1'b1;
for (g=16; g>=8; g-=2) always @(posedge clk) gen_MINUSEQ[g] = 1'b1;
`ifndef verilator //UNSUPPORTED
for (g=8; g<=16; g*=2) always @(posedge clk) gen_TIMESEQ[g] = 1'b1;
for (g=16; g>=8; g/=2) always @(posedge clk) gen_DIVEQ[g] = 1'b1;
for (g=15; g>8; g%=8) always @(posedge clk) gen_MODEQ[g] = 1'b1;
for (g=7; g>4; g&=4) always @(posedge clk) gen_ANDEQ[g] = 1'b1;
for (g=1; g<=1; g|=2) always @(posedge clk) gen_OREQ[g] = 1'b1;
for (g=7; g==7; g^=2) always @(posedge clk) gen_XOREQ[g] = 1'b1;
for (g=8; g<=16; g<<=2) always @(posedge clk) gen_SLEFTEQ[g] = 1'b1;
for (g=16; g>=8; g>>=2) always @(posedge clk) gen_SRIGHTEQ[g] = 1'b1;
for (g=16; g>=8; g>>>=2) always @(posedge clk) gen_SSRIGHTEQ[g] = 1'b1;
`endif
endgenerate
always @ (posedge clk) begin
cyc <= cyc + 1;
if (cyc == 3) begin
`ifdef TEST_VERBOSE
$write("gen_pre_PLUSPLUS %b\n", gen_pre_PLUSPLUS);
$write("gen_pre_MINUSMINUS %b\n", gen_pre_MINUSMINUS);
$write("gen_post_PLUSPLUS %b\n", gen_post_PLUSPLUS);
$write("gen_post_MINUSMINUS %b\n", gen_post_MINUSMINUS);
$write("gen_PLUSEQ %b\n", gen_PLUSEQ);
$write("gen_MINUSEQ %b\n", gen_MINUSEQ);
$write("gen_TIMESEQ %b\n", gen_TIMESEQ);
$write("gen_DIVEQ %b\n", gen_DIVEQ);
$write("gen_MODEQ %b\n", gen_MODEQ);
$write("gen_ANDEQ %b\n", gen_ANDEQ);
$write("gen_OREQ %b\n", gen_OREQ);
$write("gen_XOREQ %b\n", gen_XOREQ);
$write("gen_SLEFTEQ %b\n", gen_SLEFTEQ);
$write("gen_SRIGHTEQ %b\n", gen_SRIGHTEQ);
$write("gen_SSRIGHTEQ %b\n", gen_SSRIGHTEQ);
`endif
if (gen_pre_PLUSPLUS !== 32'b00000000000000011111111100000000) $stop;
if (gen_pre_MINUSMINUS !== 32'b00000000000000011111111100000000) $stop;
if (gen_post_PLUSPLUS !== 32'b00000000000000011111111100000000) $stop;
if (gen_post_MINUSMINUS!== 32'b00000000000000011111111100000000) $stop;
if (gen_PLUSEQ !== 32'b00000000000000010101010100000000) $stop;
if (gen_MINUSEQ !== 32'b00000000000000010101010100000000) $stop;
`ifndef verilator //UNSUPPORTED
if (gen_TIMESEQ !== 32'b00000000000000010000000100000000) $stop;
if (gen_DIVEQ !== 32'b00000000000000010000000100000000) $stop;
if (gen_MODEQ !== 32'b00000000000000001000000000000000) $stop;
if (gen_ANDEQ !== 32'b00000000000000000000000010000000) $stop;
if (gen_OREQ !== 32'b00000000000000000000000000000010) $stop;
if (gen_XOREQ !== 32'b00000000000000000000000010000000) $stop;
if (gen_SLEFTEQ !== 32'b00000000000000000000000100000000) $stop;
if (gen_SRIGHTEQ !== 32'b00000000000000010000000000000000) $stop;
if (gen_SSRIGHTEQ !== 32'b00000000000000010000000000000000) $stop;
`endif
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
+2 -2
View File
@@ -11,8 +11,8 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'%Error: t/t_inst_array_bad.v:\d+: Port connection __pinNumber2 as part of a module instance array requires 1 or 8 bits, but connection\'s VARREF generates 9 bits.
%Error: Exiting due to.*',
q{%Error: t/t_inst_array_bad.v:\d+: Port connection __pinNumber2 as part of a module instance array requires 1 or 8 bits, but connection's VARREF 'onebitbad' generates 9 bits.
%Error: Exiting due to.*},
);
ok(1);
+5 -5
View File
@@ -16,12 +16,12 @@ compile (
verilator_make_gcc=>0,
fails=>$Self->{v3},
expect=>
'%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outy_w92 expects 92 bits but connection\'s VARREF generates 30 bits.
q{%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outy_w92 expects 92 bits but connection's VARREF 'outc_w30' generates 30 bits.
%Warning-WIDTH: Use .* to disable this message.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outz_w22 expects 22 bits but connection\'s VARREF generates 73 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inw_w31 expects 31 bits but connection\'s VARREF generates 1 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inx_w11 expects 11 bits but connection\'s VARREF generates 61 bits.
%Error: Exiting due to.*',
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Output port connection outz_w22 expects 22 bits but connection's VARREF 'outd_w73' generates 73 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inw_w31 expects 31 bits but connection's VARREF 'ina_w1' generates 1 bits.
%Warning-WIDTH: t/t_inst_overwide.v:\d+: Input port connection inx_w11 expects 11 bits but connection's VARREF 'inb_w61' generates 61 bits.
%Error: Exiting due to.*},
);
ok(1);
+2 -2
View File
@@ -11,9 +11,9 @@ compile (
v_flags2 => ["--lint-only"],
fails=>1,
expect=>
'.*%Warning-WIDTH: t/t_lint_restore_bad.v:\d+: Operator ASSIGN expects 5 bits on the Assign RHS, but Assign RHS\'s CONST generates 64 bits.
q{.*%Warning-WIDTH: t/t_lint_restore_bad.v:\d+: Operator ASSIGN expects 5 bits on the Assign RHS, but Assign RHS's CONST '64'h1' generates 64 bits.
%Warning-WIDTH: Use .*
%Error: Exiting due to.*',
%Error: Exiting due to.*},
) if $Self->{v3};
ok(1);
+20
View File
@@ -0,0 +1,20 @@
#!/usr/bin/perl
if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); die; }
# DESCRIPTION: Verilator: Verilog Test driver/expect definition
#
# Copyright 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=>
q{.*%Warning-WIDTH: t/t_lint_width_bad.v:\d+: Operator ASSIGNW expects 5 bits on the Assign RHS, but Assign RHS's VARREF 'in' generates 4 bits.
%Warning-WIDTH: Use .*
%Error: Exiting due to.*},
) if $Self->{v3};
ok(1);
1;
+19
View File
@@ -0,0 +1,19 @@
// 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 ();
// This shows the uglyness in width warnings across param modules
// TODO: Would be nice to also show relevant parameter settings
p #(.WIDTH(4)) p4 (.in(4'd0));
p #(.WIDTH(5)) p5 (.in(5'd0));
endmodule
module p
#(parameter WIDTH=64)
(input [WIDTH-1:0] in);
wire [4:0] out = in;
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;
+87
View File
@@ -0,0 +1,87 @@
// 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 [15:0] in = crc[15:0];
/*AUTOWIRE*/
// Beginning of automatic wires (for undeclared instantiated-module outputs)
wire [15:0] outa; // From test of Test.v
wire [15:0] outb; // From test of Test.v
wire [15:0] outc; // From test of Test.v
// End of automatics
Test test (/*AUTOINST*/
// Outputs
.outa (outa[15:0]),
.outb (outb[15:0]),
.outc (outc[15:0]),
// Inputs
.clk (clk),
.in (in[15:0]));
// Aggregate outputs into a single result vector
wire [63:0] result = {16'h0, outa, outb, outc};
// 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'h09be74b1b0f8c35d
if (sum !== `EXPECTED_SUM) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
module Test (/*AUTOARG*/
// Outputs
outa, outb, outc,
// Inputs
clk, in
);
input clk;
input [15:0] in;
output reg [15:0] outa;
output reg [15:0] outb;
output reg [15:0] outc;
parameter WIDTH = 0;
always @(posedge clk) begin
outa <= {in};
outb <= {{WIDTH{1'b0}}, in};
outc <= {in, {WIDTH{1'b0}}};
end
endmodule
+4
View File
@@ -84,6 +84,10 @@ module t (/*AUTOARG*/
if ( con__ascii !== {"abcd","efgh","ijkl","mnop"}) $stop;
if ( 3'dx !== 3'hx) $stop;
// Wide decimal
if ( 94'd12345678901234567890123456789 != 94'h27e41b3246bec9b16e398115) $stop;
if (-94'sd123456789012345678901234567 != 94'h3f99e1020ea70d57d360b479) $stop;
end
if (cyc==2) begin
win <= 32'h123123;
+3 -1
View File
@@ -36,8 +36,10 @@ module t (/*AUTOARG*/
endmodule
module m1;
localparam PAR1MINUS1 = PAR1DUP-2-1;
localparam PAR1DUP = PAR1+2; // Check we propagate parameters properly
parameter PAR1 = 0;
m2 #(PAR1-1) m2 ();
m2 #(PAR1MINUS1) m2 ();
endmodule
module m2;
+7 -1
View File
@@ -191,4 +191,10 @@ Line_Preproc_Check 131
(x,y )
Line_Preproc_Check 144
`line 146 "t/t_preproc.v" 2
x,y)--bee submacro has comma paren
`line 152 "t/t_preproc.v" 2
+2 -2
View File
@@ -7,7 +7,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Lesser General Public License Version 3 or the Perl Artistic License
# Version 2.0.
$golden_out ||= "t/$Self->{name}.out";
$Self->{golden_out} ||= "t/$Self->{name}.out";
my $stdout_filename = "$Self->{obj_dir}/$Self->{name}__test.vpp";
if (!$Self->{v3}) {
@@ -19,7 +19,7 @@ if (!$Self->{v3}) {
stdout_filename => $stdout_filename,
);
ok(preproc_check($Self->{top_filename}, $stdout_filename)
&& files_identical($stdout_filename, $golden_out));
&& files_identical($stdout_filename, $Self->{golden_out}));
}
sub preproc_check {
+6
View File
@@ -143,3 +143,9 @@ Line_Preproc_Check `__LINE__
)
Line_Preproc_Check `__LINE__
//======================================================================
// misparsed comma in submacro
`define sb bee
`define sa(l) x,y)
`define sfoo(q,r) q--r
`sfoo(`sa(el),`sb) submacro has comma paren
+3 -3
View File
@@ -12,7 +12,7 @@ top_filename("$Self->{obj_dir}/$Self->{name}.v");
# Rather then having to maintain a new .v and .out, simply add returns
# to all lines of the existing t_preproc test.
$golden_out ||= "$Self->{obj_dir}/$Self->{name}.out";
$Self->{golden_out} = "$Self->{obj_dir}/$Self->{name}.out";
{
my $wholefile = file_contents("$Self->{t_dir}/t_preproc.v");
@@ -22,9 +22,9 @@ $golden_out ||= "$Self->{obj_dir}/$Self->{name}.out";
{
my $wholefile = file_contents("$Self->{t_dir}/t_preproc.out");
$wholefile =~ s!t/t_preproc.v!$Self->{obj_dir}/t_preproc_dos.v!og; # Fix `line's
write_wholefile($golden_out, $wholefile);
write_wholefile($Self->{golden_out}, $wholefile);
}
require 't/t_preproc.pl';
do 't/t_preproc.pl';
1;
-2
View File
@@ -7,7 +7,6 @@ module t (/*AUTOARG*/);
reg signed [2:0] negcnt;
integer times;
integer repeats;
initial begin
times = 0;
repeat (1) begin
@@ -23,7 +22,6 @@ module t (/*AUTOARG*/);
end
if (times != 10) $stop;
//
repeats = 0;
forever begin
$write("*-* All Finished *-*\n");
$finish;
@@ -8,12 +8,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
v_flags2 => ["--lint-only"],
fails=>$Self->{v3},
expect=>
'%Error: t/t_var_bad_rsvd.v:\d+: Unsupported: C\+\+ common word: bool
%Error: t/t_var_bad_rsvd.v:\d+: Unsupported: C\+\+ reserved word: switch
%Error: Exiting due to.*',
q{%Error: t/t_select_bad_tri.v:\d+: Selection index is constantly unknown or tristated: lsb=7'bxxxxxxx width=\?32\?sh47
%Error: Exiting due to.*},
);
ok(1);
1;

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