[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