[Pkg-electronics-commits] [SCM] Packaging for Verilator branch, master, updated. debian/3.847-1-3-g29f91a8
أحمد المحمو =?UTF-8?Q?=D8=AF=D9=8A=20?=(Ahmed El-Mahmoudy)
aelmahmoudy at sabily.org
Mon Jun 10 08:04:56 UTC 2013
The following commit has been merged in the master branch:
commit 37ae114c2dd915fc7e7d0ff75ebe309ef8015bf9
Author: أحمد المحمودي (Ahmed El-Mahmoudy) <aelmahmoudy at sabily.org>
Date: Mon Jun 10 09:45:35 2013 +0200
Imported Upstream version 3.850
diff --git a/Changes b/Changes
index 7cb2dbf..72649f4 100644
--- a/Changes
+++ b/Changes
@@ -3,6 +3,19 @@ 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.850 2013-06-02
+
+** Support interfaces and modports, bug102. [Byron Bradley, Jeremy Bennett]
+
+*** Duplicate clock gate optimization on by default, bug621.
+
+**** Fix arrayed input compile error, bug645. [Krzysztof Jankowski]
+
+**** Fix GCC version runtime changes, bug651. [Jeremy Bennett]
+
+**** Fix packed array select internal error, bug652. [Krzysztof Jankowski]
+
+
* Verilator 3.847 2013-05-11
*** Add ALWCOMBORDER warning. [KC Buckenmaier]
diff --git a/README b/README
index fa2517d..ab36570 100644
--- a/README
+++ b/README
@@ -19,14 +19,14 @@ DISTRIBUTION
DESCRIPTION
- Verilator converts synthesizable (not behavioral) Verilog code into C++
- or SystemC code. It is not a complete simulator, just a translator.
+ Verilator converts synthesizable (generally not behavioral) Verilog code
+ into C++ or SystemC code. It is not a complete simulator, just a
+ translator.
Verilator is invoked with parameters similar to GCC or Synopsys's VCS.
It reads the specified Verilog code, lints it, and optionally adds
coverage code. For C++ format, it outputs .cpp and .h files. For SystemC
- format, it outputs .sp files for the SystemPerl preprocessor available
- at http://www.veripool.org.
+ format, it outputs .cpp and .h files using the standard SystemC headers.
The resulting files are then compiled with C++. The user writes a little
C++ wrapper file, which instantiates the top level module. This is
@@ -36,15 +36,12 @@ DESCRIPTION
SUPPORTED SYSTEMS
- Verilator is developed and has primary testing on:
-
- SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2
-
- Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris.
- It should run with minor porting on any Linix-ish platform. Verilator
- also works on Windows under Cygwin, and Windows under MinGW (gcc
- -mno-cygwin). Verilated output (not Verilator itself) compiles under
- MSVC++ 2008.
+ Verilator is developed and has primary testing on Ubuntu. Versions have
+ also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
+ with minor porting on any Linix-ish platform. Verilator also works on
+ Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
+ Verilated output (not Verilator itself) compiles under MSVC++ 2008 and
+ newer.
INSTALLATION
@@ -62,11 +59,11 @@ INSTALLATION
tar xvzf verilator_version.tgz
* If you will be using SystemC (vs straight C++ output), download
- SystemC 2.0.1 from <http://www.systemc.org>. Follow their
- installation instructions. You will need to set SYSTEMC_INCLUDE to
- point to the include directory with systemc.h in it, and
- SYSTEMC_LIBDIR to points to the directory with libsystemc.a in it.
- (Older installations may set SYSTEMC and SYSTEMC_ARCH instead.)
+ SystemC from <http://www.systemc.org>. Follow their installation
+ instructions. You will need to set SYSTEMC_INCLUDE to point to the
+ include directory with systemc.h in it, and SYSTEMC_LIBDIR to points
+ to the directory with libsystemc.a in it. (Older installations may
+ set SYSTEMC and SYSTEMC_ARCH instead.)
* If you will be using SystemPerl or coverage, download and install
System-Perl, <http://www.veripool.org/systemperl>. Note you'll need
@@ -88,8 +85,8 @@ INSTALLATION
1. Our personal favorite is to always run Verilator from the kit
directory. This allows the easiest experimentation and
- upgrading. It's also how most EDA tools operate; to run any of
- them you point to the tarball.
+ upgrading. It's also how most EDA tools operate; to run you
+ point to the tarball, no install is needed.
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
@@ -129,11 +126,10 @@ INSTALLATION
* Type "make" to compile Verilator.
- Type "make test_c" to check the compilation.
+ Type "make test" to check the compilation.
- Type "make test" for a more complete test. You may get a error about
- the Bit::Vector Perl package. You will need to install it and
- SystemPerl if you want all tests to pass.
+ Configure with "--enable-longtests" for more complete developer
+ tests. Additional packages may be required for these tests.
You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
@@ -164,7 +160,7 @@ DIRECTORY STRUCTURE
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
- include/verilated.h => Global headers
+ include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
diff --git a/README.html b/README.html
index 667e55b..c2ead5b 100644
--- a/README.html
+++ b/README.html
@@ -53,13 +53,13 @@ more details.</p>
</p>
<hr />
<h1><a name="description">DESCRIPTION</a></h1>
-<p>Verilator converts synthesizable (not behavioral) Verilog code into C++ or
-SystemC code. It is not a complete simulator, just a translator.</p>
+<p>Verilator converts synthesizable (generally not behavioral) Verilog code
+into C++ or SystemC code. It is not a complete simulator, just a
+translator.</p>
<p>Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
reads the specified Verilog code, lints it, and optionally adds coverage
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
-it outputs .sp files for the SystemPerl preprocessor available at
-<a href="http://www.veripool.org.">http://www.veripool.org.</a></p>
+it outputs .cpp and .h files using the standard SystemC headers.</p>
<p>The resulting files are then compiled with C++. The user writes a little
C++ wrapper file, which instantiates the top level module. This is
compiled in C++, and linked with the Verilated files.</p>
@@ -68,13 +68,11 @@ compiled in C++, and linked with the Verilated files.</p>
</p>
<hr />
<h1><a name="supported_systems">SUPPORTED SYSTEMS</a></h1>
-<p>Verilator is developed and has primary testing on:</p>
-<pre>
- SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2</pre>
-<p>Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It
-should run with minor porting on any Linix-ish platform. Verilator also
-works on Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
-Verilated output (not Verilator itself) compiles under MSVC++ 2008.</p>
+<p>Verilator is developed and has primary testing on Ubuntu. Versions have
+also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
+with minor porting on any Linix-ish platform. Verilator also works on
+Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
+output (not Verilator itself) compiles under MSVC++ 2008 and newer.</p>
<p>
</p>
<hr />
@@ -94,11 +92,11 @@ will let you track changes.</p>
<dt>
<dd>
<p>If you will be using SystemC (vs straight C++ output), download SystemC
-2.0.1 from <a href="http://www.systemc.org">http://www.systemc.org</a>. Follow their installation
-instructions. You will need to set SYSTEMC_INCLUDE to point to the
-include directory with systemc.h in it, and SYSTEMC_LIBDIR to points
-to the directory with libsystemc.a in it. (Older installations may
-set SYSTEMC and SYSTEMC_ARCH instead.)</p>
+from <a href="http://www.systemc.org">http://www.systemc.org</a>. Follow their installation instructions.
+You will need to set SYSTEMC_INCLUDE to point to the include directory with
+systemc.h in it, and SYSTEMC_LIBDIR to points to the directory with
+libsystemc.a in it. (Older installations may set SYSTEMC and SYSTEMC_ARCH
+instead.)</p>
</dd>
<dt>
<dd>
@@ -126,7 +124,7 @@ executable, so try to have them correct before configuring.</p>
<li>
<p>Our personal favorite is to always run Verilator from the kit directory.
This allows the easiest experimentation and upgrading. It's also how most
-EDA tools operate; to run any of them you point to the tarball.</p>
+EDA tools operate; to run you point to the tarball, no install is needed.</p>
<pre>
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
@@ -170,10 +168,9 @@ PATH.</p>
<dt>
<dd>
<p>Type <code>make</code> to compile Verilator.</p>
-<p>Type <code>make test_c</code> to check the compilation.</p>
-<p>Type <code>make test</code> for a more complete test. You may get a error about the
-Bit::Vector Perl package. You will need to install it and SystemPerl if
-you want all tests to pass.</p>
+<p>Type <code>make test</code> to check the compilation.</p>
+<p>Configure with <code>--enable-longtests</code> for more complete developer tests.
+Additional packages may be required for these tests.</p>
<p>You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
unsigned long uint32_t;}.</p>
@@ -207,7 +204,7 @@ set.</p>
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
- include/verilated.h => Global headers
+ include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
diff --git a/README.pdf b/README.pdf
index cdae039..625e547 100644
Binary files a/README.pdf and b/README.pdf differ
diff --git a/bin/verilator b/bin/verilator
index 2616245..4784bac 100755
--- a/bin/verilator
+++ b/bin/verilator
@@ -1920,16 +1920,12 @@ uwire keyword.
=head2 SystemVerilog 2005 (IEEE 1800-2005) Support
-Verilator currently has some support for SystemVerilog synthesis
-constructs. As SystemVerilog features enter common usage they are added;
-please file a bug if a feature you need is missing.
-
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
-const, do-while, enum, export, final, import, int, logic, longint, package,
-program, shortint, struct, time, typedef, union, var, void, priority
-case/if, and unique case/if.
+const, do-while, enum, export, final, import, int, interface, logic,
+longint, modport, package, program, shortint, struct, time, typedef, union,
+var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
@@ -2605,6 +2601,12 @@ and continue keywords.
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
+=item interface
+
+Interfaces and modports, including with generated data types are supported.
+Generate blocks around modports are not supported, nor are virtual
+interfaces nor unnamed interfaces.
+
=item priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted to be
diff --git a/configure b/configure
index 7d149c9..092d7b1 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
#! /bin/sh
# Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for Verilator 3.847 2013-05-11.
+# Generated by GNU Autoconf 2.68 for Verilator 3.850 2013-06-02.
#
#
# Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -557,8 +557,8 @@ MAKEFLAGS=
# Identity of this package.
PACKAGE_NAME='Verilator'
PACKAGE_TARNAME='verilator'
-PACKAGE_VERSION='3.847 2013-05-11'
-PACKAGE_STRING='Verilator 3.847 2013-05-11'
+PACKAGE_VERSION='3.850 2013-06-02'
+PACKAGE_STRING='Verilator 3.850 2013-06-02'
PACKAGE_BUGREPORT=''
PACKAGE_URL=''
@@ -1223,7 +1223,7 @@ if test "$ac_init_help" = "long"; then
# Omit some internal or obsolete options to make the list less imposing.
# This message is too long to be a string in the A/UX 3.1 sh.
cat <<_ACEOF
-\`configure' configures Verilator 3.847 2013-05-11 to adapt to many kinds of systems.
+\`configure' configures Verilator 3.850 2013-06-02 to adapt to many kinds of systems.
Usage: $0 [OPTION]... [VAR=VALUE]...
@@ -1284,7 +1284,7 @@ fi
if test -n "$ac_init_help"; then
case $ac_init_help in
- short | recursive ) echo "Configuration of Verilator 3.847 2013-05-11:";;
+ short | recursive ) echo "Configuration of Verilator 3.850 2013-06-02:";;
esac
cat <<\_ACEOF
@@ -1376,7 +1376,7 @@ fi
test -n "$ac_init_help" && exit $ac_status
if $ac_init_version; then
cat <<\_ACEOF
-Verilator configure 3.847 2013-05-11
+Verilator configure 3.850 2013-06-02
generated by GNU Autoconf 2.68
Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1633,7 +1633,7 @@ cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
-It was created by Verilator $as_me 3.847 2013-05-11, which was
+It was created by Verilator $as_me 3.850 2013-06-02, which was
generated by GNU Autoconf 2.68. Invocation command line was
$ $0 $@
@@ -4565,7 +4565,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
# report actual input values of CONFIG_FILES etc. instead of their
# values after options handling.
ac_log="
-This file was extended by Verilator $as_me 3.847 2013-05-11, which was
+This file was extended by Verilator $as_me 3.850 2013-06-02, which was
generated by GNU Autoconf 2.68. Invocation command line was
CONFIG_FILES = $CONFIG_FILES
@@ -4627,7 +4627,7 @@ _ACEOF
cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
ac_cs_version="\\
-Verilator config.status 3.847 2013-05-11
+Verilator config.status 3.850 2013-06-02
configured by $0, generated by GNU Autoconf 2.68,
with options \\"\$ac_cs_config\\"
diff --git a/configure.ac b/configure.ac
index e22b04a..3e9a8a2 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,7 @@
#AC_INIT([Verilator],[#.### YYYY-MM-DD])
#AC_INIT([Verilator],[#.### devel])
-AC_INIT([Verilator],[3.847 2013-05-11])
+AC_INIT([Verilator],[3.850 2013-06-02])
AC_CONFIG_HEADER(src/config_build.h)
AC_CONFIG_FILES(Makefile src/Makefile src/Makefile_obj include/verilated.mk include/verilated_config.h)
diff --git a/include/verilated_config.h b/include/verilated_config.h
index 7690a1e..7489cf3 100644
--- a/include/verilated_config.h
+++ b/include/verilated_config.h
@@ -25,4 +25,4 @@
// Autoconf substitutes this with the strings from AC_INIT.
#define VERILATOR_PRODUCT "Verilator"
-#define VERILATOR_VERSION "3.847 2013-05-11"
+#define VERILATOR_VERSION "3.850 2013-06-02"
diff --git a/internals.pdf b/internals.pdf
index f2d57f1..00cda40 100644
Binary files a/internals.pdf and b/internals.pdf differ
diff --git a/readme.pod b/readme.pod
index 9262b18..beef0a0 100644
--- a/readme.pod
+++ b/readme.pod
@@ -24,14 +24,14 @@ more details.
=head1 DESCRIPTION
-Verilator converts synthesizable (not behavioral) Verilog code into C++ or
-SystemC code. It is not a complete simulator, just a translator.
+Verilator converts synthesizable (generally not behavioral) Verilog code
+into C++ or SystemC code. It is not a complete simulator, just a
+translator.
Verilator is invoked with parameters similar to GCC or Synopsys's VCS. It
reads the specified Verilog code, lints it, and optionally adds coverage
code. For C++ format, it outputs .cpp and .h files. For SystemC format,
-it outputs .sp files for the SystemPerl preprocessor available at
-http://www.veripool.org.
+it outputs .cpp and .h files using the standard SystemC headers.
The resulting files are then compiled with C++. The user writes a little
C++ wrapper file, which instantiates the top level module. This is
@@ -41,14 +41,11 @@ The resulting executable will perform the actual simulation.
=head1 SUPPORTED SYSTEMS
-Verilator is developed and has primary testing on:
-
- SuSE 11.1 AMD64 i686-linux-2.6.27, GCC 4.3.2
-
-Versions have also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It
-should run with minor porting on any Linix-ish platform. Verilator also
-works on Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin).
-Verilated output (not Verilator itself) compiles under MSVC++ 2008.
+Verilator is developed and has primary testing on Ubuntu. Versions have
+also built on Redhat Linux, Macs OS-X, HPUX and Solaris. It should run
+with minor porting on any Linix-ish platform. Verilator also works on
+Windows under Cygwin, and Windows under MinGW (gcc -mno-cygwin). Verilated
+output (not Verilator itself) compiles under MSVC++ 2008 and newer.
=head1 INSTALLATION
@@ -71,11 +68,11 @@ Download the latest package from that site, and decompress.
=item
If you will be using SystemC (vs straight C++ output), download SystemC
-2.0.1 from L<http://www.systemc.org>. Follow their installation
-instructions. You will need to set SYSTEMC_INCLUDE to point to the
-include directory with systemc.h in it, and SYSTEMC_LIBDIR to points
-to the directory with libsystemc.a in it. (Older installations may
-set SYSTEMC and SYSTEMC_ARCH instead.)
+from L<http://www.systemc.org>. Follow their installation instructions.
+You will need to set SYSTEMC_INCLUDE to point to the include directory with
+systemc.h in it, and SYSTEMC_LIBDIR to points to the directory with
+libsystemc.a in it. (Older installations may set SYSTEMC and SYSTEMC_ARCH
+instead.)
=item
@@ -107,7 +104,7 @@ executable, so try to have them correct before configuring.
Our personal favorite is to always run Verilator from the kit directory.
This allows the easiest experimentation and upgrading. It's also how most
-EDA tools operate; to run any of them you point to the tarball.
+EDA tools operate; to run you point to the tarball, no install is needed.
export VERILATOR_ROOT=`pwd` # if your shell is bash
setenv VERILATOR_ROOT `pwd` # if your shell is csh
@@ -156,11 +153,10 @@ PATH.
Type C<make> to compile Verilator.
-Type C<make test_c> to check the compilation.
+Type C<make test> to check the compilation.
-Type C<make test> for a more complete test. You may get a error about the
-Bit::Vector Perl package. You will need to install it and SystemPerl if
-you want all tests to pass.
+Configure with C<--enable-longtests> for more complete developer tests.
+Additional packages may be required for these tests.
You may get a error about a typedef conflict for uint32_t. Edit
verilated.h to change the typedef to work, probably to @samp{typedef
@@ -195,7 +191,7 @@ The directories in the kit after de-taring are as follows:
bin/verilator => Compiler Wrapper invoked to Verilate code
include/ => Files that should be in your -I compiler path
include/verilated*.cpp => Global routines to link into your simulator
- include/verilated.h => Global headers
+ include/verilated*.h => Global headers
include/verilated.v => Stub defines for linting
include/verilated.mk => Common makefile
src/ => Translator source code
diff --git a/src/V3Ast.h b/src/V3Ast.h
index 7d58a3f..0413cc1 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -38,6 +38,9 @@ class VFlagLogicPacked {};
class VFlagBitPacked {};
class VFlagChildDType {}; // Used by parser.y to select constructor that sets childDType
+// For broken() function, return error string if have a match
+#define BROKEN_RTN(test) do { if (VL_UNLIKELY(test)) return # test; } while(0)
+
//######################################################################
class AstType {
@@ -407,7 +410,8 @@ public:
BLOCKTEMP,
MODULETEMP,
STMTTEMP,
- XTEMP
+ XTEMP,
+ IFACEREF // Used to link Interfaces between modules
};
enum en m_e;
inline AstVarType () : m_e(UNKNOWN) {}
@@ -421,7 +425,8 @@ public:
"SUPPLY0","SUPPLY1","WIRE","IMPLICITWIRE",
"TRIWIRE","TRI0","TRI1",
"PORT",
- "BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP"};
+ "BLOCKTEMP","MODULETEMP","STMTTEMP","XTEMP",
+ "IFACEREF"};
return names[m_e]; }
bool isSignal() const { return (m_e==WIRE || m_e==IMPLICITWIRE
|| m_e==TRIWIRE
@@ -1171,7 +1176,7 @@ public:
virtual bool hasDType() const { return false; } // Iff has a data type; dtype() must be non null
virtual AstNodeDType* getChildDTypep() const { return NULL; } // Iff has a non-null childDTypep(), as generic node function
virtual bool maybePointedTo() const { return false; } // Another AstNode* may have a pointer into this node, other then normal front/back/etc.
- virtual bool broken() const { return false; }
+ virtual const char* broken() const { return NULL; }
// INVOKERS
virtual void accept(AstNVisitor& v, AstNUser* vup=NULL) = 0;
@@ -1472,7 +1477,7 @@ public:
}
ASTNODE_BASE_FUNCS(NodeVarRef)
virtual bool hasDType() const { return true; }
- virtual bool broken() const;
+ virtual const char* broken() const;
virtual int instrCount() const { return widthInstrs(); }
virtual void cloneRelink();
virtual string name() const { return m_name; } // * = Var name
@@ -1579,7 +1584,7 @@ public:
numeric(numericUnpack.isSigned() ? AstNumeric::SIGNED : AstNumeric::UNSIGNED);
}
ASTNODE_BASE_FUNCS(NodeClassDType)
- virtual bool broken() const;
+ virtual const char* broken() const;
virtual void dump(ostream& str);
// For basicp() we reuse the size to indicate a "fake" basic type of same size
virtual AstBasicDType* basicp() const { return findLogicDType(width(),width(),numeric())->castBasicDType(); }
@@ -1615,8 +1620,8 @@ public:
ASTNODE_BASE_FUNCS(NodeArrayDType)
virtual void dump(ostream& str);
virtual void dumpSmall(ostream& str);
- virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
- || (!m_refDTypep && childDTypep())); }
+ virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
+ || (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -1740,7 +1745,7 @@ public:
addNOp2p(pinsp);
}
ASTNODE_BASE_FUNCS(NodeFTaskRef)
- virtual bool broken() const { return m_taskp && !m_taskp->brokeExists(); }
+ virtual const char* broken() const { BROKEN_RTN(m_taskp && !m_taskp->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_taskp && m_taskp->clonep()) {
m_taskp = m_taskp->clonep()->castNodeFTask();
}}
@@ -1847,4 +1852,9 @@ inline int AstNodeArrayDType::lsb() const { return rangep()->lsbConst(); }
inline int AstNodeArrayDType::elementsConst() const { return rangep()->elementsConst(); }
inline VNumRange AstNodeArrayDType::declRange() const { return VNumRange(msb(), lsb(), rangep()->littleEndian()); }
+inline void AstIfaceRefDType::cloneRelink() {
+ if (m_cellp && m_cellp->clonep()) m_cellp = m_cellp->clonep()->castCell();
+ if (m_ifacep && m_ifacep->clonep()) m_ifacep = m_ifacep->clonep()->castIface();
+ if (m_modportp && m_modportp->clonep()) m_modportp = m_modportp->clonep()->castModport(); }
+
#endif // Guard
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index cfa015b..178d8ff 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -35,8 +35,22 @@
// Special methods
// We need these here, because the classes they point to aren't defined when we declare the class
-bool AstNodeVarRef::broken() const { return ((m_varScopep && !m_varScopep->brokeExists())
- || (m_varp && !m_varp->brokeExists())); }
+const char* AstIfaceRefDType::broken() const {
+ BROKEN_RTN(m_ifacep && !m_ifacep->brokeExists());
+ BROKEN_RTN(m_cellp && !m_cellp->brokeExists());
+ BROKEN_RTN(m_modportp && !m_modportp->brokeExists());
+ return NULL;
+}
+
+AstIface* AstIfaceRefDType::ifaceViaCellp() const {
+ return ((m_cellp && m_cellp->modp()) ? m_cellp->modp()->castIface() : m_ifacep);
+}
+
+const char* AstNodeVarRef::broken() const {
+ BROKEN_RTN(m_varScopep && !m_varScopep->brokeExists());
+ BROKEN_RTN(m_varp && !m_varp->brokeExists());
+ return NULL;
+}
void AstNodeVarRef::cloneRelink() {
if (m_varp && m_varp->clonep()) { m_varp = m_varp->clonep()->castVar(); }
@@ -54,18 +68,18 @@ void AstNodeClassDType::repairMemberCache() {
}
}
-bool AstNodeClassDType::broken() const {
+const char* AstNodeClassDType::broken() const {
set<AstMemberDType*> exists;
for (AstMemberDType* itemp = membersp(); itemp; itemp=itemp->nextp()->castMemberDType()) {
exists.insert(itemp);
}
for (MemberNameMap::const_iterator it=m_members.begin(); it!=m_members.end(); ++it) {
- if (exists.find(it->second) == exists.end()) {
+ if (VL_UNLIKELY(exists.find(it->second) == exists.end())) {
this->v3error("Internal: Structure member broken: "<<it->first);
- return true;
+ return "member broken";
}
}
- return false;
+ return NULL;
}
int AstBasicDType::widthAlignBytes() const {
@@ -419,10 +433,12 @@ AstNode* AstArraySel::baseFromp(AstNode* nodep) { ///< What is the base variable
return nodep;
}
-bool AstScope::broken() const {
- return ((m_aboveScopep && !m_aboveScopep->brokeExists())
- || (m_aboveCellp && !m_aboveCellp->brokeExists())
- || !m_modp || !m_modp->brokeExists());
+const char* AstScope::broken() const {
+ BROKEN_RTN(m_aboveScopep && !m_aboveScopep->brokeExists());
+ BROKEN_RTN(m_aboveCellp && !m_aboveCellp->brokeExists());
+ BROKEN_RTN(!m_modp);
+ BROKEN_RTN(m_modp && !m_modp->brokeExists());
+ return NULL;
}
void AstScope::cloneRelink() {
@@ -718,12 +734,31 @@ void AstEnumItemRef::dump(ostream& str) {
if (itemp()) { itemp()->dump(str); }
else { str<<"UNLINKED"; }
}
+void AstIfaceRefDType::dump(ostream& str) {
+ this->AstNode::dump(str);
+ if (cellName()!="") { str<<" cell="<<cellName(); }
+ if (ifaceName()!="") { str<<" if="<<ifaceName(); }
+ if (modportName()!="") { str<<" mp="<<modportName(); }
+ if (cellp()) { str<<" -> "; cellp()->dump(str); }
+ else if (ifacep()) { str<<" -> "; ifacep()->dump(str); }
+ else { str<<" -> UNLINKED"; }
+}
+void AstIfaceRefDType::dumpSmall(ostream& str) {
+ this->AstNodeDType::dumpSmall(str);
+ str<<"iface";
+}
void AstJumpGo::dump(ostream& str) {
this->AstNode::dump(str);
str<<" -> ";
if (labelp()) { labelp()->dump(str); }
else { str<<"%Error:UNLINKED"; }
}
+void AstModportVarRef::dump(ostream& str) {
+ this->AstNode::dump(str);
+ str<<" "<<varType();
+ if (varp()) { str<<" -> "; varp()->dump(str); }
+ else { str<<" -> UNLINKED"; }
+}
void AstPin::dump(ostream& str) {
this->AstNode::dump(str);
if (modVarp()) { str<<" -> "; modVarp()->dump(str); }
@@ -839,7 +874,7 @@ void AstVarXRef::dump(ostream& str) {
if (lvalue()) str<<" [LV] => ";
else str<<" [RV] <- ";
str<<dotted()<<". - ";
- if (inlinedDots()!="") str<<" flat.="<<inlinedDots()<<" - ";
+ if (inlinedDots()!="") str<<" inline.="<<inlinedDots()<<" - ";
if (varScopep()) { varScopep()->dump(str); }
else if (varp()) { varp()->dump(str); }
else { str<<"UNLINKED"; }
diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h
index 7cd2e40..8d6e1c9 100644
--- a/src/V3AstNodes.h
+++ b/src/V3AstNodes.h
@@ -244,16 +244,16 @@ public:
refDTypep(NULL);
setOp2p(rangep);
dtypep(NULL); // V3Width will resolve
- // For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
- widthFromSub(subDTypep());
+ int width = subDTypep()->width() * rangep->elementsConst();
+ widthForce(width,width);
}
AstPackArrayDType(FileLine* fl, AstNodeDType* dtp, AstRange* rangep)
: AstNodeArrayDType(fl) {
refDTypep(dtp);
setOp2p(rangep);
dtypep(this);
- // For backward compatibility AstNodeArrayDType and others inherit width and signing from the subDType/base type
- widthFromSub(subDTypep());
+ int width = subDTypep()->width() * rangep->elementsConst();
+ widthForce(width,width);
}
ASTNODE_NODE_FUNCS(PackArrayDType, PACKARRAYDTYPE)
};
@@ -357,7 +357,7 @@ public:
virtual bool same(AstNode* samep) const { // width/widthMin/numeric compared elsewhere
return samep->castBasicDType()->m == m; }
virtual string name() const { return m.m_keyword.ascii(); }
- virtual bool broken() const { return dtypep()!=this; }
+ virtual const char* broken() const { BROKEN_RTN(dtypep()!=this); return NULL; }
AstRange* rangep() const { return op1p()->castRange(); } // op1 = Range of variable
void rangep(AstRange* nodep) { setNOp1p(nodep); }
void setSignedState(VSignedState signst) {
@@ -410,8 +410,8 @@ public:
widthFromSub(subDTypep());
}
ASTNODE_NODE_FUNCS(ConstDType, CONSTDTYPE)
- virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
- || (!m_refDTypep && childDTypep())); }
+ virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
+ || (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -432,6 +432,48 @@ public:
virtual int widthTotalBytes() const { return subDTypep()->widthTotalBytes(); }
};
+struct AstIfaceRefDType : public AstNodeDType {
+ // Reference to an interface, either for a port, or inside parent cell
+private:
+ string m_cellName; // "" = no cell, such as when connects to 'input' iface
+ string m_ifaceName; // Interface name
+ string m_modportName; // "" = no modport
+ AstIface* m_ifacep; // Pointer to interface; note cellp() should override
+ AstCell* m_cellp; // When exact parent cell known; not a guess
+ AstModport* m_modportp; // NULL = unlinked or no modport
+public:
+ AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName)
+ : AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(""),
+ m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
+ AstIfaceRefDType(FileLine* fl, const string& cellName, const string& ifaceName, const string& modport)
+ : AstNodeDType(fl), m_cellName(cellName), m_ifaceName(ifaceName), m_modportName(modport),
+ m_ifacep(NULL), m_cellp(NULL), m_modportp(NULL) { }
+ ASTNODE_NODE_FUNCS(IfaceRefDType, IFACEREFDTYPE)
+ // METHODS
+ virtual const char* broken() const;
+ virtual void dump(ostream& str=cout);
+ virtual void dumpSmall(ostream& str);
+ virtual void cloneRelink();
+ virtual AstBasicDType* basicp() const { return NULL; }
+ virtual AstNodeDType* skipRefp() const { return (AstNodeDType*)this; }
+ virtual int widthAlignBytes() const { return 1; }
+ virtual int widthTotalBytes() const { return 1; }
+ string cellName() const { return m_cellName; }
+ void cellName(const string& name) { m_cellName=name; }
+ string ifaceName() const { return m_ifaceName; }
+ void ifaceName(const string& name) { m_ifaceName=name; }
+ string modportName() const { return m_modportName; }
+ void modportName(const string& name) { m_modportName=name; }
+ AstIface* ifaceViaCellp() const; // Use cellp or ifacep
+ AstIface* ifacep() const { return m_ifacep; }
+ void ifacep(AstIface* nodep) { m_ifacep=nodep; }
+ AstCell* cellp() const { return m_cellp; }
+ void cellp(AstCell* nodep) { m_cellp=nodep; }
+ AstModport* modportp() const { return m_modportp; }
+ void modportp(AstModport* modportp) { m_modportp=modportp; }
+ bool isModport() { return !m_modportName.empty(); }
+};
+
struct AstRefDType : public AstNodeDType {
private:
AstNodeDType* m_refDTypep; // data type pointed to, BELOW the AstTypedef
@@ -447,7 +489,7 @@ public:
}
ASTNODE_NODE_FUNCS(RefDType, REFDTYPE)
// METHODS
- virtual bool broken() const { return m_refDTypep && !m_refDTypep->brokeExists(); }
+ virtual const char* broken() const { BROKEN_RTN(m_refDTypep && !m_refDTypep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -571,7 +613,7 @@ public:
ASTNODE_NODE_FUNCS(EnumItemRef, ENUMITEMREF)
virtual void dump(ostream& str);
virtual string name() const { return itemp()->name(); }
- virtual bool broken() const { return !itemp(); }
+ virtual const char* broken() const { BROKEN_RTN(!itemp()); return NULL; }
virtual int instrCount() const { return 0; }
virtual void cloneRelink() { if (m_itemp->clonep()) m_itemp = m_itemp->clonep()->castEnumItem(); }
virtual bool same(AstNode* samep) const {
@@ -601,8 +643,8 @@ public:
m_uniqueNum = uniqueNumInc();
}
ASTNODE_NODE_FUNCS(EnumDType, ENUMDTYPE)
- virtual bool broken() const { return !((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
- || (!m_refDTypep && childDTypep())); }
+ virtual const char* broken() const { BROKEN_RTN(!((m_refDTypep && !childDTypep() && m_refDTypep->brokeExists())
+ || (!m_refDTypep && childDTypep()))); return NULL; }
virtual void cloneRelink() { if (m_refDTypep && m_refDTypep->clonep()) {
m_refDTypep = m_refDTypep->clonep()->castNodeDType();
}}
@@ -843,6 +885,7 @@ private:
bool m_isStatic:1; // Static variable
bool m_isPulldown:1; // Tri0
bool m_isPullup:1; // Tri1
+ bool m_isIfaceParent:1; // dtype is reference to interface present in this module
bool m_trace:1; // Trace this variable
void init() {
@@ -854,6 +897,7 @@ private:
m_funcLocal=false; m_funcReturn=false;
m_attrClockEn=false; m_attrScBv=false; m_attrIsolateAssign=false; m_attrSFormat=false;
m_fileDescr=false; m_isConst=false; m_isStatic=false; m_isPulldown=false; m_isPullup=false;
+ m_isIfaceParent=false;
m_trace=false;
}
public:
@@ -944,6 +988,7 @@ public:
void primaryIO(bool flag) { m_primaryIO = flag; }
void isConst(bool flag) { m_isConst = flag; }
void isStatic(bool flag) { m_isStatic = flag; }
+ void isIfaceParent(bool flag) { m_isIfaceParent = flag; }
void funcLocal(bool flag) { m_funcLocal = flag; }
void funcReturn(bool flag) { m_funcReturn = flag; }
void trace(bool flag) { m_trace=flag; }
@@ -959,6 +1004,8 @@ public:
bool isPrimaryIO() const { return m_primaryIO; }
bool isPrimaryIn() const { return isPrimaryIO() && isInput(); }
bool isIO() const { return (m_input||m_output); }
+ bool isIfaceRef() const { return (varType()==AstVarType::IFACEREF); }
+ bool isIfaceParent() const { return m_isIfaceParent; }
bool isSignal() const { return varType().isSignal(); }
bool isTemp() const { return (varType()==AstVarType::BLOCKTEMP || varType()==AstVarType::MODULETEMP
|| varType()==AstVarType::STMTTEMP || varType()==AstVarType::XTEMP); }
@@ -1079,7 +1126,7 @@ public:
,m_name(name) ,m_aboveScopep(aboveScopep) ,m_aboveCellp(aboveCellp), m_modp(modp) {}
ASTNODE_NODE_FUNCS(Scope, SCOPE)
virtual void cloneRelink();
- virtual bool broken() const;
+ virtual const char* broken() const;
virtual bool maybePointedTo() const { return true; }
virtual string name() const { return m_name; } // * = Scope name
virtual void name(const string& name) { m_name = name; }
@@ -1133,8 +1180,8 @@ public:
UASSERT(m_scopep->clonep(), "No clone cross link: "<<this);
m_scopep = m_scopep->clonep()->castScope();
}}
- virtual bool broken() const { return ( (m_varp && !m_varp->brokeExists())
- || (m_scopep && !m_scopep->brokeExists())); }
+ virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists());
+ BROKEN_RTN(m_scopep && !m_scopep->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual string name() const {return scopep()->name()+"->"+varp()->name();} // * = Var name
virtual void dump(ostream& str);
@@ -1234,7 +1281,7 @@ public:
}
ASTNODE_NODE_FUNCS(Pin, PIN)
virtual void dump(ostream& str);
- virtual bool broken() const { return (m_modVarp && !m_modVarp->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(m_modVarp && !m_modVarp->brokeExists()); return NULL; }
virtual string name() const { return m_name; } // * = Pin name, ""=go by number
virtual void name(const string& name) { m_name = name; }
bool dotStar() const { return name() == ".*"; } // Special fake name for .* connections until linked
@@ -1290,7 +1337,7 @@ public:
AstPackageImport(FileLine* fl, AstPackage* packagep, const string& name)
: AstNode (fl), m_name(name), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageImport, PACKAGEIMPORT)
- virtual bool broken() const { return (!m_packagep || !m_packagep->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) m_packagep = m_packagep->clonep()->castPackage(); }
virtual void dump(ostream& str);
virtual string name() const { return m_name; }
@@ -1298,6 +1345,49 @@ public:
void packagep(AstPackage* nodep) { m_packagep=nodep; }
};
+struct AstIface : public AstNodeModule {
+ // A module declaration
+ AstIface(FileLine* fl, const string& name)
+ : AstNodeModule (fl,name) { }
+ ASTNODE_NODE_FUNCS(Iface, IFACE)
+};
+
+struct AstModportVarRef : public AstNode {
+ // A input/output/etc variable referenced under a modport
+ // The storage for the variable itself is inside the interface, thus this is a reference
+ // PARENT: AstIface
+private:
+ string m_name; // Name of the variable referenced
+ AstVarType m_type; // Type of the variable (in/out)
+ AstVar* m_varp; // Link to the actual Var
+public:
+ AstModportVarRef(FileLine* fl, const string& name, AstVarType::en type)
+ : AstNode(fl), m_name(name), m_type(type), m_varp(NULL) { }
+ ASTNODE_NODE_FUNCS(ModportVarRef, MODPORTVARREF)
+ virtual const char* broken() const { BROKEN_RTN(m_varp && !m_varp->brokeExists()); return NULL; }
+ virtual void dump(ostream& str);
+ AstVarType varType() const { return m_type; } // * = Type of variable
+ virtual string name() const { return m_name; }
+ bool isInput() const { return (varType()==AstVarType::INPUT || varType()==AstVarType::INOUT); }
+ bool isOutput() const { return (varType()==AstVarType::OUTPUT || varType()==AstVarType::INOUT); }
+ AstVar* varp() const { return m_varp; } // [After Link] Pointer to variable
+ void varp(AstVar* varp) { m_varp=varp; }
+};
+
+struct AstModport : public AstNode {
+ // A modport in an interface
+private:
+ string m_name; // Name of the modport
+public:
+ AstModport(FileLine* fl, const string& name, AstModportVarRef* varsp)
+ : AstNode(fl), m_name(name) {
+ addNOp1p(varsp); }
+ virtual string name() const { return m_name; }
+ virtual bool maybePointedTo() const { return true; }
+ ASTNODE_NODE_FUNCS(Modport, MODPORT)
+ AstModportVarRef* varsp() const { return op1p()->castModportVarRef(); } // op1 = List of Vars
+};
+
struct AstCell : public AstNode {
// A instantiation cell or interface call (don't know which until link)
private:
@@ -1305,17 +1395,18 @@ private:
string m_origName; // Original name before dot addition
string m_modName; // Module the cell instances
AstNodeModule* m_modp; // [AfterLink] Pointer to module instanced
+ bool m_hasIfaceVar; // True if a Var has been created for this cell
public:
AstCell(FileLine* fl, const string& instName, const string& modName,
AstPin* pinsp, AstPin* paramsp, AstRange* rangep)
: AstNode(fl)
, m_name(instName), m_origName(instName), m_modName(modName)
- , m_modp(NULL) {
+ , m_modp(NULL), m_hasIfaceVar(false) {
addNOp1p(pinsp); addNOp2p(paramsp); setNOp3p(rangep); }
ASTNODE_NODE_FUNCS(Cell, CELL)
// No cloneRelink, we presume cloneee's want the same module linkages
virtual void dump(ostream& str);
- virtual bool broken() const { return (m_modp && !m_modp->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(m_modp && !m_modp->brokeExists()); return NULL; }
virtual bool maybePointedTo() const { return true; }
// ACCESSORS
virtual string name() const { return m_name; } // * = Cell name
@@ -1331,6 +1422,8 @@ public:
void addPinsp(AstPin* nodep) { addOp1p(nodep); }
void addParamsp(AstPin* nodep) { addOp2p(nodep); }
void modp(AstNodeModule* nodep) { m_modp = nodep; }
+ bool hasIfaceVar() const { return m_hasIfaceVar; }
+ void hasIfaceVar(bool flag) { m_hasIfaceVar = flag; }
};
struct AstCellInline : public AstNode {
@@ -1440,7 +1533,7 @@ public:
: AstNode(fl), m_packagep(packagep) {}
ASTNODE_NODE_FUNCS(PackageRef, PACKAGEREF)
// METHODS
- virtual bool broken() const { return !m_packagep || !m_packagep->brokeExists(); }
+ virtual const char* broken() const { BROKEN_RTN(!m_packagep || !m_packagep->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_packagep && m_packagep->clonep()) {
m_packagep = m_packagep->clonep()->castPackage();
}}
@@ -1713,6 +1806,16 @@ struct AstAssignW : public AstNodeAssign {
}
};
+struct AstAssignVarScope : public AstNodeAssign {
+ // Assign two VarScopes to each other
+ AstAssignVarScope(FileLine* fileline, AstNode* lhsp, AstNode* rhsp)
+ : AstNodeAssign(fileline, lhsp, rhsp) {
+ dtypeFrom(rhsp);
+ }
+ ASTNODE_NODE_FUNCS(AssignVarScope, ASSIGNVARSCOPE)
+ virtual AstNode* cloneType(AstNode* lhsp, AstNode* rhsp) { return new AstAssignVarScope(this->fileline(), lhsp, rhsp); }
+};
+
struct AstPull : public AstNode {
private:
bool m_direction;
@@ -1799,10 +1902,10 @@ public:
m_dataDeclp = NULL;
}
ASTNODE_NODE_FUNCS(CoverDecl, COVERDECL)
- virtual bool broken() const {
- if (m_dataDeclp && !m_dataDeclp->brokeExists()) return true;
+ virtual const char* broken() const {
+ BROKEN_RTN(m_dataDeclp && !m_dataDeclp->brokeExists());
if (m_dataDeclp && m_dataDeclp->m_dataDeclp) v3fatalSrc("dataDeclp should point to real data, not be a list"); // Avoid O(n^2) accessing
- return false; }
+ return NULL; }
virtual void cloneRelink() { if (m_dataDeclp && m_dataDeclp->clonep()) m_dataDeclp = m_dataDeclp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1840,7 +1943,7 @@ public:
m_declp = declp;
}
ASTNODE_NODE_FUNCS(CoverInc, COVERINC)
- virtual bool broken() const { return !declp()->brokeExists(); }
+ virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castCoverDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 1+2*instrCountLd(); }
@@ -1991,7 +2094,7 @@ public:
}
ASTNODE_NODE_FUNCS(Display, DISPLAY)
virtual void dump(ostream& str);
- virtual bool broken() const { return !fmtp(); }
+ virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return (filep() ? (string)"$f"+(string)displayType().ascii()
: (string)"$"+(string)displayType().ascii()); }
virtual bool isGateOptimizable() const { return false; }
@@ -2021,7 +2124,7 @@ struct AstSFormat : public AstNode {
setOp3p(lhsp);
}
ASTNODE_NODE_FUNCS(SFormat, SFORMAT)
- virtual bool broken() const { return !fmtp(); }
+ virtual const char* broken() const { BROKEN_RTN(!fmtp()); return NULL; }
virtual string verilogKwd() const { return "$sformat"; }
virtual string emitVerilog() { V3ERROR_NA; return ""; }
virtual string emitC() { V3ERROR_NA; return ""; }
@@ -2442,7 +2545,7 @@ public:
m_labelp = labelp;
}
ASTNODE_NODE_FUNCS(JumpGo, JUMPGO)
- virtual bool broken() const { return !labelp()->brokeExistsAbove(); }
+ virtual const char* broken() const { BROKEN_RTN(!labelp()->brokeExistsAbove()); return NULL; }
virtual void cloneRelink() { if (m_labelp->clonep()) m_labelp = m_labelp->clonep()->castJumpLabel(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return instrCountBranch(); }
@@ -2719,7 +2822,7 @@ public:
addNOp2p(valuep);
}
ASTNODE_NODE_FUNCS(TraceInc, TRACEINC)
- virtual bool broken() const { return !declp()->brokeExists(); }
+ virtual const char* broken() const { BROKEN_RTN(!declp()->brokeExists()); return NULL; }
virtual void cloneRelink() { if (m_declp->clonep()) m_declp = m_declp->clonep()->castTraceDecl(); }
virtual void dump(ostream& str);
virtual int instrCount() const { return 10+2*instrCountLd(); }
@@ -2756,7 +2859,7 @@ public:
ASTNODE_NODE_FUNCS(Active, ACTIVE)
virtual void dump(ostream& str=cout);
virtual string name() const { return m_name; }
- virtual bool broken() const { return (m_sensesp && !m_sensesp->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(m_sensesp && !m_sensesp->brokeExists()); return NULL; }
virtual void cloneRelink() {
if (m_sensesp->clonep()) {
m_sensesp = m_sensesp->clonep()->castSenTree();
@@ -4358,7 +4461,7 @@ public:
}
ASTNODE_NODE_FUNCS(CFunc, CFUNC)
virtual string name() const { return m_name; }
- virtual bool broken() const { return ( (m_scopep && !m_scopep->brokeExists())); }
+ virtual const char* broken() const { BROKEN_RTN((m_scopep && !m_scopep->brokeExists())); return NULL; }
virtual bool maybePointedTo() const { return true; }
virtual void dump(ostream& str=cout);
virtual V3Hash sameHash() const { return V3Hash(); }
@@ -4446,7 +4549,7 @@ public:
virtual void cloneRelink() { if (m_funcp && m_funcp->clonep()) {
m_funcp = m_funcp->clonep()->castCFunc();
}}
- virtual bool broken() const { return (m_funcp && !m_funcp->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(m_funcp && !m_funcp->brokeExists()); return NULL; }
virtual int instrCount() const { return instrCountCall(); }
virtual V3Hash sameHash() const { return V3Hash(funcp()); }
virtual bool same(AstNode* samep) const {
@@ -4578,7 +4681,7 @@ public:
m_dollarUnitPkgp = NULL;
}
ASTNODE_NODE_FUNCS(Netlist, NETLIST)
- virtual bool broken() const { return (m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); }
+ virtual const char* broken() const { BROKEN_RTN(m_dollarUnitPkgp && !m_dollarUnitPkgp->brokeExists()); return NULL; }
AstNodeModule* modulesp() const { return op1p()->castNodeModule();} // op1 = List of modules
AstNodeModule* topModulep() const { return op1p()->castNodeModule(); } // * = Top module in hierarchy (first one added, for now)
void addModulep(AstNodeModule* modulep) { addOp1p(modulep); }
diff --git a/src/V3Broken.cpp b/src/V3Broken.cpp
index ca11e7e..ff72870 100644
--- a/src/V3Broken.cpp
+++ b/src/V3Broken.cpp
@@ -202,8 +202,8 @@ class BrokenCheckVisitor : public AstNVisitor {
private:
virtual void visit(AstNode* nodep, AstNUser*) {
BrokenTable::setUnder(nodep,true);
- if (nodep->broken()) {
- nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo)");
+ if (const char* whyp=nodep->broken()) {
+ nodep->v3fatalSrc("Broken link in node (or something without maybePointedTo): "<<whyp);
}
if (nodep->dtypep()) {
if (!nodep->dtypep()->brokeExists()) { nodep->v3fatalSrc("Broken link in node->dtypep() to "<<(void*)nodep->dtypep()); }
diff --git a/src/V3Cdc.cpp b/src/V3Cdc.cpp
index 1030633..25501d5 100644
--- a/src/V3Cdc.cpp
+++ b/src/V3Cdc.cpp
@@ -526,7 +526,7 @@ private:
}
}
}
- sort(report.begin(), report.end());
+ stable_sort(report.begin(), report.end());
for (deque<string>::iterator it = report.begin(); it!=report.end(); ++it) {
*ofp << *it;
}
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index b0299ba..e69149d 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -1413,7 +1413,7 @@ private:
for (AstNodeSenItem* senp = nodep->sensesp()->castNodeSenItem(); senp; senp=senp->nextp()->castNodeSenItem()) {
vec.push_back(senp);
}
- sort(vec.begin(), vec.end(), SenItemCmp());
+ stable_sort(vec.begin(), vec.end(), SenItemCmp());
for (vector<AstNodeSenItem*>::iterator it=vec.begin(); it!=vec.end(); ++it) {
(*it)->unlinkFrBack();
}
@@ -1466,6 +1466,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Don't perform any optimizations, keep the alias around
}
+ virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
+ // Don't perform any optimizations, the node won't be linked yet
+ }
virtual void visit(AstAssignW* nodep, AstNUser*) {
nodep->iterateChildren(*this);
if (m_doNConst && replaceNodeAssign(nodep)) return;
diff --git a/src/V3Coverage.cpp b/src/V3Coverage.cpp
index c571019..8e63fc2 100644
--- a/src/V3Coverage.cpp
+++ b/src/V3Coverage.cpp
@@ -64,6 +64,7 @@ private:
bool m_checkBlock; // Should this block get covered?
AstNodeModule* m_modp; // Current module to add statement to
bool m_inToggleOff; // In function/task etc
+ bool m_inModOff; // In module with no coverage
FileMap m_fileps; // Column counts for each fileline
string m_beginHier; // AstBegin hier name for user coverage points
@@ -124,9 +125,11 @@ private:
// VISITORS - BOTH
virtual void visit(AstNodeModule* nodep, AstNUser*) {
m_modp = nodep;
+ m_inModOff = nodep->isTop(); // Ignore coverage on top module; it's a shell we created
m_fileps.clear();
nodep->iterateChildren(*this);
m_modp = NULL;
+ m_inModOff = true;
}
// VISITORS - TOGGLE COVERAGE
@@ -140,7 +143,7 @@ private:
}
virtual void visit(AstVar* nodep, AstNUser*) {
nodep->iterateChildren(*this);
- if (m_modp && !m_inToggleOff
+ if (m_modp && !m_inModOff && !m_inToggleOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageToggle()) {
const char* disablep = varIgnoreToggle(nodep);
if (disablep) {
@@ -231,7 +234,7 @@ private:
UINFO(4," IF: "<<nodep<<endl);
if (m_checkBlock) {
nodep->ifsp()->iterateAndNext(*this);
- if (m_checkBlock
+ if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "if" branch didn't disable it
if (!nodep->backp()->castIf()
|| nodep->backp()->castIf()->elsesp()!=nodep) { // Ignore if else; did earlier
@@ -243,7 +246,7 @@ private:
if (nodep->elsesp()) {
m_checkBlock = true;
nodep->elsesp()->iterateAndNext(*this);
- if (m_checkBlock
+ if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) { // if a "else" branch didn't disable it
UINFO(4," COVER: "<<nodep<<endl);
if (nodep->elsesp()->castIf()) {
@@ -258,7 +261,7 @@ private:
}
virtual void visit(AstCaseItem* nodep, AstNUser*) {
UINFO(4," CASEI: "<<nodep<<endl);
- if (m_checkBlock
+ if (m_checkBlock && !m_inModOff
&& nodep->fileline()->coverageOn() && v3Global.opt.coverageLine()) {
nodep->bodysp()->iterateAndNext(*this);
if (m_checkBlock) { // if the case body didn't disable it
@@ -327,6 +330,7 @@ public:
m_checkBlock = true;
m_beginHier = "";
m_inToggleOff = false;
+ m_inModOff = true;
rootp->iterateChildren(*this);
}
virtual ~CoverageVisitor() {}
diff --git a/src/V3Delayed.cpp b/src/V3Delayed.cpp
index fa3fafb..7b7c650 100644
--- a/src/V3Delayed.cpp
+++ b/src/V3Delayed.cpp
@@ -124,10 +124,10 @@ private:
AstVar* varp;
AstNodeModule* addmodp = oldvarscp->scopep()->modp();
// We need a new AstVar, but only one for all scopes, to match the new AstVarScope
- VarMap::iterator iter = m_modVarMap.find(make_pair(addmodp,name));
- if (iter != m_modVarMap.end()) {
+ VarMap::iterator it = m_modVarMap.find(make_pair(addmodp,name));
+ if (it != m_modVarMap.end()) {
// Created module's AstVar earlier under some other scope
- varp = iter->second;
+ varp = it->second;
} else {
if (width==0) {
varp = new AstVar (oldvarscp->fileline(), AstVarType::BLOCKTEMP, name, oldvarscp->varp());
diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp
index 1c37b42..a75f4c7 100644
--- a/src/V3EmitC.cpp
+++ b/src/V3EmitC.cpp
@@ -86,6 +86,13 @@ public:
}
void emitOpName(AstNode* nodep, const string& format,
AstNode* lhsp, AstNode* rhsp, AstNode* thsp);
+ void emitDeclArrayBrackets(AstVar* nodep) {
+ // This isn't very robust and may need cleanup for other data types
+ for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
+ arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
+ puts("["+cvtToStr(arrayp->elementsConst())+"]");
+ }
+ }
// VISITORS
virtual void visit(AstNodeAssign* nodep, AstNUser*) {
@@ -788,7 +795,7 @@ class EmitCImp : EmitCStmts {
if (!m_blkChangeDetVec.empty()) puts("return __req;\n");
-// puts("__Vm_activity = true;\n");
+ //puts("__Vm_activity = true;\n");
puts("}\n");
}
@@ -875,7 +882,6 @@ public:
void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
AstBasicDType* basicp = nodep->basicp(); if (!basicp) nodep->v3fatalSrc("Unimplemented: Outputting this data type");
if (nodep->isIO()) {
- bool isArray = !nodep->dtypeSkipRefp()->castBasicDType();
if (nodep->isSc()) {
m_ctorVarsVec.push_back(nodep);
ofp()->putAlign(nodep->isStatic(), 4); // sc stuff is a structure, so bigger alignment
@@ -891,12 +897,7 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
puts(">\t");
}
puts(nodep->name());
- if (isArray) {
- for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
- arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
- puts("["+cvtToStr(arrayp->elementsConst())+"]");
- }
- }
+ emitDeclArrayBrackets(nodep);
puts(";\n");
} else { // C++ signals
ofp()->putAlign(nodep->isStatic(), nodep->dtypeSkipRefp()->widthAlignBytes(),
@@ -909,36 +910,20 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
if (nodep->isQuad()) puts("64");
else if (nodep->widthMin() <= 8) puts("8");
else if (nodep->widthMin() <= 16) puts("16");
-
- if (isArray) {
- if (nodep->isWide()) puts("W");
- puts("("+nodep->name());
- for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
- arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
- puts("["+cvtToStr(arrayp->elementsConst())+"]");
- }
- puts(","+cvtToStr(basicp->msb())+","+cvtToStr(basicp->lsb()));
- if (basicp->isWide()) puts(","+cvtToStr(basicp->widthWords()));
- } else {
- if (!basicp->isWide())
- puts("("+nodep->name()
- +","+cvtToStr(basicp->msb())
- +","+cvtToStr(basicp->lsb()));
- else puts("W("+nodep->name()
- +","+cvtToStr(basicp->msb())
- +","+cvtToStr(basicp->lsb())
- +","+cvtToStr(basicp->widthWords()));
- }
+ else if (nodep->isWide()) puts("W");
+
+ puts("("+nodep->name());
+ emitDeclArrayBrackets(nodep);
+ // If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
+ puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+ +","+cvtToStr(basicp->lsb()));
+ if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
} else if (basicp && basicp->isOpaque()) {
// strings and other fundamental c types
puts(nodep->vlArgType(true,false));
- // This isn't very robust and may need cleanup for other data types
- for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
- arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
- puts("["+cvtToStr(arrayp->elementsConst())+"]");
- }
+ emitDeclArrayBrackets(nodep);
puts(";\n");
} else {
// Arrays need a small alignment, but may need different padding after.
@@ -960,13 +945,10 @@ void EmitCStmts::emitVarDecl(AstVar* nodep, const string& prefixIfImp) {
}
if (prefixIfImp!="") { puts(prefixIfImp); puts("::"); }
puts(nodep->name());
- // This isn't very robust and may need cleanup for other data types
- for (AstUnpackArrayDType* arrayp=nodep->dtypeSkipRefp()->castUnpackArrayDType(); arrayp;
- arrayp = arrayp->subDTypep()->skipRefp()->castUnpackArrayDType()) {
- puts("["+cvtToStr(arrayp->elementsConst())+"]");
- }
+ emitDeclArrayBrackets(nodep);
// If it's a packed struct/array then nodep->width is the whole thing, msb/lsb is just lowest dimension
- puts(","+cvtToStr(basicp->lsb()+nodep->width())+","+cvtToStr(basicp->lsb()));
+ puts(","+cvtToStr(basicp->lsb()+nodep->width()-1)
+ +","+cvtToStr(basicp->lsb()));
if (nodep->isWide()) puts(","+cvtToStr(nodep->widthWords()));
puts(");\n");
}
@@ -1735,7 +1717,7 @@ void EmitCImp::emitIntFuncDecls(AstNodeModule* modp) {
}
}
- sort(funcsp.begin(), funcsp.end(), CmpName());
+ stable_sort(funcsp.begin(), funcsp.end(), CmpName());
for (vector<AstCFunc*>::iterator it = funcsp.begin(); it != funcsp.end(); ++it) {
AstCFunc* funcp = *it;
diff --git a/src/V3EmitCSyms.cpp b/src/V3EmitCSyms.cpp
index f17d854..fc7f77e 100644
--- a/src/V3EmitCSyms.cpp
+++ b/src/V3EmitCSyms.cpp
@@ -168,8 +168,8 @@ class EmitCSyms : EmitCBaseVisitor {
varsExpand();
// Sort by names, so line/process order matters less
- sort(m_scopes.begin(), m_scopes.end(), CmpName());
- sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
+ stable_sort(m_scopes.begin(), m_scopes.end(), CmpName());
+ stable_sort(m_dpis.begin(), m_dpis.end(), CmpDpi());
// Output
emitSymHdr();
diff --git a/src/V3Error.cpp b/src/V3Error.cpp
index 4b433a3..67f5f0f 100644
--- a/src/V3Error.cpp
+++ b/src/V3Error.cpp
@@ -44,6 +44,7 @@ bool V3Error::s_describedEachWarn[V3ErrorCode::_ENUM_MAX];
bool V3Error::s_describedWarnings = false;
bool V3Error::s_pretendError[V3ErrorCode::_ENUM_MAX];
V3Error::MessagesSet V3Error::s_messages;
+V3Error::ErrorExitCb V3Error::s_errorExitCb = NULL;
struct v3errorIniter {
v3errorIniter() { V3Error::init(); }
@@ -89,8 +90,8 @@ const string FileLineSingleton::filenameLetters(int no) {
//! We associate a language with each source file, so we also set the default
//! for this.
int FileLineSingleton::nameToNumber(const string& filename) {
- FileNameNumMap::const_iterator iter = m_namemap.find(filename);
- if (VL_LIKELY(iter != m_namemap.end())) return iter->second;
+ FileNameNumMap::const_iterator it = m_namemap.find(filename);
+ if (VL_LIKELY(it != m_namemap.end())) return it->second;
int num = m_names.size();
m_names.push_back(filename);
m_languages.push_back(V3LangCode::mostRecent());
@@ -482,7 +483,8 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
}
#ifndef _V3ERROR_NO_GLOBAL_
if (debug()) {
- v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",99));
+ v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",990));
+ if (s_errorExitCb) s_errorExitCb();
V3Stats::statsFinalAll(v3Global.rootp());
V3Stats::statsReport();
}
@@ -491,5 +493,10 @@ void V3Error::v3errorEnd (ostringstream& sstr) {
vlAbort();
}
+ else if (isError(s_errorCode, s_errorSuppressed)) {
+ // We don't dump tree on any error because a Visitor may be in middle of
+ // a tree cleanup and cause a false broken problem.
+ if (s_errorExitCb) s_errorExitCb();
+ }
}
}
diff --git a/src/V3Error.h b/src/V3Error.h
index 1f9030c..a4909c3 100644
--- a/src/V3Error.h
+++ b/src/V3Error.h
@@ -181,6 +181,7 @@ class V3Error {
// Base class for any object that wants debugging and error reporting
typedef set<string> MessagesSet;
+ typedef void (*ErrorExitCb)(void);
private:
static bool s_describedWarnings; // Told user how to disable warns
@@ -194,6 +195,8 @@ class V3Error {
static V3ErrorCode s_errorCode; // Error string being formed will abort
static bool s_errorSuppressed; // Error being formed should be suppressed
static MessagesSet s_messages; // What errors we've outputted
+ static ErrorExitCb s_errorExitCb; // Callback when error occurs for dumping
+
enum MaxErrors { MAX_ERRORS = 50 }; // Fatal after this may errors
V3Error() { cerr<<("Static class"); abort(); }
@@ -218,6 +221,7 @@ class V3Error {
static bool isError(V3ErrorCode code, bool supp);
static string lineStr (const char* filename, int lineno);
static V3ErrorCode errorCode() { return s_errorCode; }
+ static void errorExitCb(ErrorExitCb cb) { s_errorExitCb = cb; }
// When printing an error/warning, print prefix for multiline message
static string warnMore();
diff --git a/src/V3Global.h b/src/V3Global.h
index a03f601..fede611 100644
--- a/src/V3Global.h
+++ b/src/V3Global.h
@@ -80,7 +80,7 @@ public:
string debugFilename(const string& nameComment, int newNumber=0) {
++m_debugFileNumber;
if (newNumber) m_debugFileNumber = newNumber;
- char digits[100]; sprintf(digits, "%02d", m_debugFileNumber);
+ char digits[100]; sprintf(digits, "%03d", m_debugFileNumber);
return opt.makeDir()+"/"+opt.prefix()+"_"+digits+"_"+nameComment;
}
bool needHInlines() const { return m_needHInlines; }
diff --git a/src/V3GraphAcyc.cpp b/src/V3GraphAcyc.cpp
index 0b90acb..54c9e52 100644
--- a/src/V3GraphAcyc.cpp
+++ b/src/V3GraphAcyc.cpp
@@ -461,7 +461,7 @@ void GraphAcyc::place() {
}
// Sort by weight, then by vertex (so that we completely process one vertex, when possible)
- sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
+ stable_sort(edges.begin(), edges.end(), GraphAcycEdgeCmp());
// Process each edge in weighted order
m_placeStep = 10;
diff --git a/src/V3GraphAlg.cpp b/src/V3GraphAlg.cpp
index 161017b..dba224a 100644
--- a/src/V3GraphAlg.cpp
+++ b/src/V3GraphAlg.cpp
@@ -464,7 +464,7 @@ void V3Graph::sortVertices() {
for (V3GraphVertex* vertexp = verticesBeginp(); vertexp; vertexp=vertexp->verticesNextp()) {
vertices.push_back(vertexp);
}
- std::sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
+ std::stable_sort(vertices.begin(), vertices.end(), GraphSortVertexCmp());
this->verticesUnlink();
for (vector<V3GraphVertex*>::iterator it = vertices.begin(); it!=vertices.end(); ++it) {
(*it)->verticesPushBack(this);
@@ -480,7 +480,7 @@ void V3Graph::sortEdges() {
edges.push_back(edgep);
}
// Sort
- std::sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
+ std::stable_sort(edges.begin(), edges.end(), GraphSortEdgeCmp());
// Relink edges in specified order
// We know the vector contains all of the edges that were
diff --git a/src/V3Inline.cpp b/src/V3Inline.cpp
index e60221d..99ce87a 100644
--- a/src/V3Inline.cpp
+++ b/src/V3Inline.cpp
@@ -42,11 +42,376 @@
#include "V3Stats.h"
#include "V3Ast.h"
+// CONFIG
+static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
+
//######################################################################
// Inline state, as a visitor of each AstNode
-// CONFIG
-static const int INLINE_MODS_SMALLER = 100; // If a mod is < this # nodes, can always inline it
+class InlineMarkVisitor : public AstNVisitor {
+private:
+ // NODE STATE
+ // Output
+ // AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
+ // Entire netlist (can be cleared after this visit completes)
+ // AstNodeModule::user2() // CIL_*. Allowed to automatically inline module
+ // AstNodeModule::user3() // int. Number of cells referencing this module
+ AstUser1InUse m_inuser1;
+ AstUser2InUse m_inuser2;
+ AstUser3InUse m_inuser3;
+
+ enum {CIL_NOTHARD=0, // For user2, inline not supported
+ CIL_NOTSOFT, // For user2, don't inline unless user overrides
+ CIL_MAYBE}; // For user2, might inline
+
+ // STATE
+ AstNodeModule* m_modp; // Flattened cell's containing module
+ int m_stmtCnt; // Statements in module
+ V3Double0 m_statUnsup; // Statistic tracking
+
+ // METHODS
+ static int debug() {
+ static int level = -1;
+ if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
+ return level;
+ }
+ void cantInline(const char* reason, bool hard) {
+ if (hard) {
+ if (m_modp->user2() != CIL_NOTHARD) {
+ UINFO(4," No inline hard: "<<reason<<" "<<m_modp<<endl);
+ m_modp->user2(CIL_NOTHARD);
+ m_statUnsup++;
+ }
+ } else {
+ if (m_modp->user2() == CIL_MAYBE) {
+ UINFO(4," No inline soft: "<<reason<<" "<<m_modp<<endl);
+ m_modp->user2(CIL_NOTSOFT);
+ }
+ }
+ }
+
+ // VISITORS
+ virtual void visit(AstNodeModule* nodep, AstNUser*) {
+ m_stmtCnt = 0;
+ m_modp = nodep;
+ m_modp->user2(CIL_MAYBE);
+ if (m_modp->castIface()) {
+ // Inlining an interface means we no longer have a cell handle to resolve to.
+ // If inlining moves post-scope this can perhaps be relaxed.
+ cantInline("modIface",true);
+ }
+ if (m_modp->modPublic()) cantInline("modPublic",false);
+ //
+ nodep->iterateChildren(*this);
+ //
+ bool userinline = nodep->user1();
+ int allowed = nodep->user2();
+ int refs = nodep->user3();
+ // Should we automatically inline this module?
+ // inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
+ bool doit = ((allowed == CIL_NOTSOFT || allowed == CIL_MAYBE)
+ && (userinline
+ || ((allowed == CIL_MAYBE)
+ && (refs==1
+ || m_stmtCnt < INLINE_MODS_SMALLER
+ || v3Global.opt.inlineMult() < 1
+ || refs*m_stmtCnt < v3Global.opt.inlineMult()))));
+ // Packages aren't really "under" anything so they confuse this algorithm
+ if (nodep->castPackage()) doit = false;
+ UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
+ <<" "<<nodep<<endl);
+ nodep->user1(doit);
+ m_modp = NULL;
+ }
+ virtual void visit(AstCell* nodep, AstNUser*) {
+ nodep->modp()->user3Inc();
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstPragma* nodep, AstNUser*) {
+ if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
+ //UINFO(0,"PRAG MARK "<<m_modp<<endl);
+ if (!m_modp) {
+ nodep->v3error("Inline pragma not under a module");
+ } else {
+ m_modp->user1(1);
+ }
+ nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
+ } else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
+ if (!m_modp) {
+ nodep->v3error("Inline pragma not under a module");
+ } else {
+ cantInline("Pragma NO_INLINE_MODULE",false);
+ }
+ nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
+ } else {
+ nodep->iterateChildren(*this);
+ }
+ }
+ virtual void visit(AstVarXRef* nodep, AstNUser*) {
+ // Cleanup link until V3LinkDot can correct it
+ nodep->varp(NULL);
+ }
+ virtual void visit(AstVar* nodep, AstNUser*) {
+ // Can't look at AstIfaceRefDType directly as it is no longer underneath the module
+ if (nodep->isIfaceRef()) {
+ // Unsupported: Inlining of modules with ifaces (see AstIface comment above)
+ if (m_modp) cantInline("Interfaced",true);
+ }
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
+ // Cleanup link until V3LinkDot can correct it
+ if (!nodep->packagep()) nodep->taskp(NULL);
+ nodep->iterateChildren(*this);
+ }
+ // Nop's to speed up the loop
+ virtual void visit(AstAlways* nodep, AstNUser*) {
+ nodep->iterateChildren(*this);
+ m_stmtCnt++;
+ }
+ virtual void visit(AstNodeAssign* nodep, AstNUser*) {
+ // Don't count assignments, as they'll likely flatten out
+ // Still need to iterate though to nullify VarXRefs
+ int oldcnt = m_stmtCnt;
+ nodep->iterateChildren(*this);
+ m_stmtCnt = oldcnt;
+ }
+ //--------------------
+ // Default: Just iterate
+ virtual void visit(AstNode* nodep, AstNUser*) {
+ nodep->iterateChildren(*this);
+ m_stmtCnt++;
+ }
+
+public:
+ // CONSTUCTORS
+ InlineMarkVisitor(AstNode* nodep) {
+ m_modp = NULL;
+ m_stmtCnt = 0;
+ nodep->accept(*this);
+ }
+ virtual ~InlineMarkVisitor() {
+ V3Stats::addStat("Optimizations, Inline unsupported", m_statUnsup);
+ // Done with these, are not outputs
+ AstNode::user2ClearTree();
+ AstNode::user3ClearTree();
+ }
+};
+
+//######################################################################
+// Using clonep(), find cell cross references.
+// clone() must not be called inside this visitor
+
+class InlineCollectVisitor : public AstNVisitor {
+private:
+ // NODE STATE
+ // Output:
+ // AstCell::user4p() // AstCell* of the created clone
+
+ static int debug() {
+ static int level = -1;
+ if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
+ return level;
+ }
+
+ // VISITORS
+ virtual void visit(AstCell* nodep, AstNUser*) {
+ nodep->user4p(nodep->clonep());
+ }
+ // Accelerate
+ virtual void visit(AstNodeStmt* nodep, AstNUser*) {}
+ virtual void visit(AstNodeMath* nodep, AstNUser*) {}
+ virtual void visit(AstNode* nodep, AstNUser*) {
+ nodep->iterateChildren(*this);
+ }
+
+public:
+ // CONSTUCTORS
+ InlineCollectVisitor(AstNodeModule* nodep) { // passed OLD module, not new one
+ nodep->accept(*this);
+ }
+ virtual ~InlineCollectVisitor() {}
+};
+
+//######################################################################
+// After cell is cloned, relink the new module's contents
+
+class InlineRelinkVisitor : public AstNVisitor {
+private:
+ // NODE STATE
+ // Input:
+ // See InlineVisitor
+
+ // STATE
+ AstNodeModule* m_modp; // Current module
+ AstCell* m_cellp; // Cell being cloned
+
+ static int debug() {
+ static int level = -1;
+ if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
+ return level;
+ }
+
+ // VISITORS
+ virtual void visit(AstCellInline* nodep, AstNUser*) {
+ // Inlined cell under the inline cell, need to move to avoid conflicts
+ nodep->unlinkFrBack();
+ m_modp->addInlinesp(nodep);
+ // Rename
+ string name = m_cellp->name() + "__DOT__" + nodep->name();
+ nodep->name(name);
+ UINFO(6, " Inline "<<nodep<<endl);
+ // Do CellInlines under this, but don't move them
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstCell* nodep, AstNUser*) {
+ // Cell under the inline cell, need to rename to avoid conflicts
+ string name = m_cellp->name() + "__DOT__" + nodep->name();
+ nodep->name(name);
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstVar* nodep, AstNUser*) {
+ if (nodep->user2p()) {
+ // Make an assignment, so we'll trace it properly
+ // user2p is either a const or a var.
+ AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
+ AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
+ UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
+ if (!exprconstp && !exprvarrefp) {
+ nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
+ }
+ if (exprconstp) {
+ m_modp->addStmtp(new AstAssignW(nodep->fileline(),
+ new AstVarRef(nodep->fileline(), nodep, true),
+ exprconstp->cloneTree(true)));
+ } else if (nodep->user3()) {
+ // Public variable at the lower module end - we need to make sure we propagate
+ // the logic changes up and down; if we aliased, we might remove the change detection
+ // on the output variable.
+ UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
+ if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
+ m_modp->addStmtp(new AstAssignW(nodep->fileline(),
+ new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
+ new AstVarRef(nodep->fileline(), nodep, false)));
+ } else if (nodep->isIfaceRef()) {
+ m_modp->addStmtp(new AstAssignVarScope(nodep->fileline(),
+ new AstVarRef(nodep->fileline(), nodep, true),
+ new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
+ AstNode* nodebp=exprvarrefp->varp();
+ nodep ->fileline()->modifyStateInherit(nodebp->fileline());
+ nodebp->fileline()->modifyStateInherit(nodep ->fileline());
+ } else {
+ // Do to inlining child's variable now within the same module, so a AstVarRef not AstVarXRef below
+ m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
+ new AstVarRef(nodep->fileline(), nodep, true),
+ new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
+ AstNode* nodebp=exprvarrefp->varp();
+ nodep ->fileline()->modifyStateInherit(nodebp->fileline());
+ nodebp->fileline()->modifyStateInherit(nodep ->fileline());
+ }
+ }
+ // Variable under the inline cell, need to rename to avoid conflicts
+ // Also clear I/O bits, as it is now local.
+ string name = m_cellp->name() + "__DOT__" + nodep->name();
+ if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
+ if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
+ if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
+ // Iterate won't hit AstIfaceRefDType directly as it is no longer underneath the module
+ if (AstIfaceRefDType* ifacerefp = nodep->dtypep()->castIfaceRefDType()) {
+ // Relink to point to newly cloned cell
+ if (ifacerefp->cellp()) {
+ if (AstCell* newcellp = ifacerefp->cellp()->user4p()->castNode()->castCell()) {
+ ifacerefp->cellp(newcellp);
+ ifacerefp->cellName(newcellp->name());
+ }
+ }
+ }
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstNodeFTask* nodep, AstNUser*) {
+ // Function under the inline cell, need to rename to avoid conflicts
+ nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstTypedef* nodep, AstNUser*) {
+ // Typedef under the inline cell, need to rename to avoid conflicts
+ nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstVarRef* nodep, AstNUser*) {
+ if (nodep->varp()->user2p() // It's being converted to an alias.
+ && !nodep->varp()->user3()
+ && !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
+ AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
+ AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
+ if (exprconstp) {
+ nodep->replaceWith(exprconstp->cloneTree(true));
+ nodep->deleteTree(); nodep=NULL;
+ return;
+ }
+ else if (exprvarrefp) {
+ nodep->varp( exprvarrefp->varp() );
+ }
+ else {
+ nodep->v3fatalSrc("Null connection?\n");
+ }
+ }
+ nodep->name(nodep->varp()->name());
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstVarXRef* nodep, AstNUser*) {
+ // Track what scope it was originally under so V3LinkDot can resolve it
+ string newname = m_cellp->name();
+ if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
+ nodep->inlinedDots(newname);
+ UINFO(8," "<<nodep<<endl);
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
+ // Track what scope it was originally under so V3LinkDot can resolve it
+ string newname = m_cellp->name();
+ if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
+ nodep->inlinedDots(newname);
+ UINFO(8," "<<nodep<<endl);
+ nodep->iterateChildren(*this);
+ }
+
+ // Not needed, as V3LinkDot doesn't care about typedefs
+ //virtual void visit(AstRefDType* nodep, AstNUser*) {}
+
+ virtual void visit(AstScopeName* nodep, AstNUser*) {
+ // If there's a %m in the display text, we add a special node that will contain the name()
+ // Similar code in V3Begin
+ // To keep correct visual order, must add before other Text's
+ AstNode* afterp = nodep->scopeAttrp();
+ if (afterp) afterp->unlinkFrBackWithNext();
+ nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
+ if (afterp) nodep->scopeAttrp(afterp);
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstCoverDecl* nodep, AstNUser*) {
+ // Fix path in coverage statements
+ nodep->hier(m_cellp->prettyName()
+ + (nodep->hier()!="" ? ".":"")
+ + nodep->hier());
+ nodep->iterateChildren(*this);
+ }
+ virtual void visit(AstNode* nodep, AstNUser*) {
+ nodep->iterateChildren(*this);
+ }
+
+public:
+ // CONSTUCTORS
+ InlineRelinkVisitor(AstNodeModule* cloneModp, AstNodeModule* oldModp, AstCell* cellp) {
+ m_modp = oldModp;
+ m_cellp = cellp;
+ cloneModp->accept(*this);
+ }
+ virtual ~InlineRelinkVisitor() {}
+};
+
+//######################################################################
+// Inline state, as a visitor of each AstNode
class InlineVisitor : public AstNVisitor {
private:
@@ -56,11 +421,13 @@ private:
// AstNodeModule::user1p() // bool. True to inline this module (from InlineMarkVisitor)
// Cleared each cell
// AstVar::user2p() // AstVarRef*/AstConst* Points to signal this is a direct connect to
- // AstVar::user3() // bool Don't alias the user4, keep it as signal
+ // AstVar::user3() // bool Don't alias the user2, keep it as signal
+ // AstCell::user4 // AstCell* of the created clone
+
+ AstUser4InUse m_inuser4;
// STATE
AstNodeModule* m_modp; // Current module
- AstCell* m_cellp; // Cell being cloned
V3Double0 m_statCells; // Statistic tracking
static int debug() {
@@ -75,34 +442,11 @@ private:
nodep->iterateChildrenBackwards(*this);
}
virtual void visit(AstNodeModule* nodep, AstNUser*) {
- if (m_cellp) {
- } else {
- m_modp = nodep;
- }
+ m_modp = nodep;
nodep->iterateChildren(*this);
}
- virtual void visit(AstCellInline* nodep, AstNUser*) {
- // Inlined cell under the inline cell, need to move to avoid conflicts
- if (m_cellp) {
- nodep->unlinkFrBack();
- m_modp->addInlinesp(nodep);
- // Rename
- string name = m_cellp->name() + "__DOT__" + nodep->name();
- nodep->name(name);
- UINFO(6, " Inline "<<nodep<<endl);
- // Do CellInlines under this, but don't move them
- nodep->iterateChildren(*this);
- }
- }
virtual void visit(AstCell* nodep, AstNUser*) {
- if (m_cellp) {
- // Cell under the inline cell, need to rename to avoid conflicts
- string name = m_cellp->name() + "__DOT__" + nodep->name();
- nodep->name(name);
- nodep->iterateChildren(*this);
- }
if (nodep->modp()->user1()) { // Marked with inline request
- if (m_cellp) nodep->v3error("Cloning should have already been done bottom-up");
UINFO(5," Inline CELL "<<nodep<<endl);
UINFO(5," To MOD "<<m_modp<<endl);
++m_statCells;
@@ -121,8 +465,10 @@ private:
//if (debug()>=9) { nodep->modp()->dumpTree(cout,"oldmod:"); }
AstNodeModule* newmodp = nodep->modp()->cloneTree(false);
if (debug()>=9) { newmodp->dumpTree(cout,"newmod:"); }
- // Clear var markings
+ // Clear var markings and find cell cross references
AstNode::user2ClearTree();
+ AstNode::user4ClearTree();
+ { InlineCollectVisitor(nodep->modp()); } // {} to destroy visitor immediately
// Create data for dotted variable resolution
AstCellInline* inlinep = new AstCellInline(nodep->fileline(),
nodep->name(), nodep->modp()->origName());
@@ -163,9 +509,7 @@ private:
pinNewVarp->user3(pinNewVarp->isSigUserRWPublic() && pinNewVarp->isOutOnly());
}
// Cleanup var names, etc, to not conflict
- m_cellp = nodep;
- newmodp->iterate(*this); // Not iterateAndNext because newmodp isn't linked; no back
- m_cellp = NULL;
+ { InlineRelinkVisitor(newmodp, m_modp, nodep); }
// Move statements to top module
if (debug()>=9) { newmodp->dumpTree(cout,"fixmod:"); }
AstNode* stmtsp = newmodp->stmtsp();
@@ -178,133 +522,10 @@ private:
if (debug()>=9) { m_modp->dumpTree(cout,"donemod:"); }
}
}
- virtual void visit(AstVar* nodep, AstNUser*) {
- if (m_cellp) {
- if (nodep->user2p()) {
- // Make an assignment, so we'll trace it properly
- // user2p is either a const or a var.
- AstConst* exprconstp = nodep->user2p()->castNode()->castConst();
- AstVarRef* exprvarrefp = nodep->user2p()->castNode()->castVarRef();
- UINFO(8,"connectto: "<<nodep->user2p()->castNode()<<endl);
- if (!exprconstp && !exprvarrefp) {
- nodep->v3fatalSrc("Unknown interconnect type; pinReconnectSimple should have cleared up\n");
- }
- if (exprconstp) {
- m_modp->addStmtp(new AstAssignW(nodep->fileline(),
- new AstVarRef(nodep->fileline(), nodep, true),
- exprconstp->cloneTree(true)));
- } else if (nodep->user3()) {
- // Public variable at the lower module end - we need to make sure we propagate
- // the logic changes up and down; if we aliased, we might remove the change detection
- // on the output variable.
- UINFO(9,"public pin assign: "<<exprvarrefp<<endl);
- if (nodep->isInput()) nodep->v3fatalSrc("Outputs only - inputs use AssignAlias");
- m_modp->addStmtp(new AstAssignW(nodep->fileline(),
- new AstVarRef(nodep->fileline(), exprvarrefp->varp(), true),
- new AstVarRef(nodep->fileline(), nodep, false)));
- } else {
- m_modp->addStmtp(new AstAssignAlias(nodep->fileline(),
- new AstVarRef(nodep->fileline(), nodep, true),
- new AstVarRef(nodep->fileline(), exprvarrefp->varp(), false)));
- AstNode* nodebp=exprvarrefp->varp();
- nodep ->fileline()->modifyStateInherit(nodebp->fileline());
- nodebp->fileline()->modifyStateInherit(nodep ->fileline());
- }
- }
- // Variable under the inline cell, need to rename to avoid conflicts
- // Also clear I/O bits, as it is now local.
- string name = m_cellp->name() + "__DOT__" + nodep->name();
- if (!nodep->isFuncLocal()) nodep->inlineAttrReset(name);
- if (debug()>=9) { nodep->dumpTree(cout,"varchanged:"); }
- if (debug()>=9) { nodep->valuep()->dumpTree(cout,"varchangei:"); }
- }
- if (nodep) nodep->iterateChildren(*this);
- }
- virtual void visit(AstNodeFTask* nodep, AstNUser*) {
- if (m_cellp) {
- // Function under the inline cell, need to rename to avoid conflicts
- nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
- }
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstTypedef* nodep, AstNUser*) {
- if (m_cellp) {
- // Typedef under the inline cell, need to rename to avoid conflicts
- nodep->name(m_cellp->name() + "__DOT__" + nodep->name());
- }
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstVarRef* nodep, AstNUser*) {
- if (m_cellp) {
- if (nodep->varp()->user2p() // It's being converted to an alias.
- && !nodep->varp()->user3()
- && !nodep->backp()->castAssignAlias()) { // Don't constant propagate aliases (we just made)
- AstConst* exprconstp = nodep->varp()->user2p()->castNode()->castConst();
- AstVarRef* exprvarrefp = nodep->varp()->user2p()->castNode()->castVarRef();
- if (exprconstp) {
- nodep->replaceWith(exprconstp->cloneTree(true));
- nodep->deleteTree(); nodep=NULL;
- return;
- }
- else if (exprvarrefp) {
- nodep->varp( exprvarrefp->varp() );
- }
- else {
- nodep->v3fatalSrc("Null connection?\n");
- }
- }
- nodep->name(nodep->varp()->name());
- }
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstVarXRef* nodep, AstNUser*) {
- if (m_cellp) {
- // Track what scope it was originally under so V3LinkDot can resolve it
- string newname = m_cellp->name();
- if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
- nodep->inlinedDots(newname);
- UINFO(8," "<<nodep<<endl);
- }
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
- if (m_cellp) {
- // Track what scope it was originally under so V3LinkDot can resolve it
- string newname = m_cellp->name();
- if (nodep->inlinedDots() != "") { newname += "." + nodep->inlinedDots(); }
- nodep->inlinedDots(newname);
- UINFO(8," "<<nodep<<endl);
- }
- nodep->iterateChildren(*this);
- }
-
- // Not needed, as V3LinkDot doesn't care about typedefs
- //virtual void visit(AstRefDType* nodep, AstNUser*) {}
-
- virtual void visit(AstScopeName* nodep, AstNUser*) {
- // If there's a %m in the display text, we add a special node that will contain the name()
- // Similar code in V3Begin
- if (m_cellp) {
- // To keep correct visual order, must add before other Text's
- AstNode* afterp = nodep->scopeAttrp();
- if (afterp) afterp->unlinkFrBackWithNext();
- nodep->scopeAttrp(new AstText(nodep->fileline(), (string)"__DOT__"+m_cellp->name()));
- if (afterp) nodep->scopeAttrp(afterp);
- }
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstCoverDecl* nodep, AstNUser*) {
- // Fix path in coverage statements
- if (m_cellp) {
- nodep->hier(m_cellp->prettyName()
- + (nodep->hier()!="" ? ".":"")
- + nodep->hier());
- }
- nodep->iterateChildren(*this);
- }
//--------------------
- // Default: Just iterate
+ virtual void visit(AstNodeMath* nodep, AstNUser*) {} // Accelerate
+ virtual void visit(AstNodeStmt* nodep, AstNUser*) {} // Accelerate
virtual void visit(AstNode* nodep, AstNUser*) {
nodep->iterateChildren(*this);
}
@@ -312,7 +533,6 @@ private:
public:
// CONSTUCTORS
InlineVisitor(AstNode* nodep) {
- m_cellp = NULL;
m_modp = NULL;
nodep->accept(*this);
}
@@ -322,126 +542,6 @@ public:
};
//######################################################################
-// Inline state, as a visitor of each AstNode
-
-class InlineMarkVisitor : public AstNVisitor {
-private:
- // NODE STATE
- // Entire netlist
- // AstNodeModule::user1() // OUTPUT: bool. User request to inline this module
- // AstNodeModule::user2() // bool. Allowed to automatically inline module
- // AstNodeModule::user3() // int. Number of cells referencing this module
- AstUser1InUse m_inuser1;
- AstUser2InUse m_inuser2;
- AstUser3InUse m_inuser3;
-
- // STATE
- AstNodeModule* m_modp; // Current module
- int m_stmtCnt; // Statements in module
-
- // METHODS
- void cantInline(const char* reason) {
- if (m_modp->user2()) {
- UINFO(4," No inline: "<<reason<<" "<<m_modp<<endl);
- m_modp->user2(false);
- }
- }
-
- // VISITORS
- virtual void visit(AstNodeModule* nodep, AstNUser*) {
- m_stmtCnt = 0;
- m_modp = nodep;
- m_modp->user2(true); // Allowed = true
- if (m_modp->modPublic()) cantInline("modPublic");
- //
- nodep->iterateChildren(*this);
- //
- bool userinline = nodep->user1();
- bool allowed = nodep->user2();
- int refs = nodep->user3();
- // Should we automatically inline this module?
- // inlineMult = 2000 by default. If a mod*#instances is < this # nodes, can inline it
- bool doit = (userinline || (allowed && (refs==1
- || m_stmtCnt < INLINE_MODS_SMALLER
- || v3Global.opt.inlineMult() < 1
- || refs*m_stmtCnt < v3Global.opt.inlineMult())));
- // Packages aren't really "under" anything so they confuse this algorithm
- if (nodep->castPackage()) doit = false;
- UINFO(4, " Inline="<<doit<<" Possible="<<allowed<<" Usr="<<userinline<<" Refs="<<refs<<" Stmts="<<m_stmtCnt
- <<" "<<nodep<<endl);
- if (doit) {
- UINFO(4," AutoInline "<<nodep<<endl);
- nodep->user1(true);
- }
- m_modp = NULL;
- }
- virtual void visit(AstCell* nodep, AstNUser*) {
- nodep->modp()->user3Inc();
- nodep->iterateChildren(*this);
- }
- virtual void visit(AstPragma* nodep, AstNUser*) {
- if (nodep->pragType() == AstPragmaType::INLINE_MODULE) {
- //UINFO(0,"PRAG MARK "<<m_modp<<endl);
- if (!m_modp) {
- nodep->v3error("Inline pragma not under a module");
- } else {
- m_modp->user1(1);
- }
- nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
- } else if (nodep->pragType() == AstPragmaType::NO_INLINE_MODULE) {
- if (!m_modp) {
- nodep->v3error("Inline pragma not under a module");
- } else {
- cantInline("Pragma NO_INLINE_MODULE");
- }
- nodep->unlinkFrBack()->deleteTree(); nodep=NULL; // Remove so don't propagate to upper cell...
- } else {
- nodep->iterateChildren(*this);
- }
- }
- virtual void visit(AstVarXRef* nodep, AstNUser*) {
- // Cleanup link until V3LinkDot can correct it
- nodep->varp(NULL);
- }
- virtual void visit(AstNodeFTaskRef* nodep, AstNUser*) {
- // Cleanup link until V3LinkDot can correct it
- if (!nodep->packagep()) nodep->taskp(NULL);
- nodep->iterateChildren(*this);
- }
- // Nop's to speed up the loop
- virtual void visit(AstAlways* nodep, AstNUser*) {
- nodep->iterateChildren(*this);
- m_stmtCnt++;
- }
- virtual void visit(AstNodeAssign* nodep, AstNUser*) {
- // Don't count assignments, as they'll likely flatten out
- // Still need to iterate though to nullify VarXRefs
- int oldcnt = m_stmtCnt;
- nodep->iterateChildren(*this);
- m_stmtCnt = oldcnt;
- }
- //--------------------
- // Default: Just iterate
- virtual void visit(AstNode* nodep, AstNUser*) {
- nodep->iterateChildren(*this);
- m_stmtCnt++;
- }
-
-public:
- // CONSTUCTORS
- InlineMarkVisitor(AstNode* nodep) {
- m_modp = NULL;
- m_stmtCnt = 0;
- //VV***** We reset all userp() on the whole netlist!!!
- AstNode::user1ClearTree();
- AstNode::user2ClearTree();
- AstNode::user3ClearTree();
- nodep->accept(*this);
- }
- virtual ~InlineMarkVisitor() {}
-};
-
-//######################################################################
// Inline class functions
void V3Inline::inlineAll(AstNetlist* nodep) {
diff --git a/src/V3Inst.cpp b/src/V3Inst.cpp
index ecdbe2a..c0a7b6f 100644
--- a/src/V3Inst.cpp
+++ b/src/V3Inst.cpp
@@ -105,6 +105,13 @@ private:
exprp);
m_modp->addStmtp(assp);
if (debug()>=9) assp->dumpTree(cout," _new: ");
+ } else if (nodep->modVarp()->isIfaceRef()) {
+ // Create an AstAssignVarScope for Vars to Cells so we can link with their scope later
+ AstNode* lhsp = new AstVarXRef (exprp->fileline(), nodep->modVarp(), m_cellp->name(), false);
+ AstVarRef* refp = exprp->castVarRef();
+ if (!refp) exprp->v3fatalSrc("Interfaces: Pin is not connected to a VarRef");
+ AstAssignVarScope* assp = new AstAssignVarScope(exprp->fileline(), lhsp, refp);
+ m_modp->addStmtp(assp);
} else {
nodep->v3error("Assigned pin is neither input nor output");
}
@@ -252,7 +259,11 @@ AstAssignW* V3Inst::pinReconnectSimple(AstPin* pinp, AstCell* cellp, AstNodeModu
&& connectRefp
&& connectRefp->varp()->dtypep()->sameTree(pinVarp->dtypep())
&& !connectRefp->varp()->isSc()) { // Need the signal as a 'shell' to convert types
- // Done. Same data type
+ // Done. Same data type
+ } else if (!alwaysCvt
+ && connectRefp
+ && connectRefp->varp()->isIfaceRef()) {
+ // Done. Interface
} else if (!alwaysCvt
&& connBasicp
&& pinBasicp
diff --git a/src/V3LanguageWords.h b/src/V3LanguageWords.h
index 7f02a58..8e9b469 100644
--- a/src/V3LanguageWords.h
+++ b/src/V3LanguageWords.h
@@ -37,9 +37,9 @@ class V3LanguageWords {
}
public:
string isKeyword(const string& kwd) {
- map<string,string>::iterator iter = m_kwdMap.find(kwd);
- if (iter == m_kwdMap.end()) return "";
- return iter->second;
+ map<string,string>::iterator it = m_kwdMap.find(kwd);
+ if (it == m_kwdMap.end()) return "";
+ return it->second;
}
public:
diff --git a/src/V3LinkCells.cpp b/src/V3LinkCells.cpp
index ad8a9df..127cc19 100644
--- a/src/V3LinkCells.cpp
+++ b/src/V3LinkCells.cpp
@@ -190,6 +190,7 @@ private:
<<"' does not match "<<nodep->typeName()<<" name: "<<nodep->prettyName());
}
}
+ if (nodep->castIface() || nodep->castPackage()) nodep->inLibrary(true); // Interfaces can't be at top, unless asked
bool topMatch = (v3Global.opt.topModule()==nodep->prettyName());
if (topMatch) {
m_topVertexp = vertex(nodep);
@@ -210,6 +211,25 @@ private:
m_modp = NULL;
}
+ virtual void visit(AstIfaceRefDType* nodep, AstNUser*) {
+ // Cell: Resolve its filename. If necessary, parse it.
+ UINFO(4,"Link IfaceRef: "<<nodep<<endl);
+ // Use findIdUpward instead of findIdFlat; it doesn't matter for now
+ // but we might support modules-under-modules someday.
+ AstNodeModule* modp = resolveModule(nodep, nodep->ifaceName());
+ if (modp) {
+ if (modp->castIface()) {
+ // Track module depths, so can sort list from parent down to children
+ new V3GraphEdge(&m_graph, vertex(m_modp), vertex(modp), 1, false);
+ if (!nodep->cellp()) nodep->ifacep(modp->castIface());
+ } else if (modp->castNotFoundModule()) { // Will error out later
+ } else {
+ nodep->v3error("Non-interface used as an interface: "<<nodep->prettyName());
+ }
+ }
+ // Note cannot do modport resolution here; modports are allowed underneath generates
+ }
+
virtual void visit(AstPackageImport* nodep, AstNUser*) {
// Package Import: We need to do the package before the use of a package
nodep->iterateChildren(*this);
@@ -314,6 +334,23 @@ private:
}
}
}
+ if (nodep->modp()->castIface()) {
+ // Cell really is the parent's instantiation of an interface, not a normal module
+ // Make sure we have a variable to refer to this cell, so can <ifacename>.<innermember>
+ // in the same way that a child does. Rename though to avoid conflict with cell.
+ // This is quite similar to how classes work; when unpacked classes are better supported
+ // may remap interfaces to be more like a class.
+ if (!nodep->hasIfaceVar()) {
+ string varName = nodep->name()+"__Viftop"; // V3LinkDot looks for this naming
+ AstIfaceRefDType* idtypep = new AstIfaceRefDType(nodep->fileline(), nodep->name(), nodep->modp()->name());
+ idtypep->cellp(nodep); // Only set when real parent cell known
+ idtypep->ifacep(NULL); // cellp overrides
+ AstVar* varp = new AstVar(nodep->fileline(), AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
+ varp->isIfaceParent(true);
+ nodep->addNextHere(varp);
+ nodep->hasIfaceVar(true);
+ }
+ }
if (nodep->modp()) {
nodep->iterateChildren(*this);
}
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 52588db..c98be54 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -31,6 +31,26 @@
// VarXRef/Func's:
// Find appropriate named cell and link to var they reference
//*************************************************************************
+// Interfaces:
+// CELL (.port (ifref)
+// ^--- cell -> IfaceDTypeRef(iface)
+// ^--- cell.modport -> IfaceDTypeRef(iface,modport)
+// ^--- varref(input_ifref) -> IfaceDTypeRef(iface)
+// ^--- varref(input_ifref).modport -> IfaceDTypeRef(iface,modport)
+// FindVisitor:
+// #1: Insert interface Vars
+// #2: Insert ModPort names
+// IfaceVisitor:
+// #3: Update ModPortVarRef to point at interface vars (after #1)
+// #4: Create ModPortVarRef symbol table entries
+// FindVisitor-insertIfaceRefs()
+// #5: Resolve IfaceRefDtype modport names (after #2)
+// #7: Record sym of IfaceRefDType and aliased interface and/or modport (after #4,#5)
+// insertAllScopeAliases():
+// #8: Insert modport's symbols under IfaceRefDType (after #7)
+// ResolveVisitor:
+// #9: Resolve general variables, which may point into the interface or modport (after #8)
+//*************************************************************************
// TOP
// {name-of-top-modulename}
// a (VSymEnt->AstCell)
@@ -77,17 +97,26 @@ private:
AstUser4InUse m_inuser4;
// TYPES
- typedef std::multimap<string,VSymEnt*> NameScopeMap;
- typedef set <pair<AstNodeModule*,string> > ImplicitNameSet;
+ typedef multimap<string,VSymEnt*> NameScopeSymMap;
+ typedef map<VSymEnt*,VSymEnt*> ScopeAliasMap;
+ typedef set<pair<AstNodeModule*,string> > ImplicitNameSet;
+ typedef vector<VSymEnt*> IfaceVarSyms;
+ typedef vector<pair<AstIface*,VSymEnt*> > IfaceModSyms;
+
+ static LinkDotState* s_errorThisp; // Last self, for error reporting only
// MEMBERS
VSymGraph m_syms; // Symbol table
VSymEnt* m_dunitEntp; // $unit entry
- NameScopeMap m_nameScopeMap; // Hash of scope referenced by non-pretty textual name
+ NameScopeSymMap m_nameScopeSymMap; // Map of scope referenced by non-pretty textual name
ImplicitNameSet m_implicitNameSet; // For [module][signalname] if we can implicitly create it
+ ScopeAliasMap m_scopeAliasMap; // Map of <lhs,rhs> aliases
+ IfaceVarSyms m_ifaceVarSyms; // List of AstIfaceRefDType's to be imported
+ IfaceModSyms m_ifaceModSyms; // List of AstIface+Symbols to be processed
bool m_forPrimary; // First link
bool m_forPrearray; // Compress cell__[array] refs
bool m_forScopeCreation; // Remove VarXRefs for V3Scope
+
public:
static int debug() {
@@ -95,14 +124,27 @@ public:
if (VL_UNLIKELY(level < 0)) level = v3Global.opt.debugSrcLevel(__FILE__);
return level;
}
- void dump() {
- if (debug()>=6) m_syms.dumpFilePrefixed("linkdot");
+ void dump(const string& nameComment="linkdot", bool force=false) {
+ if (debug()>=6 || force) {
+ string filename = v3Global.debugFilename(nameComment)+".txt";
+ const auto_ptr<ofstream> logp (V3File::new_ofstream(filename));
+ if (logp->fail()) v3fatalSrc("Can't write "<<filename);
+ ostream& os = *logp;
+ m_syms.dump(os);
+ if (!m_scopeAliasMap.empty()) os<<"\nScopeAliasMap:\n";
+ for (ScopeAliasMap::iterator it = m_scopeAliasMap.begin(); it != m_scopeAliasMap.end(); ++it) {
+ os<<"\t"<<it->first<<" -> "<<it->second<<endl;
+ }
+ }
+ }
+ static void preErrorDumpHandler() {
+ if (s_errorThisp) s_errorThisp->preErrorDump();
}
void preErrorDump() {
static bool diddump = false;
if (!diddump && v3Global.opt.dumpTree()) {
diddump = true;
- m_syms.dumpFilePrefixed("linkdot-preerr");
+ dump("linkdot-preerr",true);
v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("linkdot-preerr.tree"));
}
}
@@ -115,8 +157,13 @@ public:
m_forPrearray = (step == LDS_PARAMED || step==LDS_PRIMARY);
m_forScopeCreation = (step == LDS_SCOPED);
m_dunitEntp = NULL;
+ s_errorThisp = this;
+ V3Error::errorExitCb(preErrorDumpHandler); // If get error, dump self
+ }
+ ~LinkDotState() {
+ V3Error::errorExitCb(NULL);
+ s_errorThisp = NULL;
}
- ~LinkDotState() {}
// ACCESSORS
VSymGraph* symsp() { return &m_syms; }
@@ -131,6 +178,7 @@ public:
else if (nodep->castTask()) return "task";
else if (nodep->castFunc()) return "function";
else if (nodep->castBegin()) return "block";
+ else if (nodep->castIface()) return "interface";
else return nodep->prettyTypeName();
}
static string ucfirst(const string& text) {
@@ -161,7 +209,6 @@ public:
// Begin: ... blocks often replicate under genif/genfor, so simply suppress duplicate checks
// See t_gen_forif.v for an example.
} else {
- preErrorDump();
UINFO(4,"name "<<name<<endl); // Not always same as nodep->name
UINFO(4,"Var1 "<<nodep<<endl);
UINFO(4,"Var2 "<<fnodep<<endl);
@@ -195,7 +242,7 @@ public:
nodep->user1p(symp);
checkDuplicate(rootEntp(), nodep, nodep->origName());
rootEntp()->insert(nodep->origName(),symp);
- if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
+ if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertCell(VSymEnt* abovep, VSymEnt* modSymp,
@@ -214,7 +261,7 @@ public:
// Duplicates are possible, as until resolve generates might have 2 same cells under an if
modSymp->reinsert(nodep->name(), symp);
}
- if (forScopeCreation()) m_nameScopeMap.insert(make_pair(scopename, symp));
+ if (forScopeCreation()) m_nameScopeSymMap.insert(make_pair(scopename, symp));
return symp;
}
VSymEnt* insertInline(VSymEnt* abovep, VSymEnt* modSymp,
@@ -246,7 +293,7 @@ public:
UINFO(9," INSERTblk se"<<(void*)symp<<" above=se"<<(void*)abovep<<" node="<<nodep<<endl);
symp->parentp(abovep);
symp->packagep(packagep);
- symp->fallbackp(abovep); // Needed so can find $unit stuff
+ symp->fallbackp(abovep);
nodep->user1p(symp);
if (name != "") {
checkDuplicate(abovep, nodep, name);
@@ -278,17 +325,17 @@ public:
return symp;
}
VSymEnt* getScopeSym(AstScope* nodep) {
- NameScopeMap::iterator iter = m_nameScopeMap.find(nodep->name());
- if (iter == m_nameScopeMap.end()) {
+ NameScopeSymMap::iterator it = m_nameScopeSymMap.find(nodep->name());
+ if (it == m_nameScopeSymMap.end()) {
nodep->v3fatalSrc("Scope never assigned a symbol entry?");
}
- return iter->second;
+ return it->second;
}
void implicitOkAdd(AstNodeModule* nodep, const string& varname) {
// Mark the given variable name as being allowed to be implicitly declared
if (nodep) {
- ImplicitNameSet::iterator iter = m_implicitNameSet.find(make_pair(nodep,varname));
- if (iter == m_implicitNameSet.end()) {
+ ImplicitNameSet::iterator it = m_implicitNameSet.find(make_pair(nodep,varname));
+ if (it == m_implicitNameSet.end()) {
m_implicitNameSet.insert(make_pair(nodep,varname));
}
}
@@ -298,6 +345,69 @@ public:
&& (m_implicitNameSet.find(make_pair(nodep,varname)) != m_implicitNameSet.end());
}
+ // Track and later recurse interface modules
+ void insertIfaceModSym(AstIface* nodep, VSymEnt* symp) {
+ m_ifaceModSyms.push_back(make_pair(nodep, symp));
+ }
+ void computeIfaceModSyms();
+
+ // Track and later insert interface references
+ void insertIfaceVarSym(VSymEnt* symp) { // Where sym is for a VAR of dtype IFACEREFDTYPE
+ m_ifaceVarSyms.push_back(symp);
+ }
+ void computeIfaceVarSyms() {
+ for (IfaceVarSyms::iterator it = m_ifaceVarSyms.begin(); it != m_ifaceVarSyms.end(); ++it) {
+ VSymEnt* varSymp = *it;
+ AstVar* varp = varSymp->nodep()->castVar();
+ UINFO(9, " insAllIface se"<<(void*)varSymp<<" "<<varp<<endl);
+ AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType();
+ if (!ifacerefp) varp->v3fatalSrc("Non-ifacerefs on list!");
+ if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
+ VSymEnt* ifaceSymp = getNodeSym(ifacerefp->ifaceViaCellp());
+ VSymEnt* ifOrPortSymp = ifaceSymp;
+ // Link Modport names to the Modport Node under the Interface
+ if (ifacerefp->isModport()) {
+ VSymEnt* foundp = ifaceSymp->findIdFallback(ifacerefp->modportName());
+ bool ok = false;
+ if (foundp) {
+ if (AstModport* modportp = foundp->nodep()->castModport()) {
+ UINFO(4,"Link Modport: "<<modportp<<endl);
+ ifacerefp->modportp(modportp);
+ ifOrPortSymp = foundp;
+ ok = true;
+ }
+ }
+ if (!ok) ifacerefp->v3error("Modport not found under interface '"
+ <<ifacerefp->prettyName(ifacerefp->ifaceName())
+ <<"': "<<ifacerefp->prettyName(ifacerefp->modportName()));
+ }
+ // Alias won't expand until interfaces and modport names are known; see notes at top
+ insertScopeAlias(varSymp, ifOrPortSymp);
+ }
+ m_ifaceVarSyms.clear();
+ }
+
+ // Track and later insert scope aliases
+ void insertScopeAlias(VSymEnt* lhsp, VSymEnt* rhsp) { // Typically lhsp=VAR w/dtype IFACEREF, rhsp=IFACE cell
+ UINFO(9," insertScopeAlias se"<<(void*)lhsp<<" se"<<(void*)rhsp<<endl);
+ m_scopeAliasMap.insert(make_pair(lhsp, rhsp));
+ }
+ void computeScopeAliases() {
+ UINFO(9,"computeIfaceAliases\n");
+ for (ScopeAliasMap::iterator it=m_scopeAliasMap.begin(); it!=m_scopeAliasMap.end(); ++it) {
+ VSymEnt* lhsp = it->first;
+ VSymEnt* srcp = lhsp;
+ while (1) { // Follow chain of aliases up to highest level non-alias
+ ScopeAliasMap::iterator it2 = m_scopeAliasMap.find(srcp);
+ if (it2 != m_scopeAliasMap.end()) { srcp = it2->second; continue; }
+ else break;
+ }
+ UINFO(9," iiasa: Insert alias se"<<lhsp<<" <- se"<<srcp<<" "<<srcp->nodep()<<endl);
+ // srcp should be an interface reference pointing to the interface we want to import
+ lhsp->importFromIface(symsp(), srcp);
+ }
+ m_scopeAliasMap.clear();
+ }
private:
VSymEnt* findWithAltFallback(VSymEnt* symp, const string& name, const string& altname) {
VSymEnt* findp = symp->findIdFallback(name);
@@ -399,10 +509,11 @@ public:
}
};
+LinkDotState* LinkDotState::s_errorThisp = NULL;
+
//======================================================================
class LinkDotFindVisitor : public AstNVisitor {
-private:
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
AstPackage* m_packagep; // Current package
@@ -486,6 +597,10 @@ private:
// Iterate
nodep->iterateChildren(*this);
nodep->user4(true);
+ // Interfaces need another pass when signals are resolved
+ if (AstIface* ifacep = nodep->castIface()) {
+ m_statep->insertIfaceModSym(ifacep, m_curSymp);
+ }
} else { //!doit
// Will be optimized away later
// Can't remove now, as our backwards iterator will throw up
@@ -525,7 +640,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, scope, baddot, okSymp);
if (!aboveSymp) {
- m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cell insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
}
@@ -554,7 +668,6 @@ private:
VSymEnt* okSymp;
aboveSymp = m_statep->findDotted(aboveSymp, dotted, baddot, okSymp);
if (!aboveSymp) {
- m_statep->preErrorDump();
nodep->v3fatalSrc("Can't find cellinline insertion point at '"<<baddot<<"' in: "<<nodep->prettyName());
}
m_statep->insertInline(aboveSymp, m_modSymp, nodep, ident);
@@ -666,7 +779,6 @@ private:
if (!foundp) {
ins=true;
} else if (!findvarp && foundp && m_curSymp->findIdFlat(nodep->name())) {
- m_statep->preErrorDump();
nodep->v3error("Unsupported in C: Variable has same name as "
<<LinkDotState::nodeTextType(foundp->nodep())<<": "<<nodep->prettyName());
} else if (findvarp != nodep) {
@@ -705,12 +817,16 @@ private:
}
}
if (ins) {
- m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
+ VSymEnt* insp = m_statep->insertSym(m_curSymp, nodep->name(), nodep, m_packagep);
if (m_statep->forPrimary() && nodep->isGParam()) {
m_paramNum++;
VSymEnt* symp = m_statep->insertSym(m_curSymp, "__paramNumber"+cvtToStr(m_paramNum), nodep, m_packagep);
symp->exported(false);
}
+ if (nodep->subDTypep()->castIfaceRefDType()) {
+ // Can't resolve until interfaces and modport names are known; see notes at top
+ m_statep->insertIfaceVarSym(insp);
+ }
}
}
}
@@ -763,7 +879,7 @@ private:
nodep->v3error("Import object not found: "<<nodep->packagep()->prettyName()<<"::"<<nodep->prettyName());
}
}
- m_curSymp->import(m_statep->symsp(), srcp, nodep->name());
+ m_curSymp->importFromPackage(m_statep->symsp(), srcp, nodep->name());
UINFO(9," Link Done: "<<nodep<<endl);
// No longer needed, but can't delete until any multi-instantiated modules are expanded
}
@@ -885,8 +1001,8 @@ private:
AstVar* refp = foundp->nodep()->castVar();
if (!refp) {
nodep->v3error("Input/output/inout declaration not found for port: "<<nodep->prettyName());
- } else if (!refp->isIO()) {
- nodep->v3error("Pin is not an in/out/inout: "<<nodep->prettyName());
+ } else if (!refp->isIO() && !refp->isIfaceRef()) {
+ nodep->v3error("Pin is not an in/out/inout/interface: "<<nodep->prettyName());
} else {
refp->user4(true);
VSymEnt* symp = m_statep->insertSym(m_statep->getNodeSym(m_modp),
@@ -942,9 +1058,10 @@ public:
//======================================================================
class LinkDotScopeVisitor : public AstNVisitor {
-private:
+
// STATE
LinkDotState* m_statep; // State to pass between visitors, including symbol table
+ AstScope* m_scopep; // The current scope
VSymEnt* m_modSymp; // Symbol entry for current module
int debug() { return LinkDotState::debug(); }
@@ -960,12 +1077,36 @@ private:
// Using the CELL names, we created all hierarchy. We now need to match this Scope
// up with the hierarchy created by the CELL names.
m_modSymp = m_statep->getScopeSym(nodep);
+ m_scopep = nodep;
nodep->iterateChildren(*this);
m_modSymp = NULL;
+ m_scopep = NULL;
}
virtual void visit(AstVarScope* nodep, AstNUser*) {
if (!nodep->varp()->isFuncLocal()) {
- m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
+ VSymEnt* varSymp = m_statep->insertSym(m_modSymp, nodep->varp()->name(), nodep, NULL);
+ if (nodep->varp()->isIfaceRef()
+ && nodep->varp()->isIfaceParent()) {
+ UINFO(9,"Iface parent ref var "<<nodep->varp()->name()<<" "<<nodep<<endl);
+ // Find the interface cell the var references
+ AstIfaceRefDType* dtypep = nodep->varp()->dtypep()->castIfaceRefDType();
+ if (!dtypep) nodep->v3fatalSrc("Non AstIfaceRefDType on isIfaceRef() var");
+ UINFO(9,"Iface parent dtype "<<dtypep<<endl);
+ string ifcellname = dtypep->cellName();
+ string baddot; VSymEnt* okSymp;
+ VSymEnt* cellSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
+ if (!cellSymp) nodep->v3fatalSrc("No symbol for interface cell: " <<nodep->prettyName(ifcellname));
+ UINFO(5, " Found interface cell: se"<<(void*)cellSymp<<" "<<cellSymp->nodep()<<endl);
+ if (dtypep->modportName()!="") {
+ VSymEnt* mpSymp = m_statep->findDotted(m_modSymp, ifcellname, baddot, okSymp);
+ if (!mpSymp) { nodep->v3fatalSrc("No symbol for interface modport: " <<nodep->prettyName(dtypep->modportName())); }
+ else cellSymp = mpSymp;
+ UINFO(5, " Found modport cell: se"<<(void*)cellSymp<<" "<<mpSymp->nodep()<<endl);
+ }
+ // Interface reference; need to put whole thing into symtable, but can't clone it now
+ // as we may have a later alias for it.
+ m_statep->insertScopeAlias(varSymp, cellSymp);
+ }
}
}
virtual void visit(AstNodeFTask* nodep, AstNUser*) {
@@ -976,15 +1117,44 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
// Track aliases created by V3Inline; if we get a VARXREF(aliased_from)
// we'll need to replace it with a VARXREF(aliased_to)
- if (m_statep->forScopeCreation()) {
- if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
- AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
- AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
- if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
- fromVscp->user2p(toVscp);
- }
+ if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\talias: ");
+ AstVarScope* fromVscp = nodep->lhsp()->castVarRef()->varScopep();
+ AstVarScope* toVscp = nodep->rhsp()->castVarRef()->varScopep();
+ if (!fromVscp || !toVscp) nodep->v3fatalSrc("Bad alias scopes");
+ fromVscp->user2p(toVscp);
nodep->iterateChildren(*this);
}
+ virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
+ UINFO(5,"ASSIGNVARSCOPE "<<nodep<<endl);
+ if (debug()>=9) nodep->dumpTree(cout,"-\t\t\t\tavs: ");
+ VSymEnt* rhsSymp;
+ {
+ AstVarRef* refp = nodep->rhsp()->castVarRef();
+ if (!refp) nodep->v3fatalSrc("Unsupported: Non VarRef attached to interface pin");
+ string scopename = refp->name();
+ string baddot; VSymEnt* okSymp;
+ VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
+ if (!symp) nodep->v3fatalSrc("No symbol for interface alias rhs");
+ UINFO(5, " Found a linked scope RHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
+ rhsSymp = symp;
+ }
+ VSymEnt* lhsSymp;
+ {
+ AstVarXRef* refp = nodep->lhsp()->castVarXRef();
+ if (!refp) nodep->v3fatalSrc("Unsupported: Non VarXRef attached to interface pin");
+ string scopename = refp->dotted()+"."+refp->name();
+ string baddot; VSymEnt* okSymp;
+ VSymEnt* symp = m_statep->findDotted(m_modSymp, scopename, baddot, okSymp);
+ if (!symp) nodep->v3fatalSrc("No symbol for interface alias lhs");
+ UINFO(5, " Found a linked scope LHS: "<<scopename<<" se"<<(void*)symp<<" "<<symp->nodep()<<endl);
+ lhsSymp = symp;
+ }
+ // Remember the alias - can't do it yet because we may have additional symbols to be added,
+ // or maybe an alias of an alias
+ m_statep->insertScopeAlias(lhsSymp, rhsSymp);
+ // We have stored the link, we don't need these any more
+ nodep->unlinkFrBack()->deleteTree(); nodep=NULL;
+ }
// For speed, don't recurse things that can't have scope
// Note we allow AstNodeStmt's as generates may be under them
virtual void visit(AstCell*, AstNUser*) {}
@@ -1000,6 +1170,7 @@ public:
LinkDotScopeVisitor(AstNetlist* rootp, LinkDotState* statep) {
UINFO(4,__FUNCTION__<<": "<<endl);
m_modSymp = NULL;
+ m_scopep = NULL;
m_statep = statep;
//
rootp->accept(*this);
@@ -1009,6 +1180,78 @@ public:
//======================================================================
+// Iterate an interface to resolve modports
+class LinkDotIfaceVisitor : public AstNVisitor {
+ // STATE
+ LinkDotState* m_statep; // State to pass between visitors, including symbol table
+ VSymEnt* m_curSymp; // Symbol Entry for current table, where to lookup/insert
+
+ // METHODS
+ int debug() { return LinkDotState::debug(); }
+
+ // VISITs
+ virtual void visit(AstModport* nodep, AstNUser*) {
+ // Modport: Remember its name for later resolution
+ UINFO(5," fiv: "<<nodep<<endl);
+ VSymEnt* oldCurSymp = m_curSymp;
+ {
+ // Create symbol table for the vars
+ m_curSymp = m_statep->insertBlock(m_curSymp, nodep->name(), nodep, NULL);
+ m_curSymp->fallbackp(oldCurSymp);
+ nodep->iterateChildren(*this);
+ }
+ m_curSymp = oldCurSymp;
+ }
+ virtual void visit(AstModportVarRef* nodep, AstNUser*) {
+ UINFO(5," fiv: "<<nodep<<endl);
+ nodep->iterateChildren(*this);
+ VSymEnt* symp = m_curSymp->findIdFallback(nodep->name());
+ if (!symp) {
+ nodep->v3error("Modport item not found: "<<nodep->prettyName());
+ } else if (AstVar* varp = symp->nodep()->castVar()) {
+ // Make symbol under modport that points at the _interface_'s var, not the modport.
+ nodep->varp(varp);
+ m_statep->insertSym(m_curSymp, nodep->name(), varp, NULL/*package*/);
+ } else if (AstVarScope* vscp = symp->nodep()->castVarScope()) {
+ // Make symbol under modport that points at the _interface_'s var, not the modport.
+ nodep->varp(vscp->varp());
+ m_statep->insertSym(m_curSymp, nodep->name(), vscp, NULL/*package*/);
+ } else {
+ nodep->v3error("Modport item is not a variable: "<<nodep->prettyName());
+ }
+ if (m_statep->forScopeCreation()) {
+ // Done with AstModportVarRef.
+ // Delete to prevent problems if we dead-delete pointed to variable
+ nodep->unlinkFrBack(); pushDeletep(nodep); nodep=NULL;
+ }
+ }
+ virtual void visit(AstNode* nodep, AstNUser*) {
+ // Default: Just iterate
+ nodep->iterateChildren(*this);
+ }
+
+public:
+ // CONSTUCTORS
+ LinkDotIfaceVisitor(AstIface* nodep, VSymEnt* curSymp, LinkDotState* statep) {
+ UINFO(4,__FUNCTION__<<": "<<endl);
+ m_curSymp = curSymp;
+ m_statep = statep;
+ nodep->accept(*this);
+ }
+ virtual ~LinkDotIfaceVisitor() {}
+};
+
+void LinkDotState::computeIfaceModSyms() {
+ for (IfaceModSyms::iterator it=m_ifaceModSyms.begin(); it!=m_ifaceModSyms.end(); ++it) {
+ AstIface* nodep = it->first;
+ VSymEnt* symp = it->second;
+ LinkDotIfaceVisitor(nodep, symp, this);
+ }
+ m_ifaceModSyms.clear();
+}
+
+//======================================================================
+
class LinkDotResolveVisitor : public AstNVisitor {
private:
// NODE STATE
@@ -1037,6 +1280,7 @@ private:
AstCell* m_cellp; // Current cell
AstNodeModule* m_modp; // Current module
AstNodeFTask* m_ftaskp; // Current function/task
+ int m_modportNum; // Uniqueify modport numbers
struct DotStates {
DotPosition m_dotPos; // Scope part of dotted resolution
@@ -1087,12 +1331,21 @@ private:
}
inline void checkNoDot(AstNode* nodep) {
if (VL_UNLIKELY(m_ds.m_dotPos != DP_NONE)) {
- m_statep->preErrorDump();
- UINFO(1,"ds="<<m_ds.ascii()<<endl);
+ //UINFO(9,"ds="<<m_ds.ascii()<<endl);
nodep->v3error("Syntax Error: Not expecting "<<nodep->type()<<" under a "<<nodep->backp()->type()<<" in dotted expression");
m_ds.m_dotErr = true;
}
}
+ AstVar* makeIfaceModportVar(FileLine* fl, AstCell* cellp, AstIface* ifacep, AstModport* modportp) {
+ // Create iface variable, using duplicate var when under same module scope
+ string varName = ifacep->name()+"__Vmp__"+modportp->name()+"__Viftop"+cvtToStr(++m_modportNum);
+ AstIfaceRefDType* idtypep = new AstIfaceRefDType(fl, cellp->name(), ifacep->name(), modportp->name());
+ idtypep->cellp(cellp);
+ AstVar* varp = new AstVar(fl, AstVarType::IFACEREF, varName, VFlagChildDType(), idtypep);
+ varp->isIfaceParent(true);
+ m_modp->addStmtp(varp);
+ return varp;
+ }
// VISITs
virtual void visit(AstNetlist* nodep, AstNUser* vup) {
@@ -1108,6 +1361,7 @@ private:
m_ds.m_dotSymp = m_curSymp = m_modSymp = m_statep->getNodeSym(nodep); // Until overridden by a SCOPE
m_cellp = NULL;
m_modp = nodep;
+ m_modportNum = 0;
nodep->iterateChildren(*this);
m_modp = NULL;
m_ds.m_dotSymp = m_curSymp = m_modSymp = NULL;
@@ -1130,7 +1384,7 @@ private:
}
}
virtual void visit(AstCell* nodep, AstNUser*) {
- // Cell: Resolve its filename. If necessary, parse it.
+ // Cell: Recurse inside or cleanup not founds
checkNoDot(nodep);
m_cellp = nodep;
AstNode::user5ClearTree();
@@ -1172,8 +1426,8 @@ private:
return;
}
nodep->v3error("Pin not found: "<<nodep->prettyName());
- } else if (!refp->isIO() && !refp->isParam()) {
- nodep->v3error("Pin is not an in/out/inout/param: "<<nodep->prettyName());
+ } else if (!refp->isIO() && !refp->isParam() && !refp->isIfaceRef()) {
+ nodep->v3error("Pin is not an in/out/inout/param/interface: "<<nodep->prettyName());
} else {
nodep->modVarp(refp);
if (refp->user5p() && refp->user5p()->castNode()!=nodep) {
@@ -1212,10 +1466,12 @@ private:
} else {
m_ds.m_dotPos = DP_SCOPE;
nodep->lhsp()->iterateAndNext(*this);
+ //if (debug()>=9) nodep->dumpTree("-dot-lho: ");
}
if (!m_ds.m_dotErr) { // Once something wrong, give up
if (start && m_ds.m_dotPos==DP_SCOPE) m_ds.m_dotPos = DP_FINAL; // Top 'final' dot RHS is final RHS, else it's a DOT(DOT(x,*here*),real-rhs) which we consider a RHS
nodep->rhsp()->iterateAndNext(*this);
+ //if (debug()>=9) nodep->dumpTree("-dot-rho: ");
}
if (start) {
AstNode* newp;
@@ -1299,7 +1555,8 @@ private:
} else {
foundp = m_ds.m_dotSymp->findIdFallback(nodep->name());
}
- if (foundp) UINFO(9," found=se"<<(void*)foundp<<" n="<<foundp->nodep()<<endl);
+ if (foundp) UINFO(9," found=se"<<(void*)foundp<<" exp="<<expectWhat
+ <<" n="<<foundp->nodep()<<endl);
// What fell out?
bool ok = false;
if (foundp->nodep()->castCell() || foundp->nodep()->castBegin()
@@ -1312,9 +1569,41 @@ private:
m_ds.m_dotPos = DP_SCOPE;
// Upper AstDot visitor will handle it from here
}
+ else if (foundp->nodep()->castCell()
+ && allowVar && m_cellp
+ && foundp->nodep()->castCell()->modp()->castIface()) {
+ // Interfaces can be referenced like a variable for interconnect
+ AstCell* cellp = foundp->nodep()->castCell();
+ VSymEnt* cellEntp = m_statep->getNodeSym(cellp); if (!cellEntp) nodep->v3fatalSrc("No interface sym entry");
+ VSymEnt* parentEntp = cellEntp->parentp(); // Container of the var; probably a module or generate begin
+ string findName = nodep->name()+"__Viftop";
+ AstVar* ifaceRefVarp = parentEntp->findIdFallback(findName)->nodep()->castVar();
+ if (!ifaceRefVarp) nodep->v3fatalSrc("Can't find interface var ref: "<<findName);
+ //
+ ok = true;
+ if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
+ m_ds.m_dotText += nodep->name();
+ m_ds.m_dotSymp = foundp;
+ m_ds.m_dotPos = DP_SCOPE;
+ UINFO(9," cell -> iface varref "<<foundp->nodep()<<endl);
+ AstNode* newp = new AstVarRef(ifaceRefVarp->fileline(), ifaceRefVarp, false);
+ nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
+ }
}
else if (AstVar* varp = foundp->nodep()->castVar()) {
- if (allowVar) {
+ if (AstIfaceRefDType* ifacerefp = varp->subDTypep()->castIfaceRefDType()) {
+ if (!ifacerefp->ifaceViaCellp()) ifacerefp->v3fatalSrc("Unlinked interface");
+ // Really this is a scope reference into an interface
+ UINFO(9,"varref-ifaceref "<<m_ds.m_dotText<<" "<<nodep<<endl);
+ if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
+ m_ds.m_dotText += nodep->name();
+ m_ds.m_dotSymp = m_statep->getNodeSym(ifacerefp->ifaceViaCellp());
+ m_ds.m_dotPos = DP_SCOPE;
+ ok = true;
+ AstNode* newp = new AstVarRef(nodep->fileline(), varp, false);
+ nodep->replaceWith(newp); pushDeletep(nodep); nodep = NULL;
+ }
+ else if (allowVar) {
AstNodeVarRef* newp;
if (m_ds.m_dotText != "") {
newp = new AstVarXRef(nodep->fileline(), nodep->name(), m_ds.m_dotText, false); // lvalue'ness computed later
@@ -1331,6 +1620,34 @@ private:
ok = true;
}
}
+ else if (AstModport* modportp = foundp->nodep()->castModport()) {
+ // A scope reference into an interface's modport (not necessarily at a pin connection)
+ UINFO(9,"cell-ref-to-modport "<<m_ds.m_dotText<<" "<<nodep<<endl);
+ UINFO(9,"dotSymp "<<m_ds.m_dotSymp<<" "<<m_ds.m_dotSymp->nodep()<<endl);
+ // Iface was the previously dotted component
+ if (!m_ds.m_dotSymp
+ || !m_ds.m_dotSymp->nodep()->castCell()
+ || !m_ds.m_dotSymp->nodep()->castCell()->modp()
+ || !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
+ nodep->v3error("Modport not referenced as <interface>."<<modportp->prettyName());
+ } else if (!m_ds.m_dotSymp->nodep()->castCell()->modp()
+ || !m_ds.m_dotSymp->nodep()->castCell()->modp()->castIface()) {
+ nodep->v3error("Modport not referenced from underneath an interface: "<<modportp->prettyName());
+ } else {
+ AstCell* cellp = m_ds.m_dotSymp->nodep()->castCell();
+ if (!cellp) nodep->v3fatalSrc("Modport not referenced from a cell");
+ AstIface* ifacep = cellp->modp()->castIface();
+ //string cellName = m_ds.m_dotText; // Use cellp->name
+ if (m_ds.m_dotText!="") m_ds.m_dotText += ".";
+ m_ds.m_dotText += nodep->name();
+ m_ds.m_dotSymp = m_statep->getNodeSym(modportp);
+ m_ds.m_dotPos = DP_SCOPE;
+ ok = true;
+ AstVar* varp = makeIfaceModportVar(nodep->fileline(), cellp, ifacep, modportp);
+ AstVarRef* refp = new AstVarRef(varp->fileline(), varp, false);
+ nodep->replaceWith(refp); pushDeletep(nodep); nodep = NULL;
+ }
+ }
else if (AstEnumItem* valuep = foundp->nodep()->castEnumItem()) {
if (allowVar) {
AstNode* newp = new AstEnumItemRef(nodep->fileline(), valuep, foundp->packagep());
@@ -1344,7 +1661,6 @@ private:
bool checkImplicit = (!m_ds.m_dotp && m_ds.m_dotText=="");
bool err = !(checkImplicit && m_statep->implicitOk(m_modp, nodep->name()));
if (err) {
- m_statep->preErrorDump();
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
<<"'"<<" as a "<<foundp->nodep()->typeName()
@@ -1388,7 +1704,6 @@ private:
nodep->packagep(foundp->packagep()); // Generally set by parse, but might be an import
}
if (!nodep->varp()) {
- m_statep->preErrorDump();
nodep->v3error("Can't find definition of signal, again: "<<nodep->prettyName());
}
}
@@ -1412,7 +1727,6 @@ private:
string inl = AstNode::dedotName(nodep->inlinedDots());
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
- m_statep->preErrorDump();
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
}
@@ -1423,7 +1737,6 @@ private:
nodep->varp(varp);
UINFO(7," Resolved "<<nodep<<endl); // Also prints varp
if (!nodep->varp()) {
- m_statep->preErrorDump();
nodep->v3error("Can't find definition of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
}
@@ -1432,7 +1745,6 @@ private:
VSymEnt* foundp = m_statep->findSymPrefixed(dotSymp, nodep->name(), baddot);
AstVarScope* vscp = foundp->nodep()->castVarScope(); // maybe NULL
if (!vscp) {
- m_statep->preErrorDump();
nodep->v3error("Can't find varpin scope of '"<<baddot<<"' in dotted signal: "<<nodep->dotted()+"."+nodep->prettyName());
okSymp->cellErrorScopes(nodep);
} else {
@@ -1499,7 +1811,6 @@ private:
UINFO(8,"\t\tInlined "<<inl<<endl);
dotSymp = m_statep->findDotted(dotSymp, inl, baddot, okSymp);
if (!dotSymp) {
- m_statep->preErrorDump();
okSymp->cellErrorScopes(nodep);
nodep->v3fatalSrc("Couldn't resolve inlined scope '"<<baddot<<"' in: "<<nodep->inlinedDots());
}
@@ -1516,7 +1827,6 @@ private:
UINFO(7," Resolved "<<nodep<<endl); // Also prints taskp
} else {
// Note ParseRef has similar error handling/message output
- m_statep->preErrorDump();
UINFO(7," ErrFtask curSymp=se"<<(void*)m_curSymp<<" dotSymp=se"<<(void*)dotSymp<<endl);
if (foundp) {
nodep->v3error("Found definition of '"<<m_ds.m_dotText<<(m_ds.m_dotText==""?"":".")<<nodep->prettyName()
@@ -1670,6 +1980,7 @@ public:
m_cellp = NULL;
m_modp = NULL;
m_ftaskp = NULL;
+ m_modportNum = 0;
//
rootp->accept(*this);
}
@@ -1691,12 +2002,18 @@ void V3LinkDot::linkDotGuts(AstNetlist* rootp, VLinkDotStep step) {
LinkDotParamVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-param.tree"));
}
+ else if (step == LDS_ARRAYED) {}
else if (step == LDS_SCOPED) {
// Well after the initial link when we're ready to operate on the flat design,
// process AstScope's. This needs to be separate pass after whole hierarchy graph created.
LinkDotScopeVisitor visitors(rootp,&state);
if (LinkDotState::debug()>=5 || v3Global.opt.dumpTree()>=9) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("prelinkdot-scoped.tree"));
}
+ else v3fatalSrc("Bad case");
+ state.dump();
+ state.computeIfaceModSyms();
+ state.computeIfaceVarSyms();
+ state.computeScopeAliases();
state.dump();
LinkDotResolveVisitor visitorb(rootp,&state);
}
diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp
index 6bd8065..9829184 100644
--- a/src/V3LinkLevel.cpp
+++ b/src/V3LinkLevel.cpp
@@ -67,7 +67,7 @@ void V3LinkLevel::modSortByLevel() {
}
vec.push_back(nodep);
}
- sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
+ stable_sort(vec.begin(), vec.end(), CmpLevel()); // Sort the vector
for (ModVec::iterator it = vec.begin(); it != vec.end(); ++it) {
AstNodeModule* nodep = *it;
nodep->unlinkFrBack();
@@ -95,6 +95,18 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
newmodp->modPublic(true);
netlistp->addModulep(newmodp);
+ // TODO the module creation above could be done after linkcells, but
+ // the rest must be done after data type resolution
+ wrapTopCell(netlistp);
+ wrapTopPackages(netlistp);
+}
+
+void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
+ AstNodeModule* newmodp = netlistp->modulesp();
+ if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
+ AstNodeModule* oldmodp = newmodp->nextp()->castNodeModule();
+ if (!oldmodp) netlistp->v3fatalSrc("No module found to process");
+
// Add instance
AstCell* cellp = new AstCell(newmodp->fileline(),
(v3Global.opt.l2Name() ? "v" : oldmodp->name()),
@@ -126,13 +138,13 @@ void V3LinkLevel::wrapTop(AstNetlist* netlistp) {
}
}
}
-
- wrapTopPackages(netlistp, newmodp);
}
-void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp, AstNodeModule* newmodp) {
+void V3LinkLevel::wrapTopPackages(AstNetlist* netlistp) {
// Instantiate all packages under the top wrapper
// This way all later SCOPE based optimizations can ignore packages
+ AstNodeModule* newmodp = netlistp->modulesp();
+ if (!newmodp || !newmodp->isTop()) netlistp->v3fatalSrc("No TOP module found to process");
for (AstNodeModule* modp = netlistp->modulesp(); modp; modp=modp->nextp()->castNodeModule()) {
if (modp->castPackage()) {
AstCell* cellp = new AstCell(modp->fileline(),
diff --git a/src/V3LinkLevel.h b/src/V3LinkLevel.h
index da8f89c..8fbdf15 100644
--- a/src/V3LinkLevel.h
+++ b/src/V3LinkLevel.h
@@ -29,7 +29,8 @@
class V3LinkLevel {
private:
- static void wrapTopPackages(AstNetlist* nodep, AstNodeModule* newmodp);
+ static void wrapTopCell(AstNetlist* nodep);
+ static void wrapTopPackages(AstNetlist* nodep);
public:
static void modSortByLevel();
static void wrapTop(AstNetlist* nodep);
diff --git a/src/V3LinkParse.cpp b/src/V3LinkParse.cpp
index 6cdae56..16c3ad0 100644
--- a/src/V3LinkParse.cpp
+++ b/src/V3LinkParse.cpp
@@ -152,6 +152,12 @@ private:
nodep->valuep()->unlinkFrBack()));
}
}
+ if (nodep->isIfaceRef() && !nodep->isIfaceParent()) {
+ // Only AstIfaceRefDType's at this point correspond to ports;
+ // haven't made additional ones for interconnect yet, so assert is simple
+ // What breaks later is we don't have a Scope/Cell representing the interface to attach to
+ if (m_modp->level()<=2) nodep->v3error("Unsupported: Interfaced port on top level module");
+ }
}
virtual void visit(AstAttrOf* nodep, AstNUser*) {
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index 560be0e..e901b78 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -1307,7 +1307,7 @@ void V3Options::optimize(int level) {
m_oSubst = flag;
m_oSubstConst = flag;
m_oTable = flag;
- m_oDedupe = level >= 3;
+ m_oDedupe = flag;
// And set specific optimization levels
if (level >= 3) {
m_inlineMult = -1; // Maximum inlining
diff --git a/src/V3Order.cpp b/src/V3Order.cpp
index dd97550..38da6da 100644
--- a/src/V3Order.cpp
+++ b/src/V3Order.cpp
@@ -476,7 +476,7 @@ private:
// elements. Up to 10 of the widest
cerr<<V3Error::msgPrefix()
<<" Widest candidate vars to split:"<<endl;
- sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
+ std::stable_sort (m_unoptflatVars.begin(), m_unoptflatVars.end(), OrderVarWidthCmp());
int lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
@@ -489,8 +489,8 @@ private:
// Up to 10 of the most fanned out
cerr<<V3Error::msgPrefix()
<<" Most fanned out candidate vars to split:"<<endl;
- sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
- OrderVarFanoutCmp());
+ std::stable_sort (m_unoptflatVars.begin(), m_unoptflatVars.end(),
+ OrderVarFanoutCmp());
lim = m_unoptflatVars.size() < 10 ? m_unoptflatVars.size() : 10;
for (int i = 0; i < lim; i++) {
OrderVarStdVertex* vsvertexp = m_unoptflatVars[i];
@@ -1324,7 +1324,7 @@ void OrderVisitor::processEdgeReport() {
}
*logp<<"Signals and their clock domains:"<<endl;
- sort(report.begin(), report.end());
+ stable_sort(report.begin(), report.end());
for (deque<string>::iterator it=report.begin(); it!=report.end(); ++it) {
*logp<<(*it)<<endl;
}
diff --git a/src/V3Param.cpp b/src/V3Param.cpp
index 0676533..52ce09a 100644
--- a/src/V3Param.cpp
+++ b/src/V3Param.cpp
@@ -21,13 +21,31 @@
// Top down traversal:
// For each cell:
// If parameterized,
-// Determine all parameter widths, constant values
+// Determine all parameter widths, constant values.
+// (Interfaces also matter, as if an interface is parameterized
+// this effectively changes the width behavior of all that
+// reference the iface.)
// Clone module cell calls, renaming with __{par1}_{par2}_...
-// Substitute constants for cell's module's parameters
-// Relink pins and cell to point to new module
-// Then process all modules called by that cell
+// Substitute constants for cell's module's parameters.
+// Relink pins and cell and ifacerefdtype to point to new module.
+//
+// For interface Parent's we have the AstIfaceRefDType::cellp()
+// pointing to this module. If that parent cell's interface
+// module gets parameterized, AstIfaceRefDType::cloneRelink
+// will update AstIfaceRefDType::cellp(), and AstLinkDot will
+// see the new interface.
+//
+// However if a submodule's AstIfaceRefDType::ifacep() points
+// to the old (unparameterized) interface and needs correction.
+// To detect this we must walk all pins looking for interfaces
+// that the parent has changed and propagate down.
+//
+// Then process all modules called by that cell.
// (Cells never referenced after parameters expanded must be ignored.)
//
+// After we complete parameters, the varp's will be wrong (point to old module)
+// and must be relinked.
+//
//*************************************************************************
#include "config_build.h"
@@ -62,23 +80,34 @@ private:
AstUser5InUse m_inuser5;
// User1/2/3 used by constant function simulations
+ // TYPES
+ typedef deque<pair<AstIfaceRefDType*,AstIfaceRefDType*> > IfaceRefRefs; // Note may have duplicate entries
+
// STATE
- typedef std::map<AstVar*,AstVar*> VarCloneMap;
+ typedef map<AstVar*,AstVar*> VarCloneMap;
struct ModInfo {
AstNodeModule* m_modp; // Module with specified name
VarCloneMap m_cloneMap; // Map of old-varp -> new cloned varp
ModInfo(AstNodeModule* modp) { m_modp=modp; }
};
- typedef std::map<string,ModInfo> ModNameMap;
+ typedef map<string,ModInfo> ModNameMap;
ModNameMap m_modNameMap; // Hash of created module flavors by name
- typedef std::map<string,string> LongMap;
+ typedef map<string,string> LongMap;
LongMap m_longMap; // Hash of very long names to unique identity number
int m_longId;
+ typedef map<AstNode*,int> ValueMap;
+ typedef map<int,int> NextValueMap;
+ ValueMap m_valueMap; // Hash of node to param value
+ NextValueMap m_nextValueMap;// Hash of param value to next value to be used
+
typedef multimap<int,AstNodeModule*> LevelModMap;
LevelModMap m_todoModps; // Modules left to process
+ typedef deque<AstCell*> CellList;
+ CellList m_cellps; // Cells left to process (in this module)
+
// METHODS
static int debug() {
static int level = -1;
@@ -91,7 +120,7 @@ private:
// Pass 1, assign first letter to each gparam's name
for (AstNode* stmtp = modp->stmtsp(); stmtp; stmtp=stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
- if (varp->isGParam()) {
+ if (varp->isGParam()||varp->isIfaceRef()) {
char ch = varp->name()[0];
ch = toupper(ch); if (ch<'A' || ch>'Z') ch='Z';
varp->user4(usedLetter[static_cast<int>(ch)]*256 + ch);
@@ -113,6 +142,27 @@ private:
}
return st;
}
+ string paramValueNumber(AstNode* nodep) {
+ // Given a compilcated object create a number to use for param module assignment
+ // Ideally would be relatively stable if design changes (not use pointer value),
+ // and must return same value given same input node
+ // Return must presently be numberic so doesn't collide with 'small' alphanumeric parameter names
+ ValueMap::iterator it = m_valueMap.find(nodep);
+ if (it != m_valueMap.end()) {
+ return cvtToStr(it->second);
+ } else {
+ static int BUCKETS = 1000;
+ V3Hash hash (nodep->name());
+ int bucket = hash.hshval() % BUCKETS;
+ int offset = 0;
+ NextValueMap::iterator it = m_nextValueMap.find(bucket);
+ if (it != m_nextValueMap.end()) { offset = it->second; it->second = offset + 1; }
+ else { m_nextValueMap.insert(make_pair(bucket, offset + 1)); }
+ int num = bucket + offset * BUCKETS;
+ m_valueMap.insert(make_pair(nodep, num));
+ return cvtToStr(num);
+ }
+ }
void relinkPins(VarCloneMap* clonemapp, AstPin* startpinp) {
for (AstPin* pinp = startpinp; pinp; pinp=pinp->nextp()->castPin()) {
if (!pinp->modVarp()) pinp->v3fatalSrc("Not linked?\n");
@@ -123,9 +173,10 @@ private:
pinp->modVarp(cloneiter->second);
}
}
+ void visitCell(AstCell* nodep);
void visitModules() {
// Loop on all modules left to process
- // Hitting a cell adds to the appropriate leval of this level-sorted list,
+ // Hitting a cell adds to the appropriate level of this level-sorted list,
// so since cells originally exist top->bottom we process in top->bottom order too.
while (!m_todoModps.empty()) {
LevelModMap::iterator it = m_todoModps.begin();
@@ -134,7 +185,19 @@ private:
if (!nodep->user5SetOnce()) { // Process once; note clone() must clear so we do it again
UINFO(4," MOD "<<nodep<<endl);
nodep->iterateChildren(*this);
- // Note this may add to m_todoModps
+ // Note above iterate may add to m_todoModps
+ //
+ // Process interface cells, then non-interface which may ref an interface cell
+ for (int nonIf=0; nonIf<2; ++nonIf) {
+ for (CellList::iterator it=m_cellps.begin(); it!=m_cellps.end(); ++it) {
+ AstCell* nodep = *it;
+ if ((nonIf==0 && nodep->modp()->castIface())
+ || (nonIf==1 && !nodep->modp()->castIface())) {
+ visitCell(nodep);
+ }
+ }
+ }
+ m_cellps.clear();
}
}
}
@@ -157,7 +220,10 @@ private:
UINFO(4," MOD-dead? "<<nodep<<endl); // Should have been done by now, if not dead
}
}
- virtual void visit(AstCell* nodep, AstNUser*);
+ virtual void visit(AstCell* nodep, AstNUser*) {
+ // Must do ifaces first, so push to list and do in proper order
+ m_cellps.push_back(nodep);
+ }
// Make sure all parameters are constantified
virtual void visit(AstVar* nodep, AstNUser*) {
@@ -218,7 +284,7 @@ private:
//! Parameter subsitution for generated for loops.
//! @todo Unlike generated IF, we don't have to worry about short-circuiting the conditional
//! expression, since this is currently restricted to simple comparisons. If we ever do
- //! move to more generic constant expressions, such code will be neede here.
+ //! move to more generic constant expressions, such code will be needed here.
virtual void visit(AstBegin* nodep, AstNUser*) {
if (nodep->genforp()) {
AstGenFor* forp = nodep->genforp()->castGenFor();
@@ -317,11 +383,13 @@ public:
//----------------------------------------------------------------------
// VISITs
-void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
+void ParamVisitor::visitCell(AstCell* nodep) {
// Cell: Check for parameters in the instantiation.
nodep->iterateChildren(*this);
- if (!nodep->modp()) { nodep->dumpTree(cerr,"error:"); nodep->v3fatalSrc("Not linked?"); }
- if (nodep->paramsp()) {
+ if (!nodep->modp()) nodep->v3fatalSrc("Not linked?");
+ if (nodep->paramsp()
+ || 1 // Need to look for interfaces; could track when one exists, but should be harmless to always do this
+ ) {
UINFO(4,"De-parameterize: "<<nodep<<endl);
// Create new module name with _'s between the constants
if (debug()>=10) nodep->dumpTree(cout,"-cell:\t");
@@ -336,7 +404,6 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
longname += "_";
if (debug()>8) nodep->paramsp()->dumpTreeAndNext(cout,"-cellparams:\t");
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
- if (!pinp) nodep->v3fatalSrc("Non pin under cell params\n");
if (!pinp->exprp()) continue; // No-connect
AstVar* modvarp = pinp->modVarp();
if (!modvarp) {
@@ -360,6 +427,30 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
}
}
}
+ IfaceRefRefs ifaceRefRefs;
+ for (AstPin* pinp = nodep->pinsp(); pinp; pinp=pinp->nextp()->castPin()) {
+ AstVar* modvarp = pinp->modVarp();
+ if (modvarp->isIfaceRef()) {
+ AstIfaceRefDType* portIrefp = modvarp->subDTypep()->castIfaceRefDType();
+ //UINFO(9," portIfaceRef "<<portIrefp<<endl);
+ if (!pinp->exprp()
+ || !pinp->exprp()->castVarRef()
+ || !pinp->exprp()->castVarRef()->varp()
+ || !pinp->exprp()->castVarRef()->varp()->subDTypep()
+ || !pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType()) {
+ pinp->v3error("Interface port '"<<modvarp->prettyName()<<"' is not connected to interface/modport pin expression");
+ } else {
+ AstIfaceRefDType* pinIrefp = pinp->exprp()->castVarRef()->varp()->subDTypep()->castIfaceRefDType();
+ //UINFO(9," pinIfaceRef "<<pinIrefp<<endl);
+ if (portIrefp->ifaceViaCellp() != pinIrefp->ifaceViaCellp()) {
+ UINFO(9," IfaceRefDType needs reconnect "<<pinIrefp<<endl);
+ longname += "_" + paramSmallName(nodep->modp(),pinp->modVarp())+paramValueNumber(pinIrefp);
+ any_overrides = true;
+ ifaceRefRefs.push_back(make_pair(portIrefp,pinIrefp));
+ }
+ }
+ }
+ }
if (!any_overrides) {
UINFO(8,"Cell parameters all match original values, skipping expansion.\n");
@@ -402,7 +493,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Note we allow multiple users of a parameterized model, thus we need to stash this info.
for (AstNode* stmtp=modp->stmtsp(); stmtp; stmtp = stmtp->nextp()) {
if (AstVar* varp = stmtp->castVar()) {
- if (varp->isIO() || varp->isGParam()) {
+ if (varp->isIO() || varp->isGParam() || varp->isIfaceRef()) {
// Cloning saved a pointer to the new node for us, so just follow that link.
AstVar* oldvarp = varp->clonep()->castVar();
//UINFO(8,"Clone list 0x"<<hex<<(uint32_t)oldvarp<<" -> 0x"<<(uint32_t)varp<<endl);
@@ -414,7 +505,21 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
// Relink parameter vars to the new module
relinkPins(clonemapp, nodep->paramsp());
+ // Fix any interface references
+ for (IfaceRefRefs::iterator it=ifaceRefRefs.begin(); it!=ifaceRefRefs.end(); ++it) {
+ AstIfaceRefDType* portIrefp = it->first;
+ AstIfaceRefDType* pinIrefp = it->second;
+ AstIfaceRefDType* cloneIrefp = portIrefp->clonep()->castIfaceRefDType();
+ UINFO(8," IfaceOld "<<portIrefp<<endl);
+ UINFO(8," IfaceTo "<<pinIrefp<<endl);
+ if (!cloneIrefp) portIrefp->v3fatalSrc("parameter clone didn't hit AstIfaceRefDType");
+ UINFO(8," IfaceClo "<<cloneIrefp<<endl);
+ cloneIrefp->ifacep(pinIrefp->ifaceViaCellp());
+ UINFO(8," IfaceNew "<<cloneIrefp<<endl);
+ }
+
// Assign parameters to the constants specified
+ // DOES clone() so must be finished with module clonep() before here
for (AstPin* pinp = nodep->paramsp(); pinp; pinp=pinp->nextp()->castPin()) {
AstVar* modvarp = pinp->modVarp();
if (modvarp && pinp->exprp()) {
@@ -440,7 +545,7 @@ void ParamVisitor::visit(AstCell* nodep, AstNUser*) {
} // if any_overrides
// Delete the parameters from the cell; they're not relevant any longer.
- nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
+ if (nodep->paramsp()) nodep->paramsp()->unlinkFrBackWithNext()->deleteTree();
UINFO(8," Done with "<<nodep<<endl);
//if (debug()>=10) v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("param-out.tree"));
}
diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h
index fb3f661..479ed4f 100644
--- a/src/V3ParseImp.h
+++ b/src/V3ParseImp.h
@@ -66,6 +66,7 @@ struct V3ParseBisonYYSType {
AstCell* cellp;
AstConst* constp;
AstMemberDType* memberp;
+ AstModportVarRef* modportvarrefp;
AstNodeModule* modulep;
AstNodeClassDType* classp;
AstNodeDType* dtypep;
diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h
index bcb6245..12bcdb0 100644
--- a/src/V3ParseSym.h
+++ b/src/V3ParseSym.h
@@ -128,7 +128,7 @@ public:
}
// Walk old sym table and reinsert into current table
// We let V3LinkDot report the error instead of us
- symCurrentp()->import(&m_syms, symp, id_or_star);
+ symCurrentp()->importFromPackage(&m_syms, symp, id_or_star);
}
public:
// CREATORS
diff --git a/src/V3Scope.cpp b/src/V3Scope.cpp
index 827da0e..3385f98 100644
--- a/src/V3Scope.cpp
+++ b/src/V3Scope.cpp
@@ -150,6 +150,14 @@ private:
m_scopep->addActivep(clonep);
clonep->iterateChildren(*this); // We iterate under the *clone*
}
+ virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
+ // Copy under the scope but don't recurse
+ UINFO(4," Move "<<nodep<<endl);
+ AstNode* clonep = nodep->cloneTree(false);
+ nodep->user2p(clonep);
+ m_scopep->addActivep(clonep);
+ clonep->iterateChildren(*this); // We iterate under the *clone*
+ }
virtual void visit(AstAssignW* nodep, AstNUser*) {
// Add to list of blocks under this scope
UINFO(4," Move "<<nodep<<endl);
@@ -215,12 +223,17 @@ private:
virtual void visit(AstVarRef* nodep, AstNUser*) {
// VarRef needs to point to VarScope
// Make sure variable has made user1p.
- nodep->varp()->accept(*this);
- AstVarScope* varscp = nodep->packagep()
- ? (AstVarScope*)nodep->varp()->user3p()
- : (AstVarScope*)nodep->varp()->user1p();
- if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
- nodep->varScopep(varscp);
+ if (!nodep->varp()) nodep->v3fatalSrc("Unlinked");
+ if (nodep->varp()->isIfaceRef()) {
+ nodep->varScopep(NULL);
+ } else {
+ nodep->varp()->accept(*this);
+ AstVarScope* varscp = nodep->packagep()
+ ? (AstVarScope*)nodep->varp()->user3p()
+ : (AstVarScope*)nodep->varp()->user1p();
+ if (!varscp) nodep->v3fatalSrc("Can't locate varref scope");
+ nodep->varScopep(varscp);
+ }
}
virtual void visit(AstScopeName* nodep, AstNUser*) {
// If there's a %m in the display text, we add a special node that will contain the name()
@@ -298,6 +311,9 @@ private:
virtual void visit(AstAssignAlias* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
+ virtual void visit(AstAssignVarScope* nodep, AstNUser*) {
+ movedDeleteOrIterate(nodep);
+ }
virtual void visit(AstAssignW* nodep, AstNUser*) {
movedDeleteOrIterate(nodep);
}
diff --git a/src/V3SymTable.h b/src/V3SymTable.h
index 15a64e3..cef0ba1 100644
--- a/src/V3SymTable.h
+++ b/src/V3SymTable.h
@@ -137,11 +137,11 @@ public:
VSymEnt* findIdFlat(const string& name) const {
// Find identifier without looking upward through symbol hierarchy
// First, scan this begin/end block or module for the name
- IdNameMap::const_iterator iter = m_idNameMap.find(name);
+ IdNameMap::const_iterator it = m_idNameMap.find(name);
UINFO(9, " SymFind se"<<(void*)this<<" '"<<name
- <<"' -> "<<(iter == m_idNameMap.end() ? "NONE"
- : "se"+cvtToStr((void*)(iter->second))+" n="+cvtToStr((void*)(iter->second->nodep())))<<endl);
- if (iter != m_idNameMap.end()) return (iter->second);
+ <<"' -> "<<(it == m_idNameMap.end() ? "NONE"
+ : "se"+cvtToStr((void*)(it->second))+" n="+cvtToStr((void*)(it->second->nodep())))<<endl);
+ if (it != m_idNameMap.end()) return (it->second);
return NULL;
}
VSymEnt* findIdFallback(const string& name) const {
@@ -166,7 +166,7 @@ private:
}
}
public:
- bool import(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
+ bool importFromPackage(VSymGraph* graphp, const VSymEnt* srcp, const string& id_or_star) {
// Import tokens from source symbol table into this symbol table
// Returns true if successful
bool any = false;
@@ -183,6 +183,18 @@ public:
}
return any;
}
+ void importFromIface(VSymGraph* graphp, const VSymEnt* srcp) {
+ // Import interface tokens from source symbol table into this symbol table, recursively
+ UINFO(9, " importIf se"<<(void*)this<<" from se"<<(void*)srcp<<endl);
+ for (IdNameMap::const_iterator it=srcp->m_idNameMap.begin(); it!=srcp->m_idNameMap.end(); ++it) {
+ const string& name = it->first;
+ VSymEnt* srcp = it->second;
+ VSymEnt* symp = new VSymEnt(graphp, srcp);
+ reinsert(name, symp);
+ // And recurse to create children
+ srcp->importFromIface(graphp, symp);
+ }
+ }
void cellErrorScopes(AstNode* lookp, string prettyName="") {
if (prettyName=="") prettyName = lookp->prettyName();
string scopes;
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index 34a03d4..ca64a07 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -1073,6 +1073,14 @@ private:
nodep->dtypeFrom(nodep->lhsp());
}
+ virtual void visit(AstIfaceRefDType* nodep, AstNUser* vup) {
+ if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
+ UINFO(5," IFACEREF "<<nodep<<endl);
+ nodep->iterateChildren(*this, vup);
+ nodep->dtypep(nodep);
+ nodep->widthForce(1, 1); // Not really relevant
+ UINFO(4,"dtWidthed "<<nodep<<endl);
+ }
virtual void visit(AstNodeClassDType* nodep, AstNUser* vup) {
if (nodep->didWidthAndSet()) return; // This node is a dtype & not both PRELIMed+FINALed
UINFO(5," NODECLASS "<<nodep<<endl);
diff --git a/src/V3WidthSel.cpp b/src/V3WidthSel.cpp
index 5b7019b..3626aa4 100644
--- a/src/V3WidthSel.cpp
+++ b/src/V3WidthSel.cpp
@@ -307,13 +307,15 @@ private:
newp->dtypeFrom(adtypep);
} else {
// Need a slice data type, which is an array of the extracted type, but with (presumably) different size
+ VNumRange newRange (msb, lsb, fromRange.littleEndian());
AstNodeDType* vardtypep = new AstPackArrayDType(nodep->fileline(),
adtypep->subDTypep(), // Need to strip off array reference
- new AstRange(nodep->fileline(), fromRange));
+ new AstRange(nodep->fileline(), newRange));
v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
newp->dtypeFrom(vardtypep);
}
- if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
+ //if (debug()>=9) newp->dumpTree(cout,"--EXTBTn: ");
+ if (newp->widthMin()!=(int)newp->widthConst()) nodep->v3fatalSrc("Width mismatch");
nodep->replaceWith(newp); pushDeletep(nodep); nodep=NULL;
}
else if (ddtypep->castBasicDType()) {
diff --git a/src/Verilator.cpp b/src/Verilator.cpp
index b84e090..6fc8596 100644
--- a/src/Verilator.cpp
+++ b/src/Verilator.cpp
@@ -228,8 +228,7 @@ void process () {
if (!v3Global.opt.xmlOnly()) {
// Add top level wrapper with instance pointing to old top
// Move packages to under new top
- // Must do this after we know the width of any parameters
- // We also do it after coverage/assertion insertion so we don't 'cover' the top level.
+ // Must do this after we know parameters and dtypes (as don't clone dtype decls)
V3LinkLevel::wrapTop(v3Global.rootp());
}
@@ -677,7 +676,7 @@ int main(int argc, char** argv, char** env) {
}
// Final steps
- V3Global::dumpGlobalTree("final.tree",99);
+ V3Global::dumpGlobalTree("final.tree",990);
V3Error::abortIfWarnings();
if (!v3Global.opt.lintOnly() && !v3Global.opt.cdc()
diff --git a/src/config_build.h b/src/config_build.h
index 6e0a426..fb22c26 100644
--- a/src/config_build.h
+++ b/src/config_build.h
@@ -27,7 +27,7 @@
//**** Version and host name
// Autoconf substitutes this with the strings from AC_INIT.
-#define PACKAGE_STRING "Verilator 3.847 2013-05-11"
+#define PACKAGE_STRING "Verilator 3.850 2013-06-02"
#define DTVERSION PACKAGE_STRING
diff --git a/src/config_rev.h b/src/config_rev.h
index 89fc770..d4c04c3 100644
--- a/src/config_rev.h
+++ b/src/config_rev.h
@@ -1 +1 @@
-static const char* DTVERSION_rev = "verilator_3_846-14-g0abde90";
+static const char* DTVERSION_rev = "verilator_3_848-1-g7a65df7";
diff --git a/src/verilog.l b/src/verilog.l
index 04d296b..ac58f77 100644
--- a/src/verilog.l
+++ b/src/verilog.l
@@ -417,6 +417,7 @@ word [a-zA-Z0-9_]+
"do" { FL; return yDO; }
"endclocking" { FL; return yENDCLOCKING; }
"endpackage" { FL; return yENDPACKAGE; }
+ "endinterface" { FL; return yENDINTERFACE; }
"endprogram" { FL; return yENDPROGRAM; }
"endproperty" { FL; return yENDPROPERTY; }
"enum" { FL; return yENUM; }
@@ -425,9 +426,11 @@ word [a-zA-Z0-9_]+
"iff" { FL; return yIFF; }
"import" { FL; return yIMPORT; }
"inside" { FL; return yINSIDE; }
+ "interface" { FL; return yINTERFACE; }
"int" { FL; return yINT; }
"logic" { FL; return yLOGIC; }
"longint" { FL; return yLONGINT; }
+ "modport" { FL; return yMODPORT; }
"package" { FL; return yPACKAGE; }
"packed" { FL; return yPACKED; }
"priority" { FL; return yPRIORITY; }
@@ -460,7 +463,6 @@ word [a-zA-Z0-9_]+
"dist" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endclass" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endgroup" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
- "endinterface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"endsequence" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"expect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"extends" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -470,13 +472,11 @@ word [a-zA-Z0-9_]+
"forkjoin" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"ignore_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"illegal_bins" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
- "interface" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"intersect" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"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); }
"matches" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
- "modport" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"new" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"null" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
"protected" { yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
diff --git a/src/verilog.y b/src/verilog.y
index 2359a9a..ad0ab28 100644
--- a/src/verilog.y
+++ b/src/verilog.y
@@ -310,6 +310,7 @@ class AstSenTree;
%token<fl> yENDCLOCKING "endclocking"
%token<fl> yENDFUNCTION "endfunction"
%token<fl> yENDGENERATE "endgenerate"
+%token<fl> yENDINTERFACE "endinterface"
%token<fl> yENDMODULE "endmodule"
%token<fl> yENDPACKAGE "endpackage"
%token<fl> yENDPRIMITIVE "endprimitive"
@@ -337,9 +338,11 @@ class AstSenTree;
%token<fl> yINSIDE "inside"
%token<fl> yINT "int"
%token<fl> yINTEGER "integer"
+%token<fl> yINTERFACE "interface"
%token<fl> yLOCALPARAM "localparam"
%token<fl> yLOGIC "logic"
%token<fl> yLONGINT "longint"
+%token<fl> yMODPORT "modport"
%token<fl> yMODULE "module"
%token<fl> yNAND "nand"
%token<fl> yNEGEDGE "negedge"
@@ -650,7 +653,7 @@ descriptionList: // IEEE: part of source_text
description: // ==IEEE: description
module_declaration { }
// // udp_declaration moved into module_declaration
- //UNSUP interface_declaration { }
+ | interface_declaration { }
| program_declaration { }
| package_declaration { }
| package_item { if ($1) GRAMMARP->unitPackage($1->fileline())->addStmtp($1); }
@@ -844,14 +847,24 @@ port<nodep>: // ==IEEE: port
// // IEEE: interface_port_header port_identifier { unpacked_dimension }
// // Expanded interface_port_header
// // We use instantCb here because the non-port form looks just like a module instantiation
- //UNSUP portDirNetE id/*interface*/ idAny/*port*/ rangeListE sigAttrListE
- //UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PARSEP->instantCb($<fl>2, $2, $3, $4); PINNUMINC(); }
- //UNSUP portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
- //UNSUP { VARDTYPE($2); VARDONEA($<fl>3, $3, $4); PINNUMINC(); }
- //UNSUP portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
- //UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PARSEP->instantCb($<fl>2, $2, $5, $6); PINNUMINC(); }
- //UNSUP portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
- //UNSUP { VARDTYPE($2); VARDONEA($<fl>5, $5, $6); PINNUMINC(); }
+ portDirNetE id/*interface*/ idAny/*port*/ variable_dimensionListE sigAttrListE
+ { $$ = new AstPort($<fl>2,PINNUMINC(),*$3);
+ AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$3,VFlagChildDType(),
+ new AstIfaceRefDType($<fl>2,"",*$2));
+ if ($4) varp->v3error("Unsupported: Arrayed interfaces");
+ varp->addAttrsp($5);
+ $$->addNext(varp); }
+ | portDirNetE yINTERFACE idAny/*port*/ rangeListE sigAttrListE
+ { $<fl>2->v3error("Unsupported: virtual interfaces"); }
+ | portDirNetE id/*interface*/ '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
+ { $$ = new AstPort($3,PINNUMINC(),*$5);
+ AstVar* varp=new AstVar($<fl>2,AstVarType(AstVarType::IFACEREF),*$5,VFlagChildDType(),
+ new AstIfaceRefDType($<fl>2,"",*$2,*$4));
+ if ($6) varp->v3error("Unsupported: Arrayed interfaces");
+ varp->addAttrsp($7);
+ $$->addNext(varp); }
+ | portDirNetE yINTERFACE '.' idAny/*modport*/ idAny/*port*/ rangeListE sigAttrListE
+ { $<fl>2->v3error("Unsupported: virtual interfaces"); }
//
// // IEEE: ansi_port_declaration, with [port_direction] removed
// // IEEE: [ net_port_header | interface_port_header ] port_identifier { unpacked_dimension } [ '=' constant_expression ]
@@ -889,7 +902,7 @@ port<nodep>: // ==IEEE: port
//UNSUP portDirNetE /*implicit*/ '.' portSig '(' portAssignExprE ')' sigAttrListE
//UNSUP { UNSUP }
//
- portDirNetE data_type portSig variable_dimensionListE sigAttrListE
+ | portDirNetE data_type portSig variable_dimensionListE sigAttrListE
{ $$=$3; VARDTYPE($2); $$->addNextNull(VARDONEP($$,$4,$5)); }
| portDirNetE yVAR data_type portSig variable_dimensionListE sigAttrListE
{ $$=$4; VARDTYPE($3); $$->addNextNull(VARDONEP($$,$5,$6)); }
@@ -932,6 +945,54 @@ portSig<nodep>:
//**********************************************************************
// Interface headers
+interface_declaration: // IEEE: interface_declaration + interface_nonansi_header + interface_ansi_header:
+ // // timeunits_delcarationE is instead in interface_item
+ intFront parameter_port_listE portsStarE ';'
+ interface_itemListE yENDINTERFACE endLabelE
+ { if ($2) $1->addStmtp($2);
+ if ($3) $1->addStmtp($3);
+ if ($5) $1->addStmtp($5);
+ SYMP->popScope($1); }
+ //UNSUP yEXTERN intFront parameter_port_listE portsStarE ';' { }
+ ;
+
+intFront<modulep>:
+ yINTERFACE lifetimeE idAny/*new_interface*/
+ { $$ = new AstIface($1,*$3);
+ $$->inLibrary(true);
+ PARSEP->rootp()->addModulep($$);
+ SYMP->pushNew($$); }
+ ;
+
+interface_itemListE<nodep>:
+ /* empty */ { $$ = NULL; }
+ | interface_itemList { $$ = $1; }
+ ;
+
+interface_itemList<nodep>:
+ interface_item { $$ = $1; }
+ | interface_itemList interface_item { $$ = $1->addNextNull($2); }
+ ;
+
+interface_item<nodep>: // IEEE: interface_item + non_port_interface_item
+ port_declaration ';' { $$ = $1; }
+ // // IEEE: non_port_interface_item
+ //UNSUP generate_region { $$ = $1; }
+ | interface_or_generate_item { $$ = $1; }
+ //UNSUP program_declaration { $$ = $1; }
+ //UNSUP interface_declaration { $$ = $1; }
+ | timeunits_declaration { $$ = $1; }
+ // // See note in interface_or_generate item
+ | module_common_item { $$ = $1; }
+ ;
+
+interface_or_generate_item<nodep>: // ==IEEE: interface_or_generate_item
+ // // module_common_item in interface_item, as otherwise duplicated
+ // // with module_or_generate_item's module_common_item
+ modport_declaration { $$ = $1; }
+ //UNSUP extern_tf_declaration { $$ = $1; }
+ ;
+
//**********************************************************************
// Program headers
@@ -989,6 +1050,46 @@ program_generate_item<nodep>: // ==IEEE: program_generate_item
//UNSUP elaboration_system_task { $$ = $1; }
;
+modport_declaration<nodep>: // ==IEEE: modport_declaration
+ yMODPORT modport_itemList ';' { $$ = $2; }
+ ;
+
+modport_itemList<nodep>: // IEEE: part of modport_declaration
+ modport_item { $$ = $1; }
+ | modport_itemList ',' modport_item { $$ = $1->addNextNull($3); }
+ ;
+
+modport_item<nodep>: // ==IEEE: modport_item
+ id/*new-modport*/ '(' modportPortsDeclList ')' { $$ = new AstModport($2,*$1,$3); }
+ ;
+
+modportPortsDeclList<modportvarrefp>:
+ modportPortsDecl { $$ = $1; }
+ | modportPortsDeclList ',' modportPortsDecl { $$ = $1->addNextNull($3)->castModportVarRef(); }
+ ;
+
+// IEEE: modport_ports_declaration + modport_simple_ports_declaration
+// + (modport_tf_ports_declaration+import_export) + modport_clocking_declaration
+// We've expanded the lists each take to instead just have standalone ID ports.
+// We track the type as with the V2k series of defines, then create as each ID is seen.
+modportPortsDecl<modportvarrefp>:
+ // // IEEE: modport_simple_ports_declaration
+ port_direction modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$2,GRAMMARP->m_varIO); }
+ // // IEEE: modport_clocking_declaration
+ //UNSUP yCLOCKING idAny/*clocking_identifier*/ { }
+ //UNSUP yIMPORT modport_tf_port { }
+ //UNSUP yEXPORT modport_tf_port { }
+ // Continuations of above after a comma.
+ // // IEEE: modport_simple_ports_declaration
+ | modportSimplePort { $$ = new AstModportVarRef($<fl>1,*$1,AstVarType::INOUT); }
+ ;
+
+modportSimplePort<strp>: // IEEE: modport_simple_port or modport_tf_port, depending what keyword was earlier
+ id { $$ = $1; }
+ //UNSUP '.' idAny '(' ')' { }
+ //UNSUP '.' idAny '(' expr ')' { }
+ ;
+
//************************************************
// Variable Declarations
diff --git a/test_regress/driver.pl b/test_regress/driver.pl
index 2ba123b..3b9d364 100755
--- a/test_regress/driver.pl
+++ b/test_regress/driver.pl
@@ -861,30 +861,50 @@ sub _run {
print " > $param{logfile}" if $param{logfile};
print "\n";
- if ($param{logfile}) {
- open(SAVEOUT, ">&STDOUT") or die "%Error: Can't dup stdout";
- open(SAVEERR, ">&STDERR") or die "%Error: Can't dup stderr";
- if (0) {close(SAVEOUT); close(SAVEERR);} # Prevent unused warning
- if ($param{tee}) {
- open(STDOUT, "|tee $param{logfile}") or die "%Error: Can't redirect stdout";
- } else {
- open(STDOUT, ">$param{logfile}") or die "%Error: Can't open $param{logfile}";
+ # Execute command redirecting output, keeping order between stderr and stdout.
+ # Must do low-level IO so GCC interaction works (can't be line-based)
+ my $status;
+ {
+ pipe(PARENTRD, CHILDWR) or die "%Error: Can't Pipe, stopped";
+ autoflush PARENTRD 1;
+ autoflush CHILDWR 1;
+ my $logfh;
+ if ($param{logfile}) {
+ $logfh = IO::File->new(">$param{logfile}") or die "%Error: Can't open $param{logfile}";
+ }
+ my $pid=fork();
+ if ($pid) { # Parent
+ close CHILDWR;
+ while (1) {
+ my $buf = '';
+ my $got = sysread PARENTRD,$buf,10000;
+ last if defined $got && $got==0;
+ print $buf if $param{tee};
+ print $logfh $buf if $logfh;
+ }
+ close PARENTRD;
+ close $logfh if $logfh;
+ }
+ else { # Child
+ close PARENTRD;
+ close $logfh if $logfh;
+ # Reset signals
+ $SIG{ALRM} = 'DEFAULT';
+ $SIG{CHLD} = 'DEFAULT';
+ # Logging
+ open(STDOUT, ">&CHILDWR") or croak "%Error: Can't redirect stdout, stopped";
+ open(STDERR, ">&STDOUT") or croak "%Error: Can't dup stdout, stopped";
+ autoflush STDOUT 1;
+ autoflush STDERR 1;
+ system "$command";
+ exit ($? ? 10 : 0); # $?<<8 misses coredumps
}
- open(STDERR, ">&STDOUT") or die "%Error: Can't dup stdout";
- autoflush STDOUT 1;
- autoflush STDERR 1;
+ waitpid($pid,0);
+ $status = $? || 0;
}
-
- system "$command";
- my $status = $?;
flush STDOUT;
flush STDERR;
- if ($param{logfile}) {
- open (STDOUT, ">&SAVEOUT");
- open (STDERR, ">&SAVEERR");
- }
-
if (!$param{fails} && $status) {
$self->error("Exec of $param{cmd}[0] failed\n");
}
@@ -1277,14 +1297,23 @@ sub _read_inputs_v {
my $filename = $self->top_filename;
$filename = "$self->{t_dir}/$filename" if !-r $filename;
my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
+ my $get_sigs=1;
+ my %inputs;
while (defined(my $line = $fh->getline)) {
- if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
- $self->{inputs}{$1} = $1;
+ if ($get_sigs) {
+ if ($line =~ /^\s*input\s*(\S+)\s*(\/[^\/]+\/|)\s*;/) {
+ $inputs{$1} = $1;
+ }
+ if ($line =~ /^\s*(function|task|endmodule)/) {
+ $get_sigs = 0;
+ }
}
- if ($line =~ /^\s*(function|task|endmodule)/) {
- last;
+ if ($line =~ /^\s*module\s+t\b/) { # Ignore any earlier inputs; Module 't' has precedence
+ %inputs = ();
+ $get_sigs = 1;
}
}
+ $self->{inputs}{$_} = $inputs{$_} foreach keys %inputs;
$fh->close();
}
diff --git a/test_regress/t/t_dist_install.pl b/test_regress/t/t_dist_install.pl
index 729d32d..82f467d 100755
--- a/test_regress/t/t_dist_install.pl
+++ b/test_regress/t/t_dist_install.pl
@@ -38,10 +38,11 @@ if (!-r "$root/.git") {
# Check empty
my @files;
$finds = `find $destdir -type f -print`;
- foreach my $f (split /\n/, $finds) {
- print "\tLEFT: $f\n";
- $f =~ s!^$cwd!.!;
- push @files, $f;
+ foreach my $file (split /\n/, $finds) {
+ next if $file =~ /\.status/; # Made by driver.pl, not Verilator
+ print "\tLEFT: $file\n";
+ $file =~ s!^$cwd!.!;
+ push @files, $file;
}
if ($#files >= 0) {
$Self->error("Uninstall missed files: ",join(' ', at files));
diff --git a/test_regress/t/t_interface.pl b/test_regress/t/t_interface.pl
index 3bd8e9c..f912897 100755
--- a/test_regress/t/t_interface.pl
+++ b/test_regress/t/t_interface.pl
@@ -7,8 +7,6 @@ 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.
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
compile (
);
diff --git a/test_regress/t/t_interface.v b/test_regress/t/t_interface.v
index 8dd7d9d..1a9b8f0 100644
--- a/test_regress/t/t_interface.v
+++ b/test_regress/t/t_interface.v
@@ -100,7 +100,7 @@ interface handshake #(
// local logic (counter)
always @ (posedge clk, posedge rst)
if (rst) cnt <= '0;
- else cnt <= cnt + inc;
+ else cnt <= cnt + {31'h0, inc};
endinterface : handshake
@@ -129,7 +129,7 @@ module source #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
- else cnt <= cnt + (inf.req & inf.grt);
+ else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// request signal
assign inf.req = rnd[0];
@@ -161,7 +161,7 @@ module drain #(
// counter
always @ (posedge clk, posedge rst)
if (rst) cnt <= 32'd0;
- else cnt <= cnt + (inf.req & inf.grt);
+ else cnt <= cnt + {31'd0, (inf.req & inf.grt)};
// grant signal
assign inf.grt = rnd[0];
diff --git a/test_regress/t/t_interface1.pl b/test_regress/t/t_interface1.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface1.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface1.v b/test_regress/t/t_interface1.v
new file mode 100644
index 0000000..3b3f916
--- /dev/null
+++ b/test_regress/t/t_interface1.v
@@ -0,0 +1,45 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// Very simple test for interface pathclearing
+
+interface ifc;
+ logic [3:0] value;
+endinterface
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc itop();
+
+ sub c1 (.isub(itop),
+ .i_value(4'h4));
+
+ always @ (posedge clk) begin
+ cyc <= cyc + 1;
+ if (cyc==20) begin
+ if (c1.i_value != 4) $stop; // 'Normal' crossref just for comparison
+ if (itop.value != 4) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+module sub
+ (
+ ifc isub,
+ input logic [3:0] i_value
+ );
+
+ always @* begin
+ isub.value = i_value;
+ end
+endmodule : sub
diff --git a/test_regress/t/t_interface1_modport.pl b/test_regress/t/t_interface1_modport.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface1_modport.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface1_modport.v b/test_regress/t/t_interface1_modport.v
new file mode 100644
index 0000000..2d41333
--- /dev/null
+++ b/test_regress/t/t_interface1_modport.v
@@ -0,0 +1,48 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// Very simple test for interface pathclearing
+
+interface ifc;
+ integer hidden_from_isub;
+ integer value;
+ modport out_modport (output value);
+endinterface
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc itop();
+
+ sub c1 (.isub(itop),
+ .i_value(4));
+
+ always @ (posedge clk) begin
+ cyc <= cyc + 1;
+ if (cyc==20) begin
+ if (itop.value != 4) $stop;
+ itop.hidden_from_isub = 20;
+ if (itop.hidden_from_isub != 20) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+module sub
+ (
+ ifc.out_modport isub,
+ input integer i_value
+ );
+
+ always @* begin
+ isub.value = i_value;
+ end
+endmodule
diff --git a/test_regress/t/t_interface2.pl b/test_regress/t/t_interface2.pl
index 555a5a4..7ae28e6 100755
--- a/test_regress/t/t_interface2.pl
+++ b/test_regress/t/t_interface2.pl
@@ -7,10 +7,8 @@ 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.
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
compile (
- v_flags => []
+ verilator_flags2 => ["--top-module t"],
);
execute (
diff --git a/test_regress/t/t_interface2.v b/test_regress/t/t_interface2.v
index c6c48d4..efe2611 100644
--- a/test_regress/t/t_interface2.v
+++ b/test_regress/t/t_interface2.v
@@ -3,11 +3,6 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
-interface counter_io;
- logic [3:0] value;
- logic reset;
-endinterface
-
module t (/*AUTOARG*/
// Inputs
clk
@@ -18,17 +13,24 @@ module t (/*AUTOARG*/
counter_io c1_data();
counter_io c2_data();
+ //counter_io c3_data; // IEEE illegal, and VCS doesn't allow non-() as it does with cells
+ counter_io c3_data();
- counter c1 (.clkm(clk),
- .c_data(c1_data),
- .i_value(4'h1));
- counter2 c2 (.clkm(clk),
- .c_data(c2_data),
- .i_value(4'h2));
+ counter_ansi c1 (.clkm(clk),
+ .c_data(c1_data),
+ .i_value(4'h1));
+ counter_ansi c2 (.clkm(clk),
+ .c_data(c2_data),
+ .i_value(4'h2));
+`ifdef VERILATOR counter_ansi `else counter_nansi `endif
+ /**/ c3 (.clkm(clk),
+ .c_data(c3_data),
+ .i_value(4'h3));
initial begin
c1_data.value = 4'h4;
c2_data.value = 4'h5;
+ c3_data.value = 4'h6;
end
always @ (posedge clk) begin
@@ -36,46 +38,71 @@ module t (/*AUTOARG*/
if (cyc<2) begin
c1_data.reset <= 1;
c2_data.reset <= 1;
+ c3_data.reset <= 1;
end
if (cyc==2) begin
c1_data.reset <= 0;
c2_data.reset <= 0;
+ c3_data.reset <= 0;
+ end
+ if (cyc==3) begin
+ if (c1_data.get_lcl() != 12345) $stop;
end
if (cyc==20) begin
- $write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
- $write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
+ $write("[%0t] c1 cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x\n", $time, cyc,
+ c1_data.value, c1_data.reset,
+ c2_data.value, c2_data.reset,
+ c3_data.value, c3_data.reset);
if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop;
+ if (c3_data.value != 4) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
-module counter
+interface counter_io;
+ logic [3:0] value;
+ logic reset;
+ integer lcl;
+ task set_lcl (input integer a); lcl=a; endtask
+ function integer get_lcl (); return lcl; endfunction
+endinterface
+
+interface ifunused;
+ logic unused;
+endinterface
+
+module counter_ansi
(
input clkm,
counter_io c_data,
input logic [3:0] i_value
);
+ initial begin
+ c_data.set_lcl(12345);
+ end
+
always @ (posedge clkm) begin
- if (c_data.reset)
- c_data.value <= i_value;
- else
- c_data.value <= c_data.value + 1;
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
-endmodule : counter
+endmodule : counter_ansi
-module counter2(clkm, c_data, i_value);
+`ifndef VERILATOR
+// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
+module counter_nansi(clkm, c_data, i_value);
input clkm;
counter_io c_data;
input logic [3:0] i_value;
always @ (posedge clkm) begin
- if (c_data.reset)
- c_data.value <= i_value;
- else
- c_data.value <= c_data.value + 1;
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
-endmodule : counter2
+endmodule : counter_nansi
+`endif
+
+module modunused (ifunused ifinunused);
+ ifunused ifunused();
+endmodule
diff --git a/test_regress/t/t_interface_down.pl b/test_regress/t/t_interface_down.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface_down.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down.v b/test_regress/t/t_interface_down.v
new file mode 100644
index 0000000..bec0b2d
--- /dev/null
+++ b/test_regress/t/t_interface_down.v
@@ -0,0 +1,72 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+interface ifc;
+ integer value;
+endinterface
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+`ifdef INLINE_A //verilator inline_module
+`else //verilator no_inline_module
+`endif
+ input clk;
+ integer cyc=1;
+
+ ifc itop1a();
+ ifc itop1b();
+ ifc itop2a();
+ ifc itop2b();
+
+ wrapper c1 (.isuba(itop1a),
+ .isubb(itop1b),
+ .i_valuea(14),
+ .i_valueb(15));
+ wrapper c2 (.isuba(itop2a),
+ .isubb(itop2b),
+ .i_valuea(24),
+ .i_valueb(25));
+
+ always @ (posedge clk) begin
+ cyc <= cyc + 1;
+ if (cyc==20) begin
+ if (itop1a.value != 14) $stop;
+ if (itop1b.value != 15) $stop;
+ if (itop2a.value != 24) $stop;
+ if (itop2b.value != 25) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+module wrapper
+ (
+ ifc isuba,
+ ifc isubb,
+ input integer i_valuea,
+ input integer i_valueb
+ );
+`ifdef INLINE_B //verilator inline_module
+`else //verilator no_inline_module
+`endif
+ lower subsuba (.isub(isuba), .i_value(i_valuea));
+ lower subsubb (.isub(isubb), .i_value(i_valueb));
+endmodule
+
+module lower
+ (
+ ifc isub,
+ input integer i_value
+ );
+`ifdef INLINE_C //verilator inline_module
+`else //verilator no_inline_module
+`endif
+ always @* begin
+ isub.value = i_value;
+ end
+endmodule
diff --git a/test_regress/t/t_interface_down_gen.pl b/test_regress/t/t_interface_down_gen.pl
new file mode 100755
index 0000000..c9f69ed
--- /dev/null
+++ b/test_regress/t/t_interface_down_gen.pl
@@ -0,0 +1,21 @@
+#!/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.
+
+$Self->{vlt} and $Self->unsupported("Verilator unsupported, interface generates changing types");
+$Self->{vcs} and $Self->unsupported("Commercially unsupported, interface crossrefs");
+
+compile (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_gen.v b/test_regress/t/t_interface_down_gen.v
new file mode 100644
index 0000000..31117d3
--- /dev/null
+++ b/test_regress/t/t_interface_down_gen.v
@@ -0,0 +1,78 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// This test demonstrates how not only parameters but the type of a parent
+// interface could propagate down to child modules, changing their data type
+// determinations. Note presently unsupported in all commercial simulators.
+
+interface ifc;
+ parameter MODE = 0;
+ generate
+ // Note block must be named per SystemVerilog 2005
+ if (MODE==1) begin : g
+ integer value;
+ end
+ else if (MODE==2) begin : g
+ real value;
+ end
+ endgenerate
+endinterface
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc #(1) itop1a();
+ ifc #(1) itop1b();
+ ifc #(2) itop2a();
+ ifc #(2) itop2b();
+
+ wrapper c1 (.isuba(itop1a),
+ .isubb(itop1b),
+ .i_valuea(14.1),
+ .i_valueb(15.2));
+ wrapper c2 (.isuba(itop2a),
+ .isubb(itop2b),
+ .i_valuea(24.3),
+ .i_valueb(25.4));
+
+ always @ (posedge clk) begin
+ cyc <= cyc + 1;
+ if (cyc==20) begin
+ if (itop1a.g.value != 14) $stop;
+ if (itop1b.g.value != 15) $stop;
+ if (itop2a.g.value != 24) $stop;
+ if (itop2b.g.value != 25) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+module wrapper
+ (
+ ifc isuba,
+ ifc isubb,
+ input real i_valuea,
+ input real i_valueb
+ );
+ lower subsuba (.isub(isuba), .i_value(i_valuea));
+ lower subsubb (.isub(isubb), .i_value(i_valueb));
+endmodule
+
+module lower
+ (
+ ifc isub,
+ input real i_value
+ );
+ always @* begin
+`error Commercial sims choke on cross ref here
+ isub.g.value = i_value;
+ end
+endmodule
diff --git a/test_regress/t/t_interface_down_inla.pl b/test_regress/t/t_interface_down_inla.pl
new file mode 100755
index 0000000..f65c1e7
--- /dev/null
+++ b/test_regress/t/t_interface_down_inla.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_A'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlab.pl b/test_regress/t/t_interface_down_inlab.pl
new file mode 100755
index 0000000..f061604
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlab.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_A +define+INLINE_B'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlac.pl b/test_regress/t/t_interface_down_inlac.pl
new file mode 100755
index 0000000..6aae824
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlac.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_A +define+INLINE_C'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlad.pl b/test_regress/t/t_interface_down_inlad.pl
new file mode 100755
index 0000000..0addbdf
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlad.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_A +define+INLINE_D'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlb.pl b/test_regress/t/t_interface_down_inlb.pl
new file mode 100755
index 0000000..b8e22f2
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlb.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_B'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlbc.pl b/test_regress/t/t_interface_down_inlbc.pl
new file mode 100755
index 0000000..53d0090
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlbc.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_B +define+INLINE_C'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlbd.pl b/test_regress/t/t_interface_down_inlbd.pl
new file mode 100755
index 0000000..bdbf339
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlbd.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_B +define+INLINE_D'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlc.pl b/test_regress/t/t_interface_down_inlc.pl
new file mode 100755
index 0000000..f8ffc15
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlc.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_C'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inlcd.pl b/test_regress/t/t_interface_down_inlcd.pl
new file mode 100755
index 0000000..eb9218e
--- /dev/null
+++ b/test_regress/t/t_interface_down_inlcd.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_C +define+INLINE_D'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_down_inld.pl b/test_regress/t/t_interface_down_inld.pl
new file mode 100755
index 0000000..c57e458
--- /dev/null
+++ b/test_regress/t/t_interface_down_inld.pl
@@ -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 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.
+
+top_filename("t/t_interface_down.v");
+
+compile (
+ v_flags2 => ['+define+INLINE_D'],
+ verilator_flags2 => ['-trace'],
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_gen.pl b/test_regress/t/t_interface_gen.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface_gen.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_gen.v b/test_regress/t/t_interface_gen.v
new file mode 100644
index 0000000..37f0dc2
--- /dev/null
+++ b/test_regress/t/t_interface_gen.v
@@ -0,0 +1,87 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// Very simple test for interface pathclearing
+
+`ifdef VCS
+ `define UNSUPPORTED_MOD_IN_GENS
+`endif
+`ifdef VERILATOR
+ `define UNSUPPORTED_MOD_IN_GENS
+`endif
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc #(1) itopa();
+ ifc #(2) itopb();
+
+ sub #(1) ca (.isub(itopa),
+ .i_value(4));
+ sub #(2) cb (.isub(itopb),
+ .i_value(5));
+
+ always @ (posedge clk) begin
+ cyc <= cyc + 1;
+ if (cyc==1) begin
+ if (itopa.MODE != 1) $stop;
+ if (itopb.MODE != 2) $stop;
+ end
+ if (cyc==20) begin
+ if (itopa.get_value() != 4) $stop;
+ if (itopb.get_value() != 5) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+module sub
+ #(parameter MODE = 0)
+ (
+ ifc.out_modport isub,
+ input integer i_value
+ );
+
+`ifdef UNSUPPORTED_MOD_IN_GENS
+ always @* isub.value = i_value;
+`else
+ generate if (MODE == 1) begin
+ always @* isub.valuea = i_value;
+ end
+ else if (MODE == 2) begin
+ always @* isub.valueb = i_value;
+ end
+ endgenerate
+`endif
+
+endmodule
+
+interface ifc;
+ parameter MODE = 0;
+ // Modports under generates not supported by all commercial simulators
+`ifdef UNSUPPORTED_MOD_IN_GENS
+ integer value;
+ modport out_modport (output value);
+ function integer get_value(); return value; endfunction
+`else
+ generate if (MODE == 0) begin
+ integer valuea;
+ modport out_modport (output valuea);
+ function integer get_valuea(); return valuea; endfunction
+ end
+ else begin
+ integer valueb;
+ modport out_modport (output valueb);
+ function integer get_valueb(); return valueb; endfunction
+ end
+ endgenerate
+`endif
+endinterface
diff --git a/test_regress/t/t_interface_gen2.pl b/test_regress/t/t_interface_gen2.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface_gen2.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_gen2.v b/test_regress/t/t_interface_gen2.v
new file mode 100644
index 0000000..13f0acb
--- /dev/null
+++ b/test_regress/t/t_interface_gen2.v
@@ -0,0 +1,70 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// Very simple test for interface pathclearing
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc #(2) itopa();
+ ifc #(4) itopb();
+
+ sub ca (.isub(itopa),
+ .clk);
+ sub cb (.isub(itopb),
+ .clk);
+
+ always @ (posedge clk) begin
+`ifdef TEST_VERBOSE
+ $write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
+`endif
+ cyc <= cyc + 1;
+ itopa.valuei <= cyc[1:0];
+ itopb.valuei <= cyc[3:0];
+ if (cyc==1) begin
+ if (itopa.WIDTH != 2) $stop;
+ if (itopb.WIDTH != 4) $stop;
+ if ($bits(itopa.valueo) != 2) $stop;
+ if ($bits(itopb.valueo) != 4) $stop;
+ if ($bits(itopa.out_modport.valueo) != 2) $stop;
+ if ($bits(itopb.out_modport.valueo) != 4) $stop;
+ end
+ if (cyc==4) begin
+ if (itopa.valueo != 2'b11) $stop;
+ if (itopb.valueo != 4'b0011) $stop;
+ end
+ if (cyc==5) begin
+ if (itopa.valueo != 2'b00) $stop;
+ if (itopb.valueo != 4'b0100) $stop;
+ end
+ if (cyc==20) begin
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+interface ifc
+ #(parameter WIDTH = 1);
+ // verilator lint_off MULTIDRIVEN
+ logic [WIDTH-1:0] valuei;
+ logic [WIDTH-1:0] valueo;
+ // verilator lint_on MULTIDRIVEN
+ modport out_modport (input valuei, output valueo);
+endinterface
+
+// Note not parameterized
+module sub
+ (
+ ifc.out_modport isub,
+ input clk
+ );
+ always @(posedge clk) isub.valueo <= isub.valuei + 1;
+endmodule
diff --git a/test_regress/t/t_interface_gen3.pl b/test_regress/t/t_interface_gen3.pl
new file mode 100755
index 0000000..1118f2e
--- /dev/null
+++ b/test_regress/t/t_interface_gen3.pl
@@ -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-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 (
+ );
+
+execute (
+ check_finished=>1,
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_gen3.v b/test_regress/t/t_interface_gen3.v
new file mode 100644
index 0000000..e3c107c
--- /dev/null
+++ b/test_regress/t/t_interface_gen3.v
@@ -0,0 +1,70 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// Very simple test for interface pathclearing
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc #(2) itopa();
+ ifc #(4) itopb();
+
+ sub ca (.isub(itopa.out_modport),
+ .clk);
+ sub cb (.isub(itopb.out_modport),
+ .clk);
+
+ always @ (posedge clk) begin
+`ifdef TEST_VERBOSE
+ $write("[%0t] cyc==%0d result=%b %b\n",$time, cyc, itopa.valueo, itopb.valueo);
+`endif
+ cyc <= cyc + 1;
+ itopa.valuei <= cyc[1:0];
+ itopb.valuei <= cyc[3:0];
+ if (cyc==1) begin
+ if (itopa.WIDTH != 2) $stop;
+ if (itopb.WIDTH != 4) $stop;
+ if ($bits(itopa.valueo) != 2) $stop;
+ if ($bits(itopb.valueo) != 4) $stop;
+ if ($bits(itopa.out_modport.valueo) != 2) $stop;
+ if ($bits(itopb.out_modport.valueo) != 4) $stop;
+ end
+ if (cyc==4) begin
+ if (itopa.valueo != 2'b11) $stop;
+ if (itopb.valueo != 4'b0011) $stop;
+ end
+ if (cyc==5) begin
+ if (itopa.valueo != 2'b00) $stop;
+ if (itopb.valueo != 4'b0100) $stop;
+ end
+ if (cyc==20) begin
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+endmodule
+
+interface ifc
+ #(parameter WIDTH = 1);
+ // verilator lint_off MULTIDRIVEN
+ logic [WIDTH-1:0] valuei;
+ logic [WIDTH-1:0] valueo;
+ // verilator lint_on MULTIDRIVEN
+ modport out_modport (input valuei, output valueo);
+endinterface
+
+// Note not parameterized
+module sub
+ (
+ ifc.out_modport isub,
+ input clk
+ );
+ always @(posedge clk) isub.valueo <= isub.valuei + 1;
+endmodule
diff --git a/test_regress/t/t_interface_inl.pl b/test_regress/t/t_interface_inl.pl
index 860bef4..ef9d007 100755
--- a/test_regress/t/t_interface_inl.pl
+++ b/test_regress/t/t_interface_inl.pl
@@ -7,13 +7,11 @@ 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.
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
top_filename("t/t_interface.v");
compile (
# Avoid inlining so we find bugs in the non-inliner connection code
- v_flags => ["-Oi"],
+ verilator_flags2 => ["-Oi"],
);
execute (
diff --git a/test_regress/t/t_interface_mismodport_bad.pl b/test_regress/t/t_interface_mismodport_bad.pl
new file mode 100755
index 0000000..3ff2dbd
--- /dev/null
+++ b/test_regress/t/t_interface_mismodport_bad.pl
@@ -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 by Wilson Snyder. This program is free software; you can
+# redistribute it and/or modify it under the terms of either the GNU
+# Lesser General Public License Version 3 or the Perl Artistic License
+# Version 2.0.
+
+compile (
+ verilator_flags2 => ["--lint-only"],
+ verilator_make_gcc => 0,
+ make_top_shell => 0,
+ make_main => 0,
+ fails => 1,
+ expect=>
+'%Error: t/t_interface_mismodport_bad.v:\d+: Can\'t find definition of \'bad\' in dotted signal: isub.bad
+.*%Error: Exiting due to.*',
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_mismodport_bad.v b/test_regress/t/t_interface_mismodport_bad.v
new file mode 100644
index 0000000..ad8aa2a
--- /dev/null
+++ b/test_regress/t/t_interface_mismodport_bad.v
@@ -0,0 +1,37 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+interface ifc;
+ integer ok;
+ integer bad;
+ modport out_modport (output ok);
+endinterface
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+
+ input clk;
+ integer cyc=1;
+
+ ifc itop();
+
+ counter_ansi c1 (.isub(itop),
+ .i_value(4'h4));
+
+endmodule
+
+module counter_ansi
+ (
+ ifc.out_modport isub,
+ input logic [3:0] i_value
+ );
+
+ always @* begin
+ isub.ok = i_value;
+ isub.bad = i_value; // Illegal access
+ end
+endmodule
diff --git a/test_regress/t/t_interface_modport.pl b/test_regress/t/t_interface_modport.pl
index d39b00a..1118f2e 100755
--- a/test_regress/t/t_interface_modport.pl
+++ b/test_regress/t/t_interface_modport.pl
@@ -7,10 +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.
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
compile (
- v_flags => [],
);
execute (
diff --git a/test_regress/t/t_interface_modport.v b/test_regress/t/t_interface_modport.v
index b1479e2..9544463 100644
--- a/test_regress/t/t_interface_modport.v
+++ b/test_regress/t/t_interface_modport.v
@@ -3,13 +3,26 @@
// This file ONLY is placed into the Public Domain, for any use,
// without warranty, 2010 by Wilson Snyder.
-interface counter_io;
+interface counter_if;
logic [3:0] value;
logic reset;
- modport counter_side (input reset, output value);
- modport core_side (output reset, input value);
+ modport counter_mp (input reset, output value);
+ modport core_mp (output reset, input value);
endinterface
+// Check can have inst module before top module
+module counter_ansi
+ (
+ input clkm,
+ counter_if c_data,
+ input logic [3:0] i_value
+ );
+
+ always @ (posedge clkm) begin
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
+ end
+endmodule : counter_ansi
+
module t (/*AUTOARG*/
// Inputs
clk
@@ -18,19 +31,31 @@ module t (/*AUTOARG*/
input clk;
integer cyc=1;
- counter_io c1_data();
- counter_io c2_data();
+ counter_if c1_data();
+ counter_if c2_data();
+ counter_if c3_data();
+ counter_if c4_data();
- counter c1 (.clkm(clk),
- .c_data(c1_data),
- .i_value(4'h1));
- counter c2 (.clkm(clk),
- .c_data(c2_data.counter_side),
- .i_value(4'h2));
+ counter_ansi c1 (.clkm(clk),
+ .c_data(c1_data.counter_mp),
+ .i_value(4'h1));
+`ifdef VERILATOR counter_ansi `else counter_nansi `endif
+ /**/ c2 (.clkm(clk),
+ .c_data(c2_data.counter_mp),
+ .i_value(4'h2));
+ counter_ansi_m c3 (.clkm(clk),
+ .c_data(c3_data),
+ .i_value(4'h3));
+`ifdef VERILATOR counter_ansi_m `else counter_nansi_m `endif
+ /**/ c4 (.clkm(clk),
+ .c_data(c4_data),
+ .i_value(4'h4));
initial begin
c1_data.value = 4'h4;
c2_data.value = 4'h5;
+ c3_data.value = 4'h6;
+ c4_data.value = 4'h7;
end
always @ (posedge clk) begin
@@ -38,33 +63,69 @@ module t (/*AUTOARG*/
if (cyc<2) begin
c1_data.reset <= 1;
c2_data.reset <= 1;
+ c3_data.reset <= 1;
+ c4_data.reset <= 1;
end
if (cyc==2) begin
c1_data.reset <= 0;
c2_data.reset <= 0;
+ c3_data.reset <= 0;
+ c4_data.reset <= 0;
end
if (cyc==20) begin
- $write("[%0t] c1 cyc%0d: %0x %0x\n", $time, cyc, c1_data.value, c1_data.reset);
- $write("[%0t] c2 cyc%0d: %0x %0x\n", $time, cyc, c2_data.value, c2_data.reset);
+ $write("[%0t] cyc%0d: c1 %0x %0x c2 %0x %0x c3 %0x %0x c4 %0x %0x\n", $time, cyc,
+ c1_data.value, c1_data.reset,
+ c2_data.value, c2_data.reset,
+ c3_data.value, c3_data.reset,
+ c4_data.value, c4_data.reset);
if (c1_data.value != 2) $stop;
if (c2_data.value != 3) $stop;
+ if (c3_data.value != 4) $stop;
+ if (c4_data.value != 5) $stop;
$write("*-* All Finished *-*\n");
$finish;
end
end
endmodule
-module counter
+`ifndef VERILATOR
+// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
+module counter_nansi
+ (clkm, c_data, i_value);
+
+ input clkm;
+ counter_if c_data;
+ input logic [3:0] i_value;
+
+ always @ (posedge clkm) begin
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
+ end
+endmodule : counter_nansi
+`endif
+
+module counter_ansi_m
(
input clkm,
- counter_io c_data,
+ counter_if.counter_mp c_data,
input logic [3:0] i_value
);
always @ (posedge clkm) begin
- if (c_data.reset)
- c_data.value <= i_value;
- else
- c_data.value <= c_data.value + 1;
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
+ end
+endmodule : counter_ansi_m
+
+`ifndef VERILATOR
+// non-ansi modports not seen in the wild yet. Verilog-Perl needs parser improvement too.
+module counter_nansi_m
+ (clkm, c_data, i_value);
+
+ input clkm;
+ counter_if.counter_mp c_data;
+ input logic [3:0] i_value;
+
+ always @ (posedge clkm) begin
+ c_data.value <= c_data.reset ? i_value : c_data.value + 1;
end
-endmodule : counter
+endmodule : counter_nansi_m
+`endif
diff --git a/test_regress/t/t_interface_modport_inl.pl b/test_regress/t/t_interface_modport_inl.pl
index 37f6499..57289df 100755
--- a/test_regress/t/t_interface_modport_inl.pl
+++ b/test_regress/t/t_interface_modport_inl.pl
@@ -7,13 +7,11 @@ 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.
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
top_filename("t/t_interface_modport.v");
compile (
# Avoid inlining so we find bugs in the non-inliner connection code
- v_flags => ["-Oi"],
+ verilator_flags2 => ["-Oi"],
);
execute (
diff --git a/test_regress/t/t_interface_top.pl b/test_regress/t/t_interface_top.pl
deleted file mode 100755
index 1a62ab7..0000000
--- a/test_regress/t/t_interface_top.pl
+++ /dev/null
@@ -1,17 +0,0 @@
-#!/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.
-
-$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug102");
-
-compile (
- verilator_flags2 => ["--lint-only"]
- );
-
-ok(1);
-1;
diff --git a/test_regress/t/t_interface_top.v b/test_regress/t/t_interface_top.v
deleted file mode 100644
index d2aaccc..0000000
--- a/test_regress/t/t_interface_top.v
+++ /dev/null
@@ -1,21 +0,0 @@
-// DESCRIPTION: Verilator: Verilog Test module
-//
-// This file ONLY is placed into the Public Domain, for any use,
-// without warranty, 2010 by Wilson Snyder.
-
-interface counter_io;
- logic [3:0] value;
- logic reset;
- modport counter_side (input reset, output value);
- modport core_side (output reset, input value);
-endinterface
-
-module t
- (// Inputs
- input clk,
- counter_io.counter_side c_data
- );
-
- integer cyc=1;
-
-endmodule
diff --git a/test_regress/t/t_interface_top_bad.pl b/test_regress/t/t_interface_top_bad.pl
new file mode 100755
index 0000000..34abb76
--- /dev/null
+++ b/test_regress/t/t_interface_top_bad.pl
@@ -0,0 +1,21 @@
+#!/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 (
+ verilator_flags2 => ["--lint-only"],
+ verilator_make_gcc => 0,
+ make_top_shell => 0,
+ make_main => 0,
+ fails => 1,
+ expect=>
+'%Error: t/t_interface_top_bad.v:\d+: Unsupported: Interfaced port on top level module',
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_interface_top_bad.v b/test_regress/t/t_interface_top_bad.v
new file mode 100644
index 0000000..2334789
--- /dev/null
+++ b/test_regress/t/t_interface_top_bad.v
@@ -0,0 +1,21 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2010 by Wilson Snyder.
+
+interface ifc;
+ logic [3:0] value;
+ logic reset;
+ modport counter_mp (input reset, output value);
+ modport core_mp (output reset, input value);
+endinterface
+
+module t
+ (// Inputs
+ input clk,
+ ifc.counter_mp c_data
+ );
+
+ integer cyc=1;
+
+endmodule
diff --git a/test_regress/t/t_lint_implicit_port.pl b/test_regress/t/t_lint_implicit_port.pl
index bd5d46c..a3f2995 100755
--- a/test_regress/t/t_lint_implicit_port.pl
+++ b/test_regress/t/t_lint_implicit_port.pl
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
$Self->{vlt} or $Self->skip("Verilator only test");
compile (
- v_flags => ["-Wno-IMPLICIT"],
+ v_flags2 => ["-Wno-IMPLICIT"],
);
ok(1);
diff --git a/test_regress/t/t_lint_only.pl b/test_regress/t/t_lint_only.pl
index e0fb17b..140f40c 100755
--- a/test_regress/t/t_lint_only.pl
+++ b/test_regress/t/t_lint_only.pl
@@ -18,6 +18,7 @@ compile (
foreach my $file (glob("$Self->{obj_dir}/*t_lint_only*")) {
next if $file =~ /simx_compile.log/; # Made by driver.pl, not Verilator
+ next if $file =~ /\.status/; # Made by driver.pl, not Verilator
$Self->error("%Error: Created $file, but --lint-only shouldn't create files");
}
diff --git a/test_regress/t/t_EXAMPLE.pl b/test_regress/t/t_math_pick.pl
similarity index 100%
copy from test_regress/t/t_EXAMPLE.pl
copy to test_regress/t/t_math_pick.pl
diff --git a/test_regress/t/t_math_pick.v b/test_regress/t/t_math_pick.v
new file mode 100644
index 0000000..1e865f8
--- /dev/null
+++ b/test_regress/t/t_math_pick.v
@@ -0,0 +1,82 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013.
+
+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 pick1 = crc[0];
+ wire [13:0][1:0] data1 = crc[27+1:1];
+ wire [3:0][2:0][1:0] data2 = crc[23+29:29];
+
+ /*AUTOWIRE*/
+ // Beginning of automatic wires (for undeclared instantiated-module outputs)
+ logic [15:0] [1:0] datao; // From test of Test.v
+ // End of automatics
+
+ Test test (/*AUTOINST*/
+ // Outputs
+ .datao (datao/*[15:0][1:0]*/),
+ // Inputs
+ .pick1 (pick1),
+ .data1 (data1/*[13:0][1:0]*/),
+ .data2 (data2/*[2:0][3:0][1:0]*/));
+
+ // Aggregate outputs into a single result vector
+ wire [63:0] result = {32'h0, datao};
+
+ // 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'h3ff4bf0e6407b281
+ if (sum !== `EXPECTED_SUM) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+
+endmodule
+
+module Test
+ (
+ input logic pick1,
+ input logic [13:0] [1:0] data1, // 14 x 2 = 28 bits
+ input logic [ 3:0] [2:0] [1:0] data2, // 4 x 3 x 2 = 24 bits
+ output logic [15:0] [1:0] datao // 16 x 2 = 32 bits
+ );
+ // verilator lint_off WIDTH
+ always_comb datao[13: 0] // 28 bits
+ = (pick1)
+ ? {data1} // 28 bits
+ : {'0, data2}; // 25-28 bits, perhaps not legal as '0 is unsized
+ // verilator lint_on WIDTH
+ always_comb datao[15:14] = '0;
+endmodule
diff --git a/test_regress/t/t_mem_multi_io2_cc.pl b/test_regress/t/t_mem_multi_io2_cc.pl
index 7433eb8..c5708fb 100755
--- a/test_regress/t/t_mem_multi_io2_cc.pl
+++ b/test_regress/t/t_mem_multi_io2_cc.pl
@@ -14,7 +14,7 @@ $Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
- verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp"],
+ verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp -Oi"],
);
execute (
diff --git a/test_regress/t/t_mem_multi_io2_sc.pl b/test_regress/t/t_mem_multi_io2_sc.pl
index a2693e6..24a2f0b 100755
--- a/test_regress/t/t_mem_multi_io2_sc.pl
+++ b/test_regress/t/t_mem_multi_io2_sc.pl
@@ -14,7 +14,7 @@ $Self->{vlt} or $Self->skip("Verilator only test");
compile (
make_top_shell => 0,
make_main => 0,
- verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc"],
+ verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io2.cpp --sc -Oi"],
);
execute (
diff --git a/test_regress/t/t_mem_multi_io3.cpp b/test_regress/t/t_mem_multi_io3.cpp
new file mode 100644
index 0000000..8f001d8
--- /dev/null
+++ b/test_regress/t/t_mem_multi_io3.cpp
@@ -0,0 +1,34 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty.
+
+#if defined(T_MEM_MULTI_IO3_CC)
+# include "Vt_mem_multi_io3_cc.h"
+#elif defined(T_MEM_MULTI_IO3_SC)
+# include "Vt_mem_multi_io3_sc.h"
+#else
+# error "Unknown test"
+#endif
+
+VM_PREFIX* tb = NULL;
+bool pass = true;
+
+double sc_time_stamp() {
+ return 0;
+}
+
+int main() {
+ Verilated::debug(0);
+ tb = new VM_PREFIX ("tb");
+
+ // Just a constructor test
+ bool pass = true;
+
+ if (pass) {
+ VL_PRINTF("*-* All Finished *-*\n");
+ } else {
+ vl_fatal(__FILE__,__LINE__,"top", "Unexpected results from test\n");
+ }
+ return 0;
+}
diff --git a/test_regress/t/t_mem_multi_io3.v b/test_regress/t/t_mem_multi_io3.v
new file mode 100644
index 0000000..e2d8266
--- /dev/null
+++ b/test_regress/t/t_mem_multi_io3.v
@@ -0,0 +1,52 @@
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013.
+
+module t
+ (
+ input logic clk,
+ input logic daten,
+ input logic [8:0] datval,
+ output logic signed [3:0][3:0][35:0] datao
+ );
+
+ logic signed [3:0][3:0][3:0][8:0] datat;
+
+ genvar i;
+ generate
+ for (i=0; i<4; i++)begin
+ testio dut(.clk(clk), .arr3d_in(datat[i]), .arr2d_out(datao[i]));
+ end
+ endgenerate
+
+ genvar j;
+ generate
+ for (i=0; i<4; i++) begin
+ for (j=0; j<4; j++) begin
+ always_comb datat[i][j][0] = daten ? 9'h0 : datval;
+ always_comb datat[i][j][1] = daten ? 9'h1 : datval;
+ always_comb datat[i][j][2] = daten ? 9'h2 : datval;
+ always_comb datat[i][j][3] = daten ? 9'h3 : datval;
+ end
+ end
+ endgenerate
+endmodule
+
+module testio
+ (
+ input clk,
+ input logic signed [3:0] [3:0] [8:0] arr3d_in,
+ output logic signed [3:0] [35:0] arr2d_out
+ );
+ logic signed [3:0] [35:0] ar2d_out_pre;
+
+ always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
+ always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
+ always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
+ always_comb ar2d_out_pre[0][35:0] = {arr3d_in[0][0][8:0], arr3d_in[0][1][8:0], arr3d_in[0][2][8:0], arr3d_in[0][3][8:0]};
+
+ always_ff @(posedge clk) begin
+ if (clk)
+ arr2d_out <= ar2d_out_pre;
+ end
+
+endmodule
diff --git a/test_regress/t/t_mem_multi_io3_cc.pl b/test_regress/t/t_mem_multi_io3_cc.pl
new file mode 100755
index 0000000..d9a9e9b
--- /dev/null
+++ b/test_regress/t/t_mem_multi_io3_cc.pl
@@ -0,0 +1,21 @@
+#!/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.
+
+top_filename("t/t_mem_multi_io3.v");
+
+$Self->{vlt} or $Self->skip("Verilator only test");
+
+compile (
+ make_top_shell => 0,
+ make_main => 0,
+ verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp -Oi"],
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_mem_multi_io3_sc.pl b/test_regress/t/t_mem_multi_io3_sc.pl
new file mode 100755
index 0000000..5d54f4f
--- /dev/null
+++ b/test_regress/t/t_mem_multi_io3_sc.pl
@@ -0,0 +1,21 @@
+#!/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.
+
+top_filename("t/t_mem_multi_io3.v");
+
+$Self->{vlt} or $Self->skip("Verilator only test");
+
+compile (
+ make_top_shell => 0,
+ make_main => 0,
+ verilator_flags2 => ["--exe $Self->{t_dir}/t_mem_multi_io3.cpp --sc -Oi"],
+ );
+
+ok(1);
+1;
diff --git a/test_regress/t/t_mem_slice.pl b/test_regress/t/t_mem_slice.pl
index 639bb98..7058e62 100755
--- a/test_regress/t/t_mem_slice.pl
+++ b/test_regress/t/t_mem_slice.pl
@@ -8,7 +8,6 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
# Version 2.0.
compile (
- v_flags => [],
);
execute (
diff --git a/test_regress/t/t_EXAMPLE.pl b/test_regress/t/t_param_if_blk.pl
similarity index 100%
copy from test_regress/t/t_EXAMPLE.pl
copy to test_regress/t/t_param_if_blk.pl
diff --git a/test_regress/t/t_param_if_blk.v b/test_regress/t/t_param_if_blk.v
new file mode 100644
index 0000000..1ff45e6
--- /dev/null
+++ b/test_regress/t/t_param_if_blk.v
@@ -0,0 +1,140 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013.
+
+// bug648
+
+module t (/*AUTOARG*/
+ // Inputs
+ clk
+ );
+ input clk;
+
+ integer cyc=0;
+ reg [63:0] crc;
+ reg [63:0] sum;
+
+ // Take CRC data and apply to testblock inputs
+ wire [7:0] datai = crc[7:0];
+ wire enable = crc[8];
+
+ /*AUTOWIRE*/
+ // Beginning of automatic wires (for undeclared instantiated-module outputs)
+ logic [7:0] datao; // From test of Test.v
+ // End of automatics
+
+ Test test (/*AUTOINST*/
+ // Outputs
+ .datao (datao[7:0]),
+ // Inputs
+ .clk (clk),
+ .datai (datai[7:0]),
+ .enable (enable));
+
+ // Aggregate outputs into a single result vector
+ wire [63:0] result = {56'h0, datao};
+
+ // 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'h9d550d82d38926fa
+ if (sum !== `EXPECTED_SUM) $stop;
+ $write("*-* All Finished *-*\n");
+ $finish;
+ end
+ end
+
+endmodule
+
+`define FAIL 1
+
+module Nested
+ (
+ input logic clk,
+ input logic x,
+ output logic y
+ );
+ logic t;
+ always_comb t = x ^ 1'b1;
+
+ always_ff @(posedge clk) begin
+ if (clk)
+ y <= t;
+ end
+endmodule
+
+module Test
+ (
+ input logic clk,
+ input logic [7:0] datai,
+ input logic enable,
+ output logic [7:0] datao
+ );
+
+ // verilator lint_off BLKANDNBLK
+ logic [7:0] datat;
+ // verilator lint_on BLKANDNBLK
+
+ for (genvar i = 0; i < 8; i++) begin
+ if (i%4 != 3) begin
+`ifndef FAIL
+ logic t;
+ always_comb begin
+ t = datai[i] ^ 1'b1;
+ end
+ always_ff @(posedge clk) begin
+ if (clk)
+ datat[i] <= t;
+ end
+`else
+ Nested nested_i
+ (
+ .clk(clk),
+ .x(datai[i]),
+ .y(datat[i]) //<== via Vcellout wire
+ );
+`endif
+
+ always_comb begin
+ casez (enable)
+ 1'b1: datao[i] = datat[i];
+ 1'b0: datao[i] = '0;
+ default: datao[i] = 'x;
+ endcase
+ end
+ end
+ else begin
+ always_ff @(posedge clk) begin
+ if (clk)
+ datat[i] <= 0; //<== assign delayed
+ end
+ always_comb begin
+ casez (enable)
+ 1'b1: datao[i] = datat[i] ^ 1'b1;
+ 1'b0: datao[i] = '1;
+ default: datao[i] = 'x;
+ endcase
+ end
+ end
+ end
+endmodule
diff --git a/verilator.1 b/verilator.1
index c01aa70..9fa7e08 100644
--- a/verilator.1
+++ b/verilator.1
@@ -124,7 +124,7 @@
.\" ========================================================================
.\"
.IX Title "VERILATOR 1"
-.TH VERILATOR 1 "2013-05-06" "perl v5.14.2" "User Contributed Perl Documentation"
+.TH VERILATOR 1 "2013-05-29" "perl v5.14.2" "User Contributed Perl Documentation"
.\" For nroff, turn off justification. Always turn off hyphenation; it makes
.\" way too many mistakes in technical documents.
.if n .ad l
@@ -1787,16 +1787,12 @@ Verilator supports most Verilog 2005 language features. This includes the
uwire keyword.
.SS "SystemVerilog 2005 (\s-1IEEE\s0 1800\-2005) Support"
.IX Subsection "SystemVerilog 2005 (IEEE 1800-2005) Support"
-Verilator currently has some support for SystemVerilog synthesis
-constructs. As SystemVerilog features enter common usage they are added;
-please file a bug if a feature you need is missing.
-.PP
Verilator supports ==? and !=? operators, ++ and \*(-- in some contexts,
\&\f(CW$bits\fR, \f(CW$countones\fR, \f(CW$error\fR, \f(CW$fatal\fR, \f(CW$info\fR, \f(CW$isunknown\fR, \f(CW$onehot\fR, \f(CW$onehot0\fR,
\&\f(CW$unit\fR, \f(CW$warning\fR, always_comb, always_ff, always_latch, bit, byte, chandle,
-const, do-while, enum, export, final, import, int, logic, longint, package,
-program, shortint, struct, time, typedef, union, var, void, priority
-case/if, and unique case/if.
+const, do-while, enum, export, final, import, int, interface, logic,
+longint, modport, package, program, shortint, struct, time, typedef, union,
+var, void, priority case/if, and unique case/if.
.PP
It also supports .name and .* interconnection.
.PP
@@ -2398,6 +2394,11 @@ and continue keywords.
.IX Item "inside"
Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.
+.IP "interface" 4
+.IX Item "interface"
+Interfaces and modports, including with generated data types are supported.
+Generate blocks around modports are not supported, nor are virtual
+interfaces nor unnamed interfaces.
.IP "priority if, unique if" 4
.IX Item "priority if, unique if"
Priority and unique if's are treated as normal ifs and not asserted to be
diff --git a/verilator.html b/verilator.html
index 4a65aee..5bafde1 100644
--- a/verilator.html
+++ b/verilator.html
@@ -1837,15 +1837,12 @@ uwire keyword.</p>
<p>
</p>
<h2><a name="systemverilog_2005__ieee_1800_2005__support">SystemVerilog 2005 (IEEE 1800-2005) Support</a></h2>
-<p>Verilator currently has some support for SystemVerilog synthesis
-constructs. As SystemVerilog features enter common usage they are added;
-please file a bug if a feature you need is missing.</p>
<p>Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte, chandle,
-const, do-while, enum, export, final, import, int, logic, longint, package,
-program, shortint, struct, time, typedef, union, var, void, priority
-case/if, and unique case/if.</p>
+const, do-while, enum, export, final, import, int, interface, logic,
+longint, modport, package, program, shortint, struct, time, typedef, union,
+var, void, priority case/if, and unique case/if.</p>
<p>It also supports .name and .* interconnection.</p>
<p>Verilator partially supports concurrent assert and cover statements; see
the enclosed coverage tests for the syntax which is allowed.</p>
@@ -2521,6 +2518,13 @@ and continue keywords.</p>
<p>Inside expressions may not include unpacked array traversal or $ as an
upper bound. Case inside and case matches are also unsupported.</p>
</dd>
+<dt><strong><a name="interface" class="item">interface</a></strong></dt>
+
+<dd>
+<p>Interfaces and modports, including with generated data types are supported.
+Generate blocks around modports are not supported, nor are virtual
+interfaces nor unnamed interfaces.</p>
+</dd>
<dt><strong><a name="priority_if_unique_if" class="item">priority if, unique if</a></strong></dt>
<dd>
diff --git a/verilator.pdf b/verilator.pdf
index 4fb9b67..49812e7 100644
Binary files a/verilator.pdf and b/verilator.pdf differ
diff --git a/verilator.txt b/verilator.txt
index 25a4242..4746811 100644
--- a/verilator.txt
+++ b/verilator.txt
@@ -1587,16 +1587,12 @@ LANGUAGE STANDARD SUPPORT
the uwire keyword.
SystemVerilog 2005 (IEEE 1800-2005) Support
- Verilator currently has some support for SystemVerilog synthesis
- constructs. As SystemVerilog features enter common usage they are added;
- please file a bug if a feature you need is missing.
-
Verilator supports ==? and !=? operators, ++ and -- in some contexts,
$bits, $countones, $error, $fatal, $info, $isunknown, $onehot, $onehot0,
$unit, $warning, always_comb, always_ff, always_latch, bit, byte,
- chandle, const, do-while, enum, export, final, import, int, logic,
- longint, package, program, shortint, struct, time, typedef, union, var,
- void, priority case/if, and unique case/if.
+ chandle, const, do-while, enum, export, final, import, int, interface,
+ logic, longint, modport, package, program, shortint, struct, time,
+ typedef, union, var, void, priority case/if, and unique case/if.
It also supports .name and .* interconnection.
@@ -2219,6 +2215,11 @@ LANGUAGE LIMITATIONS
Inside expressions may not include unpacked array traversal or $ as
an upper bound. Case inside and case matches are also unsupported.
+ interface
+ Interfaces and modports, including with generated data types are
+ supported. Generate blocks around modports are not supported, nor
+ are virtual interfaces nor unnamed interfaces.
+
priority if, unique if
Priority and unique if's are treated as normal ifs and not asserted
to be full nor unique.
--
Packaging for Verilator
More information about the Pkg-electronics-commits
mailing list