[Pkg-electronics-commits] [verilator] 01/03: Imported Upstream version 3.868

أحمد المحمودي (Ahmed El-Mahmoudy) aelmahmoudy at sabily.org
Tue Dec 23 13:57:27 UTC 2014


This is an automated email from the git hooks/post-receive script.

aelmahmoudy-guest pushed a commit to branch experimental
in repository verilator.

commit 29747cec4bc3e7dfc7b74412374dbbf43ce7299c
Author: أحمد المحمودي (Ahmed El-Mahmoudy) <aelmahmoudy at users.sourceforge.net>
Date:   Tue Dec 23 10:49:53 2014 +0200

    Imported Upstream version 3.868
---
 .gitignore                                         |   1 +
 Changes                                            |  25 ++
 MANIFEST.SKIP                                      |   1 +
 Makefile.in                                        |  39 +-
 README                                             |  13 +-
 README.html                                        |  14 +-
 README.pdf                                         | Bin 112209 -> 110434 bytes
 TODO                                               |  17 -
 bin/verilator                                      | 100 ++---
 bin/verilator_coverage                             | 291 +++++++++++++
 bin/verilator_includer                             |   6 +-
 configure                                          |  18 +-
 configure.ac                                       |   2 +-
 doxygen.config                                     |   2 -
 include/verilated.cpp                              |  50 +++
 include/verilated.h                                |   4 +
 include/verilated.mk.in                            |  10 +-
 include/verilated_config.h                         |   2 +-
 include/verilated_cov.cpp                          | 451 ++++++++++++++++++++
 include/verilated_cov.h                            | 146 +++++++
 include/verilated_cov_key.h                        | 147 +++++++
 include/verilated_heavy.h                          |  13 +-
 include/verilated_vcd_c.cpp                        |   2 +-
 include/verilated_vcd_c.h                          |   2 +-
 include/verilated_vcd_sc.cpp                       |   2 +-
 include/verilated_vcd_sc.h                         |   2 +-
 include/verilatedos.h                              |   7 +
 internals.html                                     |  13 +-
 internals.pdf                                      | Bin 197500 -> 195665 bytes
 internals.pod                                      |  14 +-
 internals.txt                                      |  13 +-
 readme.pod                                         |  14 +-
 src/Makefile.in                                    |   8 +-
 src/Makefile_obj.in                                |  26 +-
 src/V3Assert.cpp                                   |  22 +-
 src/V3AssertPre.cpp                                |  15 -
 src/V3Ast.cpp                                      |  25 --
 src/V3Ast.h                                        |  26 +-
 src/V3AstNodes.cpp                                 |  10 +-
 src/V3AstNodes.h                                   | 258 ++++++++----
 src/V3Branch.cpp                                   |  45 +-
 src/V3Config.h                                     |   1 +
 src/V3Const.cpp                                    |  10 +-
 src/V3EmitC.cpp                                    |  39 +-
 src/V3EmitMk.cpp                                   |   6 +-
 src/V3EmitV.cpp                                    |   6 +-
 src/V3EmitXml.cpp                                  |   2 +-
 src/V3Error.cpp                                    | 284 +------------
 src/V3Error.h                                      | 154 +------
 src/V3File.cpp                                     |   2 +-
 src/{V3Error.cpp => V3FileLine.cpp}                | 215 +---------
 src/V3FileLine.h                                   | 171 ++++++++
 src/V3Global.h                                     |   1 +
 src/V3LinkDot.cpp                                  |  17 +
 src/V3LinkLevel.cpp                                |   7 +-
 src/V3Number.cpp                                   |  69 +++-
 src/V3Number.h                                     |  27 +-
 src/V3Number_test.cpp                              |   1 +
 src/V3Options.cpp                                  |  24 +-
 src/V3Options.h                                    |  10 +-
 src/V3ParseImp.cpp                                 |   2 +-
 src/V3ParseImp.h                                   |   4 +-
 src/V3ParseLex.cpp                                 |   9 -
 src/V3ParseSym.h                                   |   1 +
 src/V3PreLex.h                                     |   5 +-
 src/V3PreLex.l                                     |  62 +--
 src/V3PreProc.cpp                                  |  11 +-
 src/V3PreProc.h                                    |   2 +-
 src/V3PreShell.h                                   |   1 +
 src/V3Premit.cpp                                   |  24 +-
 src/V3Stats.cpp                                    |  28 +-
 src/V3Stats.h                                      |   3 +-
 src/V3Subst.cpp                                    |  11 +-
 src/V3Unknown.cpp                                  |   8 +-
 src/V3Width.cpp                                    | 457 ++++++++++++++++++---
 src/V3WidthCommit.h                                |   5 +-
 src/Verilator.cpp                                  |   2 +-
 src/VlcBucket.h                                    | 133 ++++++
 src/VlcMain.cpp                                    | 203 +++++++++
 src/VlcOptions.h                                   |  87 ++++
 src/VlcPoint.h                                     | 152 +++++++
 src/VlcSource.h                                    | 145 +++++++
 src/VlcTest.h                                      | 137 ++++++
 src/VlcTop.cpp                                     | 263 ++++++++++++
 src/VlcTop.h                                       |  69 ++++
 src/astgen                                         |   8 +-
 src/config_build.h                                 |   2 +-
 src/config_rev.h                                   |   2 +-
 src/verilog.l                                      | 172 ++------
 src/verilog.y                                      |  94 +----
 src/vlcovgen                                       | 173 ++++++++
 test_regress/Makefile_obj                          |   2 +-
 test_regress/driver.pl                             |  16 +-
 test_regress/t/t_assert_basic_cover.pl             |   2 +-
 test_regress/t/t_assert_cover.pl                   |   2 +-
 test_regress/t/t_bitsel_wire_array_bad.pl          |  13 +-
 test_regress/t/t_cover_line.out                    | 170 ++++++++
 test_regress/t/t_cover_line_cc.pl                  |   9 +-
 test_regress/t/t_cover_line_sp.pl                  |  24 --
 test_regress/t/t_cover_sva_notflat.pl              |   2 +-
 test_regress/t/t_cover_toggle.pl                   |   2 +-
 test_regress/t/t_dist_spdiff.pl                    |  23 --
 .../{t_sv_enum_type_methods.pl => t_enum_name2.pl} |   3 -
 test_regress/t/t_enum_name2.v                      |  31 ++
 test_regress/t/t_enum_type_methods.v               | 143 ++++---
 ...sv_enum_type_methods.pl => t_enum_type_pins.pl} |   0
 ...t_sv_enum_type_methods.v => t_enum_type_pins.v} |   0
 .../{t_sv_enum_type_methods.pl => t_flag_stats.pl} |   6 +-
 test_regress/t/t_flag_stats.v                      |  13 +
 test_regress/t/t_flag_werror_bad2.pl               |   2 +-
 test_regress/t/t_help.pl                           |  22 +-
 test_regress/t/t_inst_overwide.pl                  |   2 +-
 test_regress/t/t_inst_overwide_bad.pl              |   2 +-
 .../t/{t_psl_basic_off.pl => t_interface_gen4.pl}  |   9 +-
 test_regress/t/t_interface_gen4.v                  |  58 +++
 test_regress/t/t_math_real.v                       |   1 +
 test_regress/t/t_mem_multidim_trace.pl             |   2 +-
 test_regress/t/t_preproc_psl.v                     |  72 ----
 test_regress/t/t_preproc_psl_off.out               |  99 -----
 test_regress/t/t_preproc_psl_on.out                |  88 ----
 test_regress/t/t_psl_basic.v                       |  54 ---
 test_regress/t/t_psl_basic_cover.pl                |  26 --
 test_regress/t/t_savable.v                         |   1 +
 .../t/{t_sv_enum_type_methods.pl => t_string.pl}   |   3 -
 test_regress/t/t_string.v                          |  91 ++++
 test_regress/t/t_sys_sformat.v                     |   4 +
 test_regress/t/t_trace_ena_sp.pl                   |  26 --
 test_regress/t/t_trace_off_sp.pl                   |  25 --
 .../t/{t_psl_basic.pl => t_trace_scstruct.pl}      |   8 +-
 test_regress/t/t_trace_scstruct.v                  |  26 ++
 test_regress/t/t_var_pins_sc1.pl                   |  34 +-
 test_regress/t/t_var_pins_sc2.pl                   |  34 +-
 test_regress/t/t_var_pins_sc32.pl                  |  34 +-
 test_regress/t/t_var_pins_sc64.pl                  |  34 +-
 test_regress/t/t_var_pins_sc_biguint.pl            |  42 +-
 test_regress/t/t_var_pins_sc_uint.pl               |  42 +-
 test_regress/t/t_var_pins_sc_uint_biguint.pl       |  42 +-
 test_regress/t/t_var_pins_scui.pl                  |  34 +-
 .../{t_sv_enum_type_methods.pl => t_var_static.pl} |   3 +-
 test_regress/t/t_var_static.v                      |  69 ++++
 test_regress/t/t_vlcov_data_a.dat                  |   5 +
 test_regress/t/t_vlcov_data_b.dat                  |   5 +
 test_regress/t/t_vlcov_data_c.dat                  |   2 +
 test_regress/t/t_vlcov_data_d.dat                  |   2 +
 test_regress/t/t_vlcov_merge.out                   |   8 +
 .../t/{t_preproc_psl_off.pl => t_vlcov_merge.pl}   |  19 +-
 test_regress/t/t_vlcov_rank.out                    |   6 +
 .../t/{t_preproc_psl_on.pl => t_vlcov_rank.pl}     |  21 +-
 .../t/{t_preproc_psl_off.pl => t_vlcov_rewrite.pl} |  25 +-
 test_sc/Makefile                                   |   7 +-
 test_sc/sc_main.cpp                                |  37 +-
 test_sp/.gitignore                                 |   8 -
 test_sp/Makefile                                   |  86 ----
 test_sp/Makefile_obj                               |  37 --
 test_vcs/.gitignore                                |  13 -
 test_vcs/Makefile                                  |  76 ----
 test_vcs/bench.v                                   |  81 ----
 verilator.1                                        |  98 ++---
 verilator.html                                     |  93 ++---
 verilator.pdf                                      | Bin 389398 -> 386595 bytes
 verilator.txt                                      | 100 ++---
 verilator_coverage.1                               | 238 +++++++++++
 162 files changed, 4889 insertions(+), 2705 deletions(-)

diff --git a/.gitignore b/.gitignore
index 9b7b2e8..7fc9bdb 100644
--- a/.gitignore
+++ b/.gitignore
@@ -23,3 +23,4 @@ gdbrun*
 internals.txt
 verilator.txt
 verilator_bin*
+verilator_coverage_bin*
diff --git a/Changes b/Changes
index d6a81dd..e549f08 100644
--- a/Changes
+++ b/Changes
@@ -3,6 +3,31 @@ 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.868 2014-12-20
+
+**    New verilator_coverage program added to replace SystemPerl's vcoverage.
+
+**    PSL support was removed, please use System Verilog assertions.
+
+**    SystemPerl mode is deprecated and now untested.
+
+***   Support enum.first/name and similar methods, bug460, bug848.
+
+***   Add 'string' printing and comparisons, bug746, bug747, etc.
+
+***   Inline C functions that are used only once, msg1525. [Jie Xu]
+
+***   Fix tracing SystemC signals with structures, bug858. [Eivind Liland]
+      Note that SystemC traces will no longer show the signals
+      in the wrapper, they can be seen one level further down.
+
+****  Add --stats-vars, bug851. [Jeremy Bennett]
+
+****  Fix bare generates in interfaces, bug789. [Bob Newgard]
+
+****  Fix underscores in real literals, bug863. [Jonathon Donaldson]
+
+
 * Verilator 3.866 2014-11-15
 
 ***   Fix +define+A+B to define A and B to match other simulators, bug847. [Adam Krolnik]
diff --git a/MANIFEST.SKIP b/MANIFEST.SKIP
index 8ff54ea..ca6161f 100644
--- a/MANIFEST.SKIP
+++ b/MANIFEST.SKIP
@@ -28,6 +28,7 @@ config.status$
 verilator.log
 verilator.tex
 verilator_bin.*
+verilator_coverage_bin.*
 .vcsmx_rebuild$
 autom4te\.cache/
 nodist/
diff --git a/Makefile.in b/Makefile.in
index d7cf4c9..166823d 100644
--- a/Makefile.in
+++ b/Makefile.in
@@ -100,10 +100,11 @@ PACKAGE_VERSION = @PACKAGE_VERSION@
 
 SHELL = /bin/sh
 
-SUBDIRS = src test_verilated test_c test_sc test_sp test_regress test_vcs
+SUBDIRS = src test_verilated test_c test_sc test_regress
 
 INFOS = README README.html README.pdf internals.txt internals.html \
-        internals.pdf verilator.txt verilator.html verilator.1 verilator.pdf
+        internals.pdf verilator.txt verilator.html verilator.1 verilator.pdf \
+	verilator_coverage.1
 
 # Files that can be generated, but should be up to date for a distribution.
 DISTDEP = info Makefile
@@ -122,6 +123,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
 	.*attributes */.*attributes  */*/.*attributes \
 	src/.*ignore src/*.in src/*.cpp src/*.[chly] \
 	src/astgen src/bisonpre src/*fix src/cppcheck_filtered \
+	src/vlcovgen \
 	src/.gdbinit \
 	src/*.pl src/*.pod \
 	test_*/.*ignore test_*/Makefile* test_*/*.cpp \
@@ -140,6 +142,7 @@ DISTFILES_INC = $(INFOS) .gitignore Artistic COPYING COPYING.LESSER \
 
 INST_PROJ_FILES = \
 	bin/verilator \
+	bin/verilator_coverage \
 	bin/verilator_includer \
 	bin/verilator_profcfunc \
 	include/verilated.mk \
@@ -149,6 +152,7 @@ INST_PROJ_FILES = \
 INST_PROJ_BIN_FILES = \
 	verilator_bin \
 	verilator_bin_dbg \
+	verilator_coverage_bin_dbg \
 
 DISTFILES := $(DISTFILES_INC)
 
@@ -165,7 +169,8 @@ all_nomsg: verilator_exe $(VL_INST_MAN_FILES)
 .PHONY:verilator_exe
 .PHONY:verilator_bin
 .PHONY:verilator_bin_dbg
-verilator_exe verilator_bin verilator_bin_dbg:
+.PHONY:verilator_coverage_bin_dbg
+verilator_exe verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg:
 	@echo ------------------------------------------------------------
 	@echo "making verilator in src" ; \
 	  (cd src && $(MAKE) $(OBJCACHE_JOBS) )
@@ -179,17 +184,15 @@ msg_test: all_nomsg
 
 .PHONY:test
 ifeq ($(CFG_WITH_LONGTESTS),yes)	# Local... Else don't burden users
-test: test_vcs test_c test_sc test_sp test_verilated test_regress
+test: test_c test_sc test_verilated test_regress
 else
-test: test_c test_sc test_sp
+test: test_c test_sc
 endif
 	@echo "Tests passed!"
 	@echo
 	@echo "Type 'make install' to install documentation."
 	@echo
 
-test_vcs: all_nomsg
-	@(cd test_vcs && $(MAKE))
 test_c: all_nomsg
 	@(cd test_c && $(MAKE))
 test_c_debug: all_nomsg
@@ -198,10 +201,6 @@ test_sc: all_nomsg
 	@(cd test_sc && $(MAKE))
 test_sc_debug: all_nomsg
 	@(cd test_sc && $(MAKE) test_debug)
-test_sp: all_nomsg
-	@(cd test_sp && $(MAKE))
-test_sp_debug: all_nomsg
-	@(cd test_sp && $(MAKE) test_debug)
 test_verilated: all_nomsg
 	@(cd test_verilated && $(MAKE))
 test_regress: all_nomsg
@@ -213,6 +212,9 @@ info: $(INFOS)
 verilator.1: ${srcdir}/bin/verilator
 	pod2man $< $@
 
+verilator_coverage.1: ${srcdir}/bin/verilator_coverage
+	pod2man $< $@
+
 verilator.txt: ${srcdir}/bin/verilator
 	$(POD2TEXT) $< $@
 
@@ -261,13 +263,13 @@ internals.pdf: internals.pod Makefile
 	-rm -f internals.toc internals.aux internals.idx internals.out
 
 # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
-VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg \
-	verilator_includer verilator_profcfunc
+VL_INST_BIN_FILES = verilator verilator_bin verilator_bin_dbg verilator_coverage_bin_dbg \
+	verilator_coverage verilator_includer verilator_profcfunc
 # Some scripts go into both the search path and pkgdatadir,
 # so they can be found by the user, and under $VERILATOR_ROOT.
 
 # See uninstall also - don't put wildcards in this variable, it might uninstall other stuff
-VL_INST_MAN_FILES = verilator.1
+VL_INST_MAN_FILES = verilator.1 verilator_coverage.1
 
 VL_INST_INC_BLDDIR_FILES = \
 	include/verilated.mk \
@@ -281,14 +283,15 @@ VL_INST_DATA_SRCDIR_FILES = \
 	test_v/*.[chv]* \
 	test_c/*.[chv]*   test_c/Makefile  test_c/Makefile_obj  \
 	test_sc/*.[chv]*  test_sc/Makefile test_sc/Makefile_obj \
-	                  test_sp/Makefile test_sp/Makefile_obj \
 
 installbin:
 	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(bindir)
 	( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator $(DESTDIR)$(bindir)/verilator )
+	( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_coverage $(DESTDIR)$(bindir)/verilator_coverage )
 	( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_profcfunc $(DESTDIR)$(bindir)/verilator_profcfunc )
 	( $(INSTALL_PROGRAM) verilator_bin $(DESTDIR)$(bindir)/verilator_bin )
 	( $(INSTALL_PROGRAM) verilator_bin_dbg $(DESTDIR)$(bindir)/verilator_bin_dbg )
+	( $(INSTALL_PROGRAM) verilator_coverage_bin_dbg $(DESTDIR)$(bindir)/verilator_coverage_bin_dbg )
 	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/bin
 	( cd ${srcdir}/bin ; $(INSTALL_PROGRAM) verilator_includer $(DESTDIR)$(pkgdatadir)/bin/verilator_includer )
 
@@ -311,7 +314,6 @@ installdata:
 	done
 	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_c
 	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sc
-	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_sp
 	$(SHELL) ${srcdir}/mkinstalldirs $(DESTDIR)$(pkgdatadir)/examples/test_v
 	cd $(srcdir) \
 	; for p in $(VL_INST_DATA_SRCDIR_FILES) ; do \
@@ -351,6 +353,7 @@ INST_PROJ_CVS = cp_if_cvs_diff
 install-project: dist
 	@echo "Install-project to $(DIRPROJECT)"
 	strip verilator_bin*
+	strip verilator_coverage_bin*
 	$(MAKE) install-project-quick
 	for p in $(VL_INST_MAN_FILES) ; do \
 	  $(INSTALL_DATA) $$p $(DIRPROJECT_PREFIX)/man/man1/$$p; \
@@ -374,6 +377,7 @@ endif
 install-cadtools: dist
 	@echo "Install-project to $(CAD_DIR)"
 	strip verilator_bin*
+	strip verilator_coverage_bin*
 	$(MAKE) install-cadtools-quick
 	$(SHELL) ${srcdir}/mkinstalldirs $(VERILATOR_CAD_DIR)/man/man1
 	for p in $(VL_INST_MAN_FILES) ; do \
@@ -459,7 +463,8 @@ clean mostlyclean distclean maintainer-clean::
 	rm -f *.tex
 
 distclean maintainer-clean::
-	rm -f Makefile config.status config.cache config.log verilator_bin* TAGS
+	rm -f Makefile config.status config.cache config.log TAGS
+	rm -f verilator_bin* verilator_coverage_bin*
 	rm -f include/verilated.mk include/verilated_config.h
 
 TAGFILES=${srcdir}/*/*.cpp ${srcdir}/*/*.h ${srcdir}/*/*.in \
diff --git a/README b/README
index d225e3e..76e32ba 100644
--- a/README
+++ b/README
@@ -65,12 +65,6 @@ INSTALLATION
         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
-        to set a "SYSTEMPERL" environment variable to point to the
-        downloaded kit. Optionally also set "SYSTEMPERL_INCLUDE" to point to
-        the installed headers.
-
     *   You will need the "flex" and "bison" packages installed.
 
     *   "cd" to the Verilator directory containing this README.
@@ -79,9 +73,8 @@ INSTALLATION
         kit.
 
         Note Verilator builds the current value of VERILATOR_ROOT,
-        SYSTEMC_INCLUDE, SYSTEMC_LIBDIR, SYSTEMPERL, and SYSTEMPERL_INCLUDE
-        as defaults into the executable, so try to have them correct before
-        configuring.
+        SYSTEMC_INCLUDE, and SYSTEMC_LIBDIR as defaults into the executable,
+        so try to have them correct before configuring.
 
         1.  Our personal favorite is to always run Verilator from the kit
             directory. This allows the easiest experimentation and
@@ -167,8 +160,6 @@ DIRECTORY STRUCTURE
         test_v                      => Example Verilog code for other test dirs
         test_c                      => Example Verilog->C++ conversion
         test_sc                     => Example Verilog->SystemC conversion
-        test_sp                     => Example Verilog->SystemPerl conversion
-        test_vcs                    => Example Verilog->VCS conversion (test the test)
         test_verilated              => Internal tests
         test_regress                => Internal tests
 
diff --git a/README.html b/README.html
index 6e354fd..6cefc68 100644
--- a/README.html
+++ b/README.html
@@ -100,14 +100,6 @@ instead.)</p>
 </dd>
 <dt>
 <dd>
-<p>If you will be using SystemPerl or coverage, download and install
-System-Perl, <a href="http://www.veripool.org/systemperl">http://www.veripool.org/systemperl</a>.  Note you'll need to
-set a <code>SYSTEMPERL</code> environment variable to point to the downloaded kit.
-Optionally also set <code>SYSTEMPERL_INCLUDE</code> to point to the installed
-headers.</p>
-</dd>
-<dt>
-<dd>
 <p>You will need the <code>flex</code> and <code>bison</code> packages installed.</p>
 </dd>
 <dt>
@@ -118,8 +110,8 @@ headers.</p>
 <dd>
 <p>You now have to decide how you're going to eventually install the kit.</p>
 <p>Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC_INCLUDE,
-SYSTEMC_LIBDIR, SYSTEMPERL, and SYSTEMPERL_INCLUDE as defaults into the
-executable, so try to have them correct before configuring.</p>
+and SYSTEMC_LIBDIR as defaults into the executable, so try to have them
+correct before configuring.</p>
 <ol>
 <li>
 <p>Our personal favorite is to always run Verilator from the kit directory.
@@ -211,8 +203,6 @@ set.</p>
     test_v                      => Example Verilog code for other test dirs
     test_c                      => Example Verilog->C++ conversion
     test_sc                     => Example Verilog->SystemC conversion
-    test_sp                     => Example Verilog->SystemPerl conversion
-    test_vcs                    => Example Verilog->VCS conversion (test the test)
     test_verilated              => Internal tests
     test_regress                => Internal tests</pre>
 <p>
diff --git a/README.pdf b/README.pdf
index 23a73fc..3c8acf5 100644
Binary files a/README.pdf and b/README.pdf differ
diff --git a/TODO b/TODO
index 15410b5..5c84ebe 100755
--- a/TODO
+++ b/TODO
@@ -30,23 +30,6 @@ Configure/Make/Install
 	* Full MSVC++ compilation (does scons support this?) (4.000?)
 	* Distribute with flex/bison already expanded?
 	  Flex library not needed.  Probably too difficult to be worth it.
-	* Integrate SystemPerl coverage
-	      see the SystemPerl git branch coverage_only
-    	      (Note in /usr/include there are no upper cased include files.)
-		Coverage.pm		-- Need all functionality, but in C?
-		Coverage/Item.pm	-- Need all functionality, but in C?
-		Coverage/ItemKey.pm	-- Need all functionality, but in C?
-		sp_preproc		-- Some steps in here need to be moved to generated C
-		--			   -- note uses Verilog::Getopt
-		src/Sp.cpp		-- n/a
-		src/SpCommon.h		-- mostly overlaps verilatedos.h
-		src/SpCoverage.cpp/h	-- All needed
-		src/SpFunctor.cpp/h	-- No longer used
-		src/SpTraceVcd.cpp/h	-- MOVED
-		src/SpTraceVcdC.cpp/h	-- MOVED
-		src/sp_log.cpp/h	-- Not needed
-		src/systemperl.h	-- some stuff may be cut
-		vcoverage		-- Need all functionality, but in C?
 
 Testing:
 	* Move test_c/sp/v/verilated into test_regress format (4.000?)
diff --git a/bin/verilator b/bin/verilator
index 59f2e1c..04a8278 100755
--- a/bin/verilator
+++ b/bin/verilator
@@ -24,14 +24,10 @@ BEGIN {
     }
 }
 
-use File::Path;
-use File::Basename;
 use Getopt::Long;
 use FindBin qw($RealBin $RealScript);
 use IO::File;
 use Pod::Usage;
-use Config;
-use Cwd qw(abs_path getcwd);
 
 use strict;
 use vars qw ($Debug @Opt_Verilator_Sw);
@@ -209,17 +205,13 @@ Verilator - Convert Verilog code to C++/SystemC
 =head1 DESCRIPTION
 
 Verilator converts synthesizable (not behavioral) Verilog code, plus some
-Synthesis, SystemVerilog and a small subset of Verilog AMS
-assertions, into C++, SystemC or SystemPerl code.  It is not a complete
-simulator, just a compiler.
+Synthesis, SystemVerilog and a small subset of Verilog AMS assertions, into
+C++ or SystemC code.  It is not a complete simulator, but a compiler.
 
 Verilator is invoked with parameters similar to GCC, Cadence
 Verilog-XL/NC-Verilog, or Synopsys's VCS.  It reads the specified Verilog
 code, lints it, and optionally adds coverage and waveform tracing code.
-For C++ and SystemC formats, it outputs .cpp and .h files.  For SystemPerl
-format, it outputs .sp files for the SystemPerl preprocessor, which greatly
-simplifies writing SystemC code and is available at
-L<http://www.veripool.org>.
+For C++ and SystemC formats, it outputs .cpp and .h files.
 
 The files created by Verilator are then compiled with C++.  The user writes
 a little C++ wrapper file, which instantiates the top level module, and
@@ -316,8 +308,8 @@ descriptions in the next sections for more information.
     --report-unoptflat          Extra diagnostics for UNOPTFLAT
     --savable			Enable model save-restore
     --sc                        Create SystemC output
-    --sp                        Create SystemPerl output
     --stats                     Create statistics file
+    --stats-vars                Provide statistics on variables
      -sv                        Enable SystemVerilog parsing
      +systemverilogext+<ext>    Synonym for +1800-2012ext+<ext>
     --top-module <topname>      Name of top level input module
@@ -452,7 +444,7 @@ run on the generated makefile these will be passed to the C++ compiler
 
 =item --cc
 
-Specifies C++ without SystemC output mode; see also --sc and --sp.
+Specifies C++ without SystemC output mode; see also --sc.
 
 =item --cdc
 
@@ -969,16 +961,18 @@ other data the process needs saved/restored.  For example:
 
 =item --sc
 
-Specifies SystemC output mode; see also --cc and -sp.
-
-=item --sp
-
-Specifies SystemPerl output mode; see also --cc and -sc.
+Specifies SystemC output mode; see also --cc.
 
 =item --stats
 
 Creates a dump file with statistics on the design in {prefix}__stats.txt.
 
+=item --stats-vars
+
+Creates more detailed statistics including a list of all the variables by
+size (plain --stats just gives a count).  See --stats, which is implied by
+this.
+
 =item -sv
 
 Specifies SystemVerilog language features should be enabled; equivalent to
@@ -1291,7 +1285,7 @@ the test_c directory in the distribution for an example.
 
 =head1 EXAMPLE SYSTEMC EXECUTION
 
-This is an example similar to the above, but using SystemPerl.
+This is an example similar to the above, but using SystemC.
 
     mkdir test_our_sc
     cd test_our_sc
@@ -1326,17 +1320,7 @@ your operating system (as an RPM), first you need to point to the kit:
 
 Now we run Verilator on our little example.
 
-    verilator -Wall --sp our.v
-
-Then we convert the SystemPerl output to SystemC.
-
-    cd obj_dir
-    export SYSTEMPERL=/path/to/where/systemperl/kit/came/from
-    $SYSTEMPERL/sp_preproc --preproc *.sp
-
-(You can also skip the above sp_preproc by getting pure SystemC from
-Verilator by replacing the verilator --sp flag in the previous step with
--sc.)
+    verilator -Wall --sc our.v
 
 We then can compile it
 
@@ -1365,7 +1349,7 @@ And we get the same output as the C++ example:
 
 Really, you're better off using a Makefile to do all this for you.  Then,
 when your source changes it will automatically run all of these steps.  See
-the test_sp directory in the distribution for an example.
+the test_sc directory in the distribution for an example.
 
 
 =head1 BENCHMARKING & OPTIMIZATION
@@ -1423,6 +1407,10 @@ especially if you link in DPI code.  To enable LTO on GCC, pass "-flto" in
 both compilation and link.  Note LTO may cause excessive compile times on
 large designs.
 
+If you are using your own makefiles, you may want to compile the Verilated
+code with -DVL_INLINE_OPT=inline. This will inline functions, however this
+requires that all cpp files be compiled in a single compiler run.
+
 You may uncover further tuning possibilities by profiling the Verilog code.
 Use Verilator's --profile-cfuncs, then GCC's -g -pg.  You can then run
 either oprofile or gprof to see where in the C++ code the time is spent.
@@ -1450,11 +1438,6 @@ For -cc and -sc mode, it also creates:
     {prefix}{each_verilog_module}.cpp	// Lower level internal C++ files
     {prefix}{each_verilog_module}.h	// Lower level internal header files
 
-For -sp mode, instead of .cpp and .h it creates:
-
-    {prefix}.sp				// Top level SystemC file
-    {prefix}{each_verilog_module}.sp	// Lower level internal SC files
-
 In certain optimization modes, it also creates:
 
     {prefix}__Dpi.h			// DPI import and export declarations
@@ -1529,21 +1512,6 @@ specified, it will come from a default optionally specified at configure
 time (before Verilator was compiled), or computed from
 SYSTEMC/lib-SYSTEMC_ARCH.
 
-=item SYSTEMPERL
-
-Specifies the directory containing the SystemPerl distribution kit.  This
-is used to find the SystemPerl library and include files.  If not
-specified, it will come from a default optionally specified at configure
-time (before Verilator was compiled).  See also SYSTEMPERL_INCLUDE.
-
-=item SYSTEMPERL_INCLUDE
-
-Specifies the directory containing the Verilog-Perl include .cpp files,
-from the src/ directory of the SystemPerl kit.  If not specified, it will
-be computed from the SYSTEMPERL environment variable if it is set, and if
-SYSTEMPERL is not set SYSTEMPERL_INCLUDE will come from a default
-optionally specified at configure time (before Verilator was compiled).
-
 =item VCS_HOME
 
 If set, specifies the directory containing the Synopsys VCS distribution.
@@ -2180,8 +2148,8 @@ Specifies the module the comment appears in may be inlined into any modules
 that use this module.  This is useful to speed up simulation time with some
 small loss of trace visibility and modularity.  Note signals under inlined
 submodules will be named I<submodule>__DOT__I<subsignal> as C++ does not
-allow "." in signal names.  SystemPerl when tracing such signals will
-replace the __DOT__ with the period.
+allow "." in signal names.  When tracing such signals the tracing routines
+will replace the __DOT__ with the period.
 
 =item /*verilator isolate_assignments*/
 
@@ -2636,8 +2604,9 @@ All specify blocks and timing checks are ignored.
 
 =item string
 
-String is supported only to the point that they can be passed to DPI
-imports.
+String is supported only to the point that they can be assigned,
+concatenated, compared, and passed to DPI imports.  Standard method calls
+on strings are not supported.
 
 =item timeunit, timeprecision
 
@@ -3459,10 +3428,6 @@ flag.
 Note you can also call ->trace on multiple Verilated objects with the same
 trace file if you want all data to land in the same output file.
 
-Note also older versions of Verilator used the SystemPerl package and
-SpTraceVcdC class.  This still works, but is depreciated as it requires
-strong coupling between the Verilator and SystemPerl versions.
-
     #include "verilated_vcd_c.h"
     ...
     int main(int argc, char **argv, char **env) {
@@ -3485,7 +3450,7 @@ Add the --trace switch to Verilator, and in your top level C sc_main code,
 include verilated_vcd_sc.h.  Then call Verilated::traceEverOn(true).  Then
 create a VerilatedVcdSc object as you would create a normal SystemC trace
 file.  For an example, see the call to VerilatedVcdSc in the
-test_sp/sc_main.cpp file of the distribution, and below.
+test_sc/sc_main.cpp file of the distribution, and below.
 
 Alternatively you may use the C++ trace mechanism described in the previous
 question, however the timescale and timeprecision will not inherited from
@@ -3537,22 +3502,21 @@ network disk.  Network disks are generally far slower.
 =item How do I do coverage analysis?
 
 Verilator supports both block (line) coverage and user inserted functional
-coverage.  Both require the SystemPerl package to be installed but do not
-require use of the SystemPerl output mode.
+coverage.
 
 First, run verilator with the --coverage option.  If you're using your own
-makefile, compile the model with the GCC flag -DSP_COVERAGE (if using
+makefile, compile the model with the GCC flag -DVM_COVERAGE (if using
 Verilator's, it will do this for you.)
 
 Run your tests in different directories.  Each test will create a
 logs/coverage.pl file.
 
-After running all of your tests, the vcoverage utility (from the SystemPerl
-package) is executed.  Vcoverage reads the logs/coverage.pl file(s), and
-creates an annotated source code listing showing code coverage details.
+After running all of your tests, verilator_coverage is executed.
+Verilator_coverage reads the logs/coverage.pl file(s), and creates an
+annotated source code listing showing code coverage details.
 
 For an example, after running 'make test' in the Verilator distribution,
-see the test_sp/logs/coverage_source directory.  Grep for lines starting
+see the test_sc/logs directory.  Grep for lines starting
 with '%' to see what lines Verilator believes need more coverage.
 
 =item Where is the translate_off command?  (How do I ignore a construct?)
@@ -3844,7 +3808,7 @@ Major concepts by Paul Wasson and Duane Galbi.
 
 =head1 SEE ALSO
 
-L<verilator_profcfunc>, L<systemperl>, L<vcoverage>, L<make>,
+L<verilator_coverage>, L<verilator_profcfunc>, L<make>,
 
 L<verilator --help> which is the source for this document,
 
diff --git a/bin/verilator_coverage b/bin/verilator_coverage
new file mode 100755
index 0000000..33bce7c
--- /dev/null
+++ b/bin/verilator_coverage
@@ -0,0 +1,291 @@
+: # -*-Mode: perl;-*- use perl, wherever it is
+eval 'exec perl -wS $0 ${1+"$@"}'
+  if 0;
+######################################################################
+#
+# Copyright 2003-2014 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.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+######################################################################
+
+require 5.006_001;
+use warnings;
+BEGIN {
+    if ($ENV{DIRPROJECT} && $ENV{DIRPROJECT_PERL_BOOT}) {
+	# Magic to allow author testing of perl packages in local directory
+	require $ENV{DIRPROJECT}."/".$ENV{DIRPROJECT_PERL_BOOT};
+    }
+}
+
+use Getopt::Long;
+use FindBin qw($RealBin $RealScript);
+use IO::File;
+use Pod::Usage;
+use Cwd qw(abs_path getcwd);
+
+use strict;
+use vars qw ($Debug @Opt_Verilator_Sw);
+
+#######################################################################
+#######################################################################
+# main
+
+autoflush STDOUT 1;
+autoflush STDERR 1;
+
+$Debug = 0;
+
+# No arguments can't do anything useful.  Give help
+if ($#ARGV < 0) {
+    pod2usage(-exitstatus=>2, -verbose=>0);
+}
+
+# We sneak a look at the flags so we can do some pre-environment checks
+# All flags will hit verilator...
+foreach my $sw (@ARGV) {
+    $sw = "'$sw'" if $sw =~ m![^---a-zA-Z0-9_/\\:.+]!;
+    push @Opt_Verilator_Sw, $sw;
+}
+
+Getopt::Long::config ("no_auto_abbrev","pass_through");
+if (! GetOptions (
+	  # Major operating modes
+	  "help"	=> \&usage,
+	  "debug:s"	=> \&debug,
+	  # "version!"	=> \&version,	# Also passthru'ed
+	  # Additional parameters
+	  "<>"		=> sub {},	# Ignored
+    )) {
+    pod2usage(-exitstatus=>2, -verbose=>0);
+}
+
+# Normal, non gdb
+run (verilator_coverage_bin()
+     ." ".join(' ', at Opt_Verilator_Sw));
+
+#----------------------------------------------------------------------
+
+sub usage {
+    pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
+}
+
+sub debug {
+    shift;
+    my $level = shift;
+    $Debug = $level||3;
+}
+
+#######################################################################
+#######################################################################
+# Builds
+
+sub verilator_coverage_bin {
+    my $bin = "";
+    # Use VERILATOR_ROOT if defined, else assume verilator_bin is in the search path
+    my $basename = ($ENV{VERILATOR_COVERAGE_BIN}
+		    || "verilator_coverage_bin_dbg");
+    if (defined($ENV{VERILATOR_ROOT})) {
+	my $dir = $ENV{VERILATOR_ROOT};
+	if (-x "$dir/bin/$basename") {  # From a "make install" into VERILATOR_ROOT
+	    $bin = "$dir/bin/$basename";
+	} else {
+	    $bin = "$dir/$basename";  # From pointing to kit directory
+	}
+    } else {
+	if (-x "$RealBin/$basename") {
+	    $bin = "$RealBin/$basename";  # From path/to/verilator with verilator_bin installed
+	} else {
+	    $bin = $basename;  # Find in PATH
+	}
+	# Note we don't look under bin/$basename which would be right if running
+	# in the kit dir. Running that would likely break, since
+	# VERILATOR_ROOT wouldn't be set and Verilator won't find internal files.
+    }
+    return $bin;
+}
+
+#######################################################################
+#######################################################################
+# Utilities
+
+sub run {
+    # Run command, check errors
+    my $command = shift;
+    $! = undef;  # Cleanup -x
+    print "\t$command\n" if $Debug>=3;
+    system($command);
+    my $status = $?;
+    if ($status) {
+	if ($! =~ /no such file or directory/i) {
+	    warn "%Error: verilator_coverage: Misinstalled, or VERILATOR_ROOT might need to be in environment\n";
+	}
+	if ($Debug) {  # For easy rerunning
+	    warn "%Error: export VERILATOR_ROOT=".($ENV{VERILATOR_ROOT}||"")."\n";
+	    warn "%Error: $command\n";
+	}
+	if ($status & 127) {
+	    if (($status & 127) == 8 || ($status & 127) == 11) { # SIGFPA or SIGSEGV
+		warn "%Error: Verilator_coverage internal fault, sorry.\n" if !$Debug;
+	    } elsif (($status & 127) == 6) {  # SIGABRT
+		warn "%Error: Verilator_coverage aborted.\n" if !$Debug;
+	    } else {
+		warn "%Error: Verilator_coverage threw signal $status.\n" if !$Debug;
+	    }
+	}
+	die "%Error: Command Failed $command\n";
+    }
+}
+
+#######################################################################
+#######################################################################
+package main;
+__END__
+
+=pod
+
+=head1 NAME
+
+verilator_coverage - Verilator coverage analyzer
+
+=head1 SYNOPSIS
+
+    verilator_coverage --help
+    verilator_coverage --version
+
+    verilator_coverage --annotate <obj>
+
+    verilator_coverage  -write merged.dat -read <datafiles>...
+
+Verilator_coverage processes Verilator coverage reports.
+
+With --anotate, it reads the specified data file and generates annotated
+source code with coverage metrics annotated.  If multiple coverage points
+exist on the same line, additional lines will be inserted to report the
+additional points.
+
+Additional Verilog-standard arguments specify the search paths necessary to
+find the source code that the coverage analysis was performed on.
+
+To get correct coverage percentages, you may wish to read logs/coverage.pl
+into Emacs and do a M-x keep-lines to include only those statistics of
+interest.
+
+For Verilog conditions that should never occur, you should add a $stop
+statement.  This will remove the coverage during the next build.
+
+=head1 ARGUMENTS
+
+=over 4
+
+=item I<filename>
+
+Specify input data file, may be repeated to read multiple inputs.  If no
+data file is specified, by default coverage.dat is read.
+
+=item --annotate I<output_directory>
+
+Sprcifies the directory name that source files with annotated coverage data
+should be written to.
+
+=item --annotate-all
+
+Specifies all files should be shown.  By default, only those source files
+which have low coverage are written to the output directory.
+
+=item --annotate-min I<count>
+
+Specifies the minimum occurrence count that should be flagged if the
+coverage point does not include a specified threshold.  Defaults to 10.
+
+=item --help
+
+Displays this message and program version and exits.
+
+=item --rank
+
+Print an experimental report listing the relative importance of each test
+in covering all of the coverage points.  The report shows "Covered" which
+indicates the number of points that test covers; a test is considered to
+cover a point if it has a bucket count of at least 1. The "rank" column has
+a higher number t indicate the test is more important, and rank 0 means the
+test does not need to be run to cover the points.  "RankPts" indicates the
+number of coverage points this test will contribute to overall coverage if
+all tests are run in the order of highest to lowest rank.
+
+=item --unlink
+
+When using --write to combine coverage data, unlink all input files after
+the output has been created.
+
+=item --version
+
+Displays program version and exits.
+
+=item --write I<filename>
+
+Specifies the aggregate coverage results, summed across all the files,
+should be written to the given filename.  This is useful in scripts to
+combine many sequential runs into one master coverage file.
+
+=back
+
+=head1 VERILOG ARGUMENTS
+
+The following arguments are compatible with GCC, VCS and most Verilog
+programs.
+
+=over 4
+
+=item +libext+I<ext>+I<ext>...
+
+Defines the extensions for Verilog files.
+
+=item +define+I<var>+I<value>
+=item -DI<var>=I<value>
+
+Defines the given variable.
+
+=item +incdir+I<dir>
+=item -II<dir>
+
+Specifies a directory for finding include files.
+
+=item -f I<file>
+
+Specifies a file containing additional command line arguments.
+
+=item -y I<dir>
+
+Specifies a module search directory.
+
+=back
+
+=head1 DISTRIBUTION
+
+The latest version is available from L<http://www.veripool.org/>.
+
+Copyright 2003-2014 by Wilson Snyder.  Verilator is free software; you can
+redistribute it and/or modify the Verilator internals under the terms of
+either the GNU Lesser General Public License Version 3 or the Perl Artistic
+License Version 2.0.
+
+=head1 AUTHORS
+
+Wilson Snyder <wsnyder at wsnyder.org>
+
+=head1 SEE ALSO
+
+C<verilator>
+
+L<verilator_coverage --help> which is the source for this document.
+
+=cut
+
+######################################################################
diff --git a/bin/verilator_includer b/bin/verilator_includer
index 28d50c8..59bf66f 100755
--- a/bin/verilator_includer
+++ b/bin/verilator_includer
@@ -12,5 +12,9 @@ require 5.005;
 use warnings;
 print "// DESCR"."IPTION: Generated by verilator_includer via makefile\n";
 foreach my $param (@ARGV) {
-    print "#include \"$param\"\n"
+    if ($param =~ /^-D([^=]+)=(.*)/) {
+	print "#define $1 $2\n"
+    } else {
+	print "#include \"$param\"\n"
+    }
 }
diff --git a/configure b/configure
index 2d8c517..c72e84d 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.866 2014-11-15.
+# Generated by GNU Autoconf 2.68 for Verilator 3.868 2014-12-20.
 #
 #
 # 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.866 2014-11-15'
-PACKAGE_STRING='Verilator 3.866 2014-11-15'
+PACKAGE_VERSION='3.868 2014-12-20'
+PACKAGE_STRING='Verilator 3.868 2014-12-20'
 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.866 2014-11-15 to adapt to many kinds of systems.
+\`configure' configures Verilator 3.868 2014-12-20 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.866 2014-11-15:";;
+     short | recursive ) echo "Configuration of Verilator 3.868 2014-12-20:";;
    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.866 2014-11-15
+Verilator configure 3.868 2014-12-20
 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.866 2014-11-15, which was
+It was created by Verilator $as_me 3.868 2014-12-20, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -4625,7 +4625,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.866 2014-11-15, which was
+This file was extended by Verilator $as_me 3.868 2014-12-20, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4687,7 +4687,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.866 2014-11-15
+Verilator config.status 3.868 2014-12-20
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/configure.ac b/configure.ac
index 21386f3..66111de 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.866 2014-11-15])
+AC_INIT([Verilator],[3.868 2014-12-20])
 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/doxygen.config b/doxygen.config
index 8fb0072..9a29b3c 100644
--- a/doxygen.config
+++ b/doxygen.config
@@ -635,9 +635,7 @@ INPUT                  = doxygen-mainpage \
                          test_c \
                          test_regress \
                          test_sc \
-                         test_sp \
                          test_v \
-                         test_vcs \
                          test_verilated
 
 # This tag can be used to specify the character encoding of the source files
diff --git a/include/verilated.cpp b/include/verilated.cpp
index eca6b49..af0c0a4 100644
--- a/include/verilated.cpp
+++ b/include/verilated.cpp
@@ -343,6 +343,12 @@ void _vl_vsformat(string& output, const char* formatp, va_list ap) {
 		output += cstrp;
 		break;
 	    }
+	    case '@': { // Verilog/C++ string
+		va_arg(ap, int);  // # bits is ignored
+		const string* cstrp = va_arg(ap, const string*);
+		output += *cstrp;
+		break;
+	    }
 	    case 'e':
 	    case 'f':
 	    case 'g': {
@@ -762,6 +768,50 @@ void VL_FCLOSE_I(IData fdi) {
     VerilatedImp::fdDelete(fdi);
 }
 
+void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...) {
+    VL_STATIC_OR_THREAD string output;  // static only for speed
+    output = "";
+    va_list ap;
+    va_start(ap,formatp);
+    _vl_vsformat(output, formatp, ap);
+    va_end(ap);
+
+    _VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
+}
+
+void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...) {
+    VL_STATIC_OR_THREAD string output;  // static only for speed
+    output = "";
+    va_list ap;
+    va_start(ap,formatp);
+    _vl_vsformat(output, formatp, ap);
+    va_end(ap);
+
+    _VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
+}
+
+void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...) {
+    VL_STATIC_OR_THREAD string output;  // static only for speed
+    output = "";
+    va_list ap;
+    va_start(ap,formatp);
+    _vl_vsformat(output, formatp, ap);
+    va_end(ap);
+
+    _VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
+}
+
+void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...) {
+    VL_STATIC_OR_THREAD string output;  // static only for speed
+    output = "";
+    va_list ap;
+    va_start(ap,formatp);
+    _vl_vsformat(output, formatp, ap);
+    va_end(ap);
+
+    _VL_STRING_TO_VINT(obits, &destr, (int)output.length(), output.c_str());
+}
+
 void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...) {
     VL_STATIC_OR_THREAD string output;  // static only for speed
     output = "";
diff --git a/include/verilated.h b/include/verilated.h
index 9454f60..7dbb10c 100644
--- a/include/verilated.h
+++ b/include/verilated.h
@@ -375,6 +375,10 @@ extern IData VL_SSCANF_IIX(int lbits, IData ld, const char* formatp, ...);
 extern IData VL_SSCANF_IQX(int lbits, QData ld, const char* formatp, ...);
 extern IData VL_SSCANF_IWX(int lbits, WDataInP lwp, const char* formatp, ...);
 
+extern void VL_SFORMAT_X(int obits, CData& destr, const char* formatp, ...);
+extern void VL_SFORMAT_X(int obits, SData& destr, const char* formatp, ...);
+extern void VL_SFORMAT_X(int obits, IData& destr, const char* formatp, ...);
+extern void VL_SFORMAT_X(int obits, QData& destr, const char* formatp, ...);
 extern void VL_SFORMAT_X(int obits, void* destp, const char* formatp, ...);
 
 extern IData VL_SYSTEM_IW(int lhsnwords, WDataInP lhs);
diff --git a/include/verilated.mk.in b/include/verilated.mk.in
index 87feb6d..9412f9c 100644
--- a/include/verilated.mk.in
+++ b/include/verilated.mk.in
@@ -23,7 +23,9 @@ CFG_CXXFLAGS_NO_UNUSED = @CFG_CXXFLAGS_NO_UNUSED@
 # Programs
 
 SP_PREPROC	= sp_preproc
-SP_INCLUDER     = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
+SP_INCLUDER	= $(VERILATOR_INCLUDER)
+VERILATOR_COVERAGE = $(PERL) $(VERILATOR_ROOT)/bin/verilator_coverage
+VERILATOR_INCLUDER = $(PERL) $(VERILATOR_ROOT)/bin/verilator_includer
 
 ######################################################################
 # Make checks
@@ -151,15 +153,15 @@ VK_USER_OBJS   = $(addsuffix .o, $(VM_USER_CLASSES))
 
 VK_GLOBAL_OBJS = $(addsuffix .o, $(VM_GLOBAL_FAST) $(VM_GLOBAL_SLOW))
 
-ifneq ($(VM_PARALLEL_BUILDS),1)
+ifneq ($(VM_PARALLEL_BUILDS),0)
   # Fast building, all .cpp's in one fell swoop
   # This saves about 5 sec per module, but can be slower if only a little changes
   VK_OBJS += $(VM_PREFIX)__ALLcls.o   $(VM_PREFIX)__ALLsup.o
   all_cpp:   $(VM_PREFIX)__ALLcls.cpp $(VM_PREFIX)__ALLsup.cpp
   $(VM_PREFIX)__ALLcls.cpp: $(VK_CLASSES_CPP)
-	$(SP_INCLUDER) $^ > $@
+	$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
   $(VM_PREFIX)__ALLsup.cpp: $(VK_SUPPORT_CPP)
-	$(SP_INCLUDER) $^ > $@
+	$(VERILATOR_INCLUDER) -DVL_INCLUDE_OPT=include $^ > $@
 else
   #Slow way of building... Each .cpp file by itself
   VK_OBJS += $(addsuffix .o, $(VM_CLASSES) $(VM_SUPPORT))
diff --git a/include/verilated_config.h b/include/verilated_config.h
index 1bbe02c..2f86a87 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.866 2014-11-15"
+#define VERILATOR_VERSION    "3.868 2014-12-20"
diff --git a/include/verilated_cov.cpp b/include/verilated_cov.cpp
new file mode 100644
index 0000000..9091277
--- /dev/null
+++ b/include/verilated_cov.cpp
@@ -0,0 +1,451 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//=============================================================================
+//
+// THIS MODULE IS PUBLICLY LICENSED
+//
+// Copyright 2001-2014 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.
+//
+// This is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+//=============================================================================
+///
+/// \file
+/// \brief Verilator coverage analysis
+///
+/// AUTHOR:  Wilson Snyder
+///
+//=============================================================================
+
+#include "verilatedos.h"
+#include "verilated.h"
+#include "verilated_cov.h"
+#include "verilated_cov_key.h"
+
+#include <map>
+#include <deque>
+#include <fstream>
+
+//=============================================================================
+// VerilatedCovImpBase
+/// Implementation base class for constants
+
+struct VerilatedCovImpBase {
+    // TYPES
+    enum { MAX_KEYS = 33 };		/// Maximum user arguments + filename+lineno
+    enum { KEY_UNDEF = 0 };		/// Magic key # for unspecified values
+};
+
+//=============================================================================
+// VerilatedCovImpItem
+/// Implementation class for a VerilatedCov item
+
+class VerilatedCovImpItem : VerilatedCovImpBase {
+public:  // But only local to this file
+    // MEMBERS
+    int	m_keys[MAX_KEYS];		///< Key
+    int	m_vals[MAX_KEYS];		///< Value for specified key
+    // CONSTRUCTORS
+    // Derived classes should call zero() in their constructor
+    VerilatedCovImpItem() {
+	for (int i=0; i<MAX_KEYS; i++) m_keys[i]=KEY_UNDEF;
+    }
+    virtual ~VerilatedCovImpItem() {}
+    virtual vluint64_t count() const = 0;
+    virtual void zero() const = 0;
+};
+
+//=============================================================================
+/// VerilatedCoverItem templated for a specific class
+/// Creates a new coverage item for the specified type.
+/// This isn't in the header file for auto-magic conversion because it
+/// inlines to too much code and makes compilation too slow.
+
+template <class T> class VerilatedCoverItemSpec : public VerilatedCovImpItem {
+private:
+    // MEMBERS
+    T*	m_countp;	///< Count value
+public:
+    // METHODS
+    virtual vluint64_t count() const { return *m_countp; }
+    virtual void zero() const { *m_countp = 0; }
+    // CONSTRUCTORS
+    VerilatedCoverItemSpec(T* countp) : m_countp(countp) { zero(); }
+    virtual ~VerilatedCoverItemSpec() {}
+};
+
+//=============================================================================
+// VerilatedCovImp
+/// Implementation class for VerilatedCov.  See that class for public method information.
+/// All value and keys are indexed into a unique number.  Thus we can greatly reduce
+/// the storage requirements for otherwise identical keys.
+
+class VerilatedCovImp : VerilatedCovImpBase {
+private:
+    // TYPES
+    typedef map<string,int> ValueIndexMap;
+    typedef map<int,string> IndexValueMap;
+    typedef deque<VerilatedCovImpItem*> ItemList;
+
+private:
+    // MEMBERS
+    ValueIndexMap	m_valueIndexes;		///< For each key/value a unique arbitrary index value
+    IndexValueMap	m_indexValues;		///< For each key/value a unique arbitrary index value
+    ItemList		m_items;		///< List of all items
+
+    VerilatedCovImpItem*	m_insertp;	///< Item about to insert
+    const char*		m_insertFilenamep;	///< Filename about to insert
+    int			m_insertLineno;		///< Line number about to insert
+
+    // CONSTRUCTORS
+    VerilatedCovImp() {
+	m_insertp = NULL;
+	m_insertFilenamep = NULL;
+	m_insertLineno = 0;
+    }
+public:
+    ~VerilatedCovImp() { clear(); }
+    static VerilatedCovImp& imp() {
+	static VerilatedCovImp s_singleton;
+	return s_singleton;
+    }
+
+private:
+    // PRIVATE METHODS
+    int valueIndex(const string& value) {
+	static int nextIndex = KEY_UNDEF+1;
+	ValueIndexMap::iterator iter = m_valueIndexes.find(value);
+	if (iter != m_valueIndexes.end()) return iter->second;
+	nextIndex++;  assert(nextIndex>0);
+	m_valueIndexes.insert(make_pair(value, nextIndex));
+	m_indexValues.insert(make_pair(nextIndex, value));
+	return nextIndex;
+    }
+    string dequote(const string& text) {
+	// Quote any special characters
+	string rtn;
+	for (const char* pos = text.c_str(); *pos; pos++) {
+	    if (!isprint(*pos) || *pos=='%' || *pos=='"') {
+		char hex[10]; sprintf(hex,"%%%02X",pos[0]);
+		rtn += hex;
+	    } else {
+		rtn += *pos;
+	    }
+	}
+	return rtn;
+    }
+    bool legalKey(const string& key) {
+	// Because we compress long keys to a single letter, and
+	// don't want applications to either get confused if they use
+	// a letter differently, nor want them to rely on our compression...
+	// (Considered using numeric keys, but will remain back compatible.)
+	if (key.length()<2) return false;
+	if (key.length()==2 && isdigit(key[1])) return false;
+	return true;
+    }
+    string keyValueFormatter (const string& key, const string& value) {
+	string name;
+	if (key.length()==1 && isalpha(key[0])) {
+	    name += string("\001")+key;
+	} else {
+	    name += string("\001")+dequote(key);
+	}
+	name += string("\002")+dequote(value);
+	return name;
+    }
+    string combineHier (const string& old, const string& add) {
+	// (foo.a.x, foo.b.x) => foo.*.x
+	// (foo.a.x, foo.b.y) => foo.*
+	// (foo.a.x, foo.b)   => foo.*
+	if (old == add) return add;
+	if (old == "") return add;
+	if (add == "") return old;
+
+	const char* a = old.c_str();
+	const char* b = add.c_str();
+
+	// Scan forward to first mismatch
+	const char* apre = a;
+	const char* bpre = b;
+	while (*apre == *bpre) { apre++; bpre++; }
+
+	// We used to backup and split on only .'s but it seems better to be verbose
+	// and not assume . is the separator
+	string prefix = string(a,apre-a);
+
+	// Scan backward to last mismatch
+	const char* apost = a+strlen(a)-1;
+	const char* bpost = b+strlen(b)-1;
+	while (*apost == *bpost
+	       && apost>apre && bpost>bpre) { apost--; bpost--; }
+
+	// Forward to . so we have a whole word
+	string suffix = *bpost ? string(bpost+1) : "";
+
+	string out = prefix+"*"+suffix;
+
+	//cout << "\nch pre="<<prefix<<"  s="<<suffix<<"\nch a="<<old<<"\nch b="<<add<<"\nch o="<<out<<endl;
+	return out;
+    }
+    bool itemMatchesString(VerilatedCovImpItem* itemp, const string& match) {
+	for (int i=0; i<MAX_KEYS; i++) {
+	    if (itemp->m_keys[i] != KEY_UNDEF) {
+		// We don't compare keys, only values
+		string val = m_indexValues[itemp->m_vals[i]];
+		if (string::npos != val.find(match)) {  // Found
+		    return true;
+		}
+	    }
+	}
+	return false;
+    }
+    void selftest() {
+	// Little selftest
+	if (combineHier ("a.b.c","a.b.c")	!="a.b.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("a.b.c","a.b")		!="a.b*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("a.x.c","a.y.c")	!="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("a.z.z.z.c","a.b.c")	!="a.*.c") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("z","a")		!="*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("q.a","q.b")		!="q.*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("q.za","q.zb")		!="q.z*") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+	if (combineHier ("1.2.3.a","9.8.7.a")	!="*.a") vl_fatal(__FILE__,__LINE__,"","%Error: selftest\n");
+    }
+
+public:
+    // PUBLIC METHODS
+    void clear() {
+	for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
+	    VerilatedCovImpItem* itemp = *(it);
+	    delete itemp;
+	}
+	m_items.clear();
+	m_indexValues.clear();
+	m_valueIndexes.clear();
+    }
+    void clearNonMatch (const char* matchp) {
+	if (matchp && matchp[0]) {
+	    ItemList newlist;
+	    for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
+		VerilatedCovImpItem* itemp = *(it);
+		if (!itemMatchesString(itemp, matchp)) {
+		    delete itemp;
+		} else {
+		    newlist.push_back(itemp);
+		}
+	    }
+	    m_items = newlist;
+	}
+    }
+    void zero() {
+	for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
+	    (*it)->zero();
+	}
+    }
+
+    // We assume there's always call to i/f/p in that order
+    void inserti (VerilatedCovImpItem* itemp) {
+	assert(!m_insertp);
+ 	m_insertp = itemp;
+    }
+    void insertf (const char* filenamep, int lineno) {
+	m_insertFilenamep = filenamep;
+	m_insertLineno = lineno;
+    }
+    void insertp (const char* ckeyps[MAX_KEYS],
+		  const char* valps[MAX_KEYS]) {
+	assert(m_insertp);
+	// First two key/vals are filename
+	ckeyps[0]="filename";	valps[0]=m_insertFilenamep;
+	VlCovCvtToCStr linestrp (m_insertLineno);
+	ckeyps[1]="lineno";	valps[1]=linestrp;
+	// Default page if not specified
+	const char* fnstartp = m_insertFilenamep;
+	while (const char* foundp = strchr(fnstartp,'/')) fnstartp=foundp+1;
+	const char* fnendp = fnstartp;
+	while (*fnendp && *fnendp!='.') fnendp++;
+	string page_default = "sp_user/"+string(fnstartp,fnendp-fnstartp);
+	ckeyps[2]="page";	valps[2]=page_default.c_str();
+
+	// Keys -> strings
+	string keys[MAX_KEYS];
+	for (int i=0; i<MAX_KEYS; i++) {
+	    if (ckeyps[i] && ckeyps[i][0]) {
+		keys[i] = ckeyps[i];
+	    }
+	}
+	// Ignore empty keys
+	for (int i=0; i<MAX_KEYS; i++) {
+	    if (keys[i]!="") {
+		for (int j=i+1; j<MAX_KEYS; j++) {
+		    if (keys[i] == keys[j]) {  // Duplicate key.  Keep the last one
+			keys[i] = "";
+			break;
+		    }
+		}
+	    }
+	}
+	// Insert the values
+	int addKeynum=0;
+	for (int i=0; i<MAX_KEYS; i++) {
+	    const string key = keys[i];
+	    if (keys[i]!="") {
+		const string val = valps[i];
+		//cout<<"   "<<__FUNCTION__<<"  "<<key<<" = "<<val<<endl;
+		m_insertp->m_keys[addKeynum] = valueIndex(key);
+		m_insertp->m_vals[addKeynum] = valueIndex(val);
+		addKeynum++;
+		if (!legalKey(key)) {
+		    string msg = "%Error: Coverage keys of one character, or letter+digit are illegal: "+key;
+		    vl_fatal("",0,"",msg.c_str());
+		}
+	    }
+	}
+	m_items.push_back(m_insertp);
+	// Prepare for next
+	m_insertp = NULL;
+    }
+
+    void write (const char* filename) {
+#ifndef VM_COVERAGE
+	vl_fatal("",0,"","%Error: Called VerilatedCov::write when VM_COVERAGE disabled\n");
+#endif
+	selftest();
+
+	ofstream os (filename);
+	if (os.fail()) {
+	    string msg = (string)"%Error: Can't write '"+filename+"'";
+	    vl_fatal("",0,"",msg.c_str());
+	    return;
+	}
+	os << "# SystemC::Coverage-3\n";
+
+	// Build list of events; totalize if collapsing hierarchy
+	typedef map<string,pair<string,vluint64_t> >	EventMap;
+	EventMap	eventCounts;
+	for (ItemList::iterator it=m_items.begin(); it!=m_items.end(); ++it) {
+	    VerilatedCovImpItem* itemp = *(it);
+	    string name;
+	    string hier;
+	    bool per_instance = false;
+
+	    for (int i=0; i<MAX_KEYS; i++) {
+		if (itemp->m_keys[i] != KEY_UNDEF) {
+		    string key = VerilatedCovKey::shortKey(m_indexValues[itemp->m_keys[i]]);
+		    string val = m_indexValues[itemp->m_vals[i]];
+		    if (key == VL_CIK_PER_INSTANCE) {
+			if (val != "0") per_instance = true;
+		    }
+		    if (key == VL_CIK_HIER) {
+			hier = val;
+		    } else {
+			// Print it
+			name += keyValueFormatter(key,val);
+		    }
+		}
+	    }
+	    if (per_instance) {  // Not collapsing hierarchies
+		name += keyValueFormatter(VL_CIK_HIER,hier);
+		hier = "";
+	    }
+
+	    // Group versus point labels don't matter here, downstream
+	    // deals with it.  Seems bad for sizing though and doesn't
+	    // allow easy addition of new group codes (would be
+	    // inefficient)
+
+	    // Find or insert the named event
+	    EventMap::iterator cit = eventCounts.find(name);
+	    if (cit != eventCounts.end()) {
+		const string& oldhier = cit->second.first;
+		cit->second.second += itemp->count();
+		cit->second.first  = combineHier(oldhier, hier);
+	    } else {
+		eventCounts.insert(make_pair(name, make_pair(hier,itemp->count())));
+	    }
+	}
+
+	// Output body
+	for (EventMap::iterator it=eventCounts.begin(); it!=eventCounts.end(); ++it) {
+	    os<<"C '"<<dec;
+	    os<<it->first;
+	    if (it->second.first != "") os<<keyValueFormatter(VL_CIK_HIER,it->second.first);
+	    os<<"' "<<it->second.second;
+	    os<<endl;
+	}
+    }
+};
+
+//=============================================================================
+// VerilatedCov
+
+void VerilatedCov::clear() {
+    VerilatedCovImp::imp().clear();
+}
+void VerilatedCov::clearNonMatch (const char* matchp) {
+    VerilatedCovImp::imp().clearNonMatch(matchp);
+}
+void VerilatedCov::zero() {
+    VerilatedCovImp::imp().zero();
+}
+void VerilatedCov::write (const char* filenamep) {
+    VerilatedCovImp::imp().write(filenamep);
+}
+void VerilatedCov::_inserti (vluint32_t* itemp) {
+    VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint32_t>(itemp));
+}
+void VerilatedCov::_inserti (vluint64_t* itemp) {
+    VerilatedCovImp::imp().inserti(new VerilatedCoverItemSpec<vluint64_t>(itemp));
+}
+void VerilatedCov::_insertf (const char* filename, int lineno) {
+    VerilatedCovImp::imp().insertf(filename,lineno);
+}
+
+#define K(n) const char* key ## n
+#define A(n) const char* key ## n, const char* val ## n		// Argument list
+#define C(n) key ## n, val ## n	// Calling argument list
+#define N(n) "",""	// Null argument list
+void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
+			     A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19),
+			     A(20),A(21),A(22),A(23),A(24),A(25),A(26),A(27),A(28),A(29)) {
+    const char* keyps[VerilatedCovImpBase::MAX_KEYS]
+	= {NULL,NULL,NULL,	// filename,lineno,page
+	   key0,key1,key2,key3,key4,key5,key6,key7,key8,key9,
+	   key10,key11,key12,key13,key14,key15,key16,key17,key18,key19,
+	   key20,key21,key22,key23,key24,key25,key26,key27,key28,key29};
+    const char* valps[VerilatedCovImpBase::MAX_KEYS]
+	= {NULL,NULL,NULL,	// filename,lineno,page
+	   val0,val1,val2,val3,val4,val5,val6,val7,val8,val9,
+	   val10,val11,val12,val13,val14,val15,val16,val17,val18,val19,
+	   val20,val21,val22,val23,val24,val25,val26,val27,val28,val29};
+    VerilatedCovImp::imp().insertp(keyps, valps);
+}
+
+// And versions with fewer arguments  (oh for a language with named parameters!)
+void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)) {
+    _insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
+	     N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
+	     N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
+}
+void VerilatedCov::_insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9),
+			     A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)) {
+    _insertp(C(0),C(1),C(2),C(3),C(4),C(5),C(6),C(7),C(8),C(9),
+	     C(10),C(11),C(12),C(13),C(14),C(15),C(16),C(17),C(18),C(19),
+	     N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
+}
+// Backward compatibility for Verilator
+void VerilatedCov::_insertp (A(0), A(1),  K(2),int val2,  K(3),int val3,
+			     K(4),const string& val4,  A(5),A(6)) {
+    _insertp(C(0),C(1),
+	     key2,VlCovCvtToCStr(val2),  key3,VlCovCvtToCStr(val3),  key4, val4.c_str(),
+	     C(5),C(6),N(7),N(8),N(9),
+	     N(10),N(11),N(12),N(13),N(14),N(15),N(16),N(17),N(18),N(19),
+	     N(20),N(21),N(22),N(23),N(24),N(25),N(26),N(27),N(28),N(29));
+}
+#undef A
+#undef C
+#undef N
+#undef K
diff --git a/include/verilated_cov.h b/include/verilated_cov.h
new file mode 100644
index 0000000..dac339d
--- /dev/null
+++ b/include/verilated_cov.h
@@ -0,0 +1,146 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//=============================================================================
+//
+// THIS MODULE IS PUBLICLY LICENSED
+//
+// Copyright 2001-2014 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.
+//
+// This is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+//=============================================================================
+///
+/// \file
+/// \brief Coverage analysis support
+///
+/// AUTHOR:  Wilson Snyder
+///
+//=============================================================================
+
+#ifndef _VERILATED_COV_H_
+#define _VERILATED_COV_H_ 1
+
+#include "verilatedos.h"
+
+#include <iostream>
+#include <sstream>
+#include <string>
+using namespace std;
+
+//=============================================================================
+/// Conditionally compile coverage code
+
+#ifdef VM_COVERAGE
+# define VL_IF_COVER(stmts) do { stmts ; } while(0)
+#else
+# define VL_IF_COVER(stmts) do { if(0) { stmts ; } } while(0)
+#endif
+
+//=============================================================================
+/// Insert a item for coverage analysis.
+/// The first argument is a pointer to the count to be dumped.
+/// The remaining arguments occur in pairs: A string key, and a value.
+/// The value may be a string, or another type which will be auto-converted to a string.
+///
+/// Some typical keys:
+///	filename	File the recording occurs in.  Defaults to __FILE__
+///	lineno		Line number the recording occurs in.  Defaults to __LINE__
+///	column		Column number (or occurrence# for dup file/lines).  Defaults to undef.
+///	hier		Hierarchical name.  Defaults to name()
+///	type		Type of coverage.  Defaults to "user"
+///			Other types are 'block', 'fsm', 'toggle'.
+///	comment		Description of the coverage event.  Should be set by the user.
+///			Comments for type==block: 'if', 'else', 'elsif', 'case'
+///	thresh		Threshold to consider fully covered.
+///			If unspecified, downstream tools will determine it.
+///
+/// Examples:
+///
+///	vluint32_t m_cases[10];
+///	constructor {
+///	    for (int i=0; i<10; i++) { m_cases[i]=0; }
+///     }
+///	for (int i=0; i<10; i++) {
+///		VL_COVER_INSERT(&m_cases[i], "comment", "Coverage Case", "i", cvtToNumStr(i));
+///	}
+
+#define VL_COVER_INSERT(countp,args...) \
+    VL_IF_COVER(VerilatedCov::_inserti(countp);	\
+		VerilatedCov::_insertf(__FILE__,__LINE__);	\
+		VerilatedCov::_insertp("hier", name(), args))
+
+//=============================================================================
+/// Convert VL_COVER_INSERT value arguments to strings
+
+template< class T> std::string vlCovCvtToStr (const T& t) {
+    ostringstream os; os<<t; return os.str();
+}
+
+/// Usage: something(VlCovCvtToCStr(i))
+/// Note the pointer will only be valid for as long as the object remains
+/// in scope!
+struct VlCovCvtToCStr {
+    string m_str;
+    // Casters
+    template< class T> VlCovCvtToCStr (const T& t) {
+	ostringstream os; os<<t; m_str=os.str();
+    }
+    ~VlCovCvtToCStr() {}
+    operator const char* () const { return m_str.c_str(); };
+};
+
+//=============================================================================
+//  VerilatedCov
+///  Verilator coverage global class
+////
+/// Global class with methods affecting all coverage data.
+
+class VerilatedCov {
+public:
+    // GLOBAL METHODS
+    /// Return default filename
+    static const char* defaultFilename() { return "coverage.dat"; }
+    /// Write all coverage data to a file
+    static void write (const char* filenamep = defaultFilename());
+    /// Insert a coverage item
+    /// We accept from 1-30 key/value pairs, all as strings.
+    /// Call _insert1, followed by _insert2 and _insert3
+    /// Do not call directly; use VL_COVER_INSERT or higher level macros instead
+    // _insert1: Remember item pointer with count.  (Not const, as may add zeroing function)
+    static void _inserti (vluint32_t* itemp);
+    static void _inserti (vluint64_t* itemp);
+    // _insert2: Set default filename and line number
+    static void _insertf (const char* filename, int lineno);
+    // _insert3: Set parameters
+    // We could have just the maximum argument version, but this compiles
+    // much slower (nearly 2x) than having smaller versions also.  However
+    // there's not much more gain in having a version for each number of args.
+#define K(n) const char* key ## n
+#define A(n) const char* key ## n, const char* valp ## n	// Argument list
+#define D(n) const char* key ## n = NULL, const char* valp ## n = NULL	// Argument list
+    static void _insertp (D(0),D(1),D(2),D(3),D(4),D(5),D(6),D(7),D(8),D(9));
+    static void _insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
+			  ,A(10),D(11),D(12),D(13),D(14),D(15),D(16),D(17),D(18),D(19));
+    static void _insertp (A(0),A(1),A(2),A(3),A(4),A(5),A(6),A(7),A(8),A(9)
+			  ,A(10),A(11),A(12),A(13),A(14),A(15),A(16),A(17),A(18),A(19)
+			  ,A(20),D(21),D(22),D(23),D(24),D(25),D(26),D(27),D(28),D(29));
+    // Backward compatibility for Verilator
+    static void _insertp (A(0), A(1),  K(2),int val2,  K(3),int val3,
+			  K(4),const string& val4,  A(5),A(6));
+
+#undef K
+#undef A
+#undef D
+    /// Clear coverage points (and call delete on all items)
+    static void clear();
+    /// Clear items not matching the provided string
+    static void clearNonMatch (const char* matchp);
+    /// Zero coverage points
+    static void zero();
+};
+
+#endif // guard
diff --git a/include/verilated_cov_key.h b/include/verilated_cov_key.h
new file mode 100644
index 0000000..3276a4a
--- /dev/null
+++ b/include/verilated_cov_key.h
@@ -0,0 +1,147 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//=============================================================================
+//
+// THIS MODULE IS PUBLICLY LICENSED
+//
+// Copyright 2001-2014 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.
+//
+// This is distributed in the hope that it will be useful, but WITHOUT ANY
+// WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// for more details.
+//
+//=============================================================================
+///
+/// \file
+/// \brief Coverage item keys
+///
+/// AUTHOR:  Wilson Snyder
+///
+//=============================================================================
+
+#ifndef _VERILATED_COV_KEY_H_
+#define _VERILATED_COV_KEY_H_ 1
+
+#include "verilatedos.h"
+
+#include <string>
+using namespace std;
+
+//=============================================================================
+// Data used to edit below file, using vlcovgen
+
+#define VLCOVGEN_ITEM(string_parsed_by_vlcovgen)
+
+VLCOVGEN_ITEM("name=>'col0_name',   short=>'C0', group=>1, default=>undef, descr=>'The column title for the header line of this column'")
+VLCOVGEN_ITEM("name=>'col1_name',   short=>'C1', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'col2_name',   short=>'C2', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'col3_name',   short=>'C3', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'column',      short=>'n',  group=>1, default=>0,     descr=>'Column number for the item.  Used to disambiguate multiple coverage points on the same line number'")
+VLCOVGEN_ITEM("name=>'filename',    short=>'f',  group=>1, default=>undef, descr=>'Filename of the item'")
+VLCOVGEN_ITEM("name=>'groupdesc',   short=>'d',  group=>1, default=>'',    descr=>'Description of the covergroup this item belongs to'")
+VLCOVGEN_ITEM("name=>'groupname',   short=>'g',  group=>1, default=>'',    descr=>'Group name of the covergroup this item belongs to'")
+VLCOVGEN_ITEM("name=>'groupcmt',    short=>'O',  group=>1, default=>'',    ")
+VLCOVGEN_ITEM("name=>'per_instance',short=>'P',  group=>1, default=>0,     descr=>'True if every hierarchy is independently counted; otherwise all hierarchies will be combined into a single count'")
+VLCOVGEN_ITEM("name=>'row0_name',   short=>'R0', group=>1, default=>undef, descr=>'The row title for the header line of this row'")
+VLCOVGEN_ITEM("name=>'row1_name',   short=>'R1', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'row2_name',   short=>'R2', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'row3_name',   short=>'R3', group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'table',       short=>'T',  group=>1, default=>undef, descr=>'The name of the table for automatically generated tables'")
+VLCOVGEN_ITEM("name=>'thresh',      short=>'s',  group=>1, default=>undef, ")
+VLCOVGEN_ITEM("name=>'type',        short=>'t',  group=>1, default=>'',    descr=>'Type of coverage (block, line, fsm, etc)'")
+// Bin attributes
+VLCOVGEN_ITEM("name=>'col0',        short=>'c0', group=>0, default=>undef, descr=>'The (enumeration) value name for this column in a table cross' ")
+VLCOVGEN_ITEM("name=>'col1',        short=>'c1', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'col2',        short=>'c2', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'col3',        short=>'c3', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'comment',     short=>'o',  group=>0, default=>'',    descr=>'Textual description for the item'")
+VLCOVGEN_ITEM("name=>'hier',        short=>'h',  group=>0, default=>'',    descr=>'Hierarchy path name for the item'")
+VLCOVGEN_ITEM("name=>'limit',       short=>'L',  group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'lineno',      short=>'l',  group=>0, default=>0,     descr=>'Line number for the item'")
+VLCOVGEN_ITEM("name=>'row0',        short=>'r0', group=>0, default=>undef, descr=>'The (enumeration) value name for this row in a table cross'")
+VLCOVGEN_ITEM("name=>'row1',        short=>'r1', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'row2',        short=>'r2', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'row3',        short=>'r3', group=>0, default=>undef, ")
+VLCOVGEN_ITEM("name=>'weight',      short=>'w',  group=>0, default=>undef, descr=>'For totaling items, weight of this item'")
+
+//=============================================================================
+//  VerilatedCovKey
+///  Verilator coverage global class
+////
+/// Global class with methods affecting all coverage data.
+
+// VLCOVGEN_CIK_AUTO_EDIT_BEGIN
+#define VL_CIK_COL0 "c0"
+#define VL_CIK_COL0_NAME "C0"
+#define VL_CIK_COL1 "c1"
+#define VL_CIK_COL1_NAME "C1"
+#define VL_CIK_COL2 "c2"
+#define VL_CIK_COL2_NAME "C2"
+#define VL_CIK_COL3 "c3"
+#define VL_CIK_COL3_NAME "C3"
+#define VL_CIK_COLUMN "n"
+#define VL_CIK_COMMENT "o"
+#define VL_CIK_FILENAME "f"
+#define VL_CIK_GROUPCMT "O"
+#define VL_CIK_GROUPDESC "d"
+#define VL_CIK_GROUPNAME "g"
+#define VL_CIK_HIER "h"
+#define VL_CIK_LIMIT "L"
+#define VL_CIK_LINENO "l"
+#define VL_CIK_PER_INSTANCE "P"
+#define VL_CIK_ROW0 "r0"
+#define VL_CIK_ROW0_NAME "R0"
+#define VL_CIK_ROW1 "r1"
+#define VL_CIK_ROW1_NAME "R1"
+#define VL_CIK_ROW2 "r2"
+#define VL_CIK_ROW2_NAME "R2"
+#define VL_CIK_ROW3 "r3"
+#define VL_CIK_ROW3_NAME "R3"
+#define VL_CIK_TABLE "T"
+#define VL_CIK_THRESH "s"
+#define VL_CIK_TYPE "t"
+#define VL_CIK_WEIGHT "w"
+// VLCOVGEN_CIK_AUTO_EDIT_END
+
+class VerilatedCovKey {
+public:
+    static string shortKey(const string& key) {
+	// VLCOVGEN_SHORT_AUTO_EDIT_BEGIN
+	if (key == "col0") return VL_CIK_COL0;
+	if (key == "col0_name") return VL_CIK_COL0_NAME;
+	if (key == "col1") return VL_CIK_COL1;
+	if (key == "col1_name") return VL_CIK_COL1_NAME;
+	if (key == "col2") return VL_CIK_COL2;
+	if (key == "col2_name") return VL_CIK_COL2_NAME;
+	if (key == "col3") return VL_CIK_COL3;
+	if (key == "col3_name") return VL_CIK_COL3_NAME;
+	if (key == "column") return VL_CIK_COLUMN;
+	if (key == "comment") return VL_CIK_COMMENT;
+	if (key == "filename") return VL_CIK_FILENAME;
+	if (key == "groupcmt") return VL_CIK_GROUPCMT;
+	if (key == "groupdesc") return VL_CIK_GROUPDESC;
+	if (key == "groupname") return VL_CIK_GROUPNAME;
+	if (key == "hier") return VL_CIK_HIER;
+	if (key == "limit") return VL_CIK_LIMIT;
+	if (key == "lineno") return VL_CIK_LINENO;
+	if (key == "per_instance") return VL_CIK_PER_INSTANCE;
+	if (key == "row0") return VL_CIK_ROW0;
+	if (key == "row0_name") return VL_CIK_ROW0_NAME;
+	if (key == "row1") return VL_CIK_ROW1;
+	if (key == "row1_name") return VL_CIK_ROW1_NAME;
+	if (key == "row2") return VL_CIK_ROW2;
+	if (key == "row2_name") return VL_CIK_ROW2_NAME;
+	if (key == "row3") return VL_CIK_ROW3;
+	if (key == "row3_name") return VL_CIK_ROW3_NAME;
+	if (key == "table") return VL_CIK_TABLE;
+	if (key == "thresh") return VL_CIK_THRESH;
+	if (key == "type") return VL_CIK_TYPE;
+	if (key == "weight") return VL_CIK_WEIGHT;
+	// VLCOVGEN_SHORT_AUTO_EDIT_END
+	return key;
+    }
+};
+
+#endif // guard
diff --git a/include/verilated_heavy.h b/include/verilated_heavy.h
index 940c669..3da1b20 100644
--- a/include/verilated_heavy.h
+++ b/include/verilated_heavy.h
@@ -41,13 +41,24 @@ inline string VL_CVT_PACK_STR_NQ(QData lhs) {
     IData lw[2];  VL_SET_WQ(lw, lhs);
     return VL_CVT_PACK_STR_NW(2, lw);
 }
-inline string VL_CVT_PACK_STR_NQ(string lhs) {
+inline string VL_CVT_PACK_STR_NQ(const string& lhs) {
     return lhs;
 }
 inline string VL_CVT_PACK_STR_NI(IData lhs) {
     IData lw[1];  lw[0] = lhs;
     return VL_CVT_PACK_STR_NW(1, lw);
 }
+inline string VL_CONCATN_NNN(const string& lhs, const string& rhs) {
+    return lhs+rhs;
+}
+inline string VL_REPLICATEN_NNQ(int,int,int rbits, const string& lhs, IData rep) {
+    string out; out.reserve(lhs.length() * rep);
+    for (unsigned times=0; times<rep; times++) out += lhs;
+    return out;
+}
+inline string VL_REPLICATEN_NNI(int obits,int lbits,int rbits, const string& lhs, IData rep) {
+    return VL_REPLICATEN_NNQ(obits,lbits,rbits,lhs,rep);
+}
 
 extern void VL_SFORMAT_X(int obits_ignored, string &output, const char* formatp, ...);
 extern string VL_SFORMATF_NX(const char* formatp, ...);
diff --git a/include/verilated_vcd_c.cpp b/include/verilated_vcd_c.cpp
index 8aa36e2..202e9cd 100644
--- a/include/verilated_vcd_c.cpp
+++ b/include/verilated_vcd_c.cpp
@@ -57,7 +57,7 @@ vector<VerilatedVcd*>	VerilatedVcd::s_vcdVecp;	///< List of all created traces
 // VerilatedVcdCallInfo
 /// Internal callback routines for each module being traced.
 ////
-/// Each SystemPerl module that wishes to be traced registers a set of
+/// Each module that wishes to be traced registers a set of
 /// callbacks stored in this class.  When the trace file is being
 /// constructed, this class provides the callback routines to be executed.
 
diff --git a/include/verilated_vcd_c.h b/include/verilated_vcd_c.h
index daf4c3b..228c7b2 100644
--- a/include/verilated_vcd_c.h
+++ b/include/verilated_vcd_c.h
@@ -395,7 +395,7 @@ public:
 /// Create a VCD dump file in C standalone (no SystemC) simulations.
 
 class VerilatedVcdC {
-    VerilatedVcd		m_sptrace;	///< SystemPerl trace file being created
+    VerilatedVcd		m_sptrace;	///< Trace file being created
 public:
     // CONSTRUCTORS
     VerilatedVcdC() {}
diff --git a/include/verilated_vcd_sc.cpp b/include/verilated_vcd_sc.cpp
index a6935c4..14ea6a6 100644
--- a/include/verilated_vcd_sc.cpp
+++ b/include/verilated_vcd_sc.cpp
@@ -15,7 +15,7 @@
 //=============================================================================
 ///
 /// \file
-/// \brief SystemPerl Tracing in VCD Format
+/// \brief Verilator tracing in VCD Format
 ///
 /// AUTHOR:  Wilson Snyder
 ///
diff --git a/include/verilated_vcd_sc.h b/include/verilated_vcd_sc.h
index 9ae96cd..08a6567 100644
--- a/include/verilated_vcd_sc.h
+++ b/include/verilated_vcd_sc.h
@@ -15,7 +15,7 @@
 //=============================================================================
 ///
 /// \file
-/// \brief SystemPerl tracing in VCD format
+/// \brief Verilator tracing in VCD format
 ///
 /// AUTHOR:  Wilson Snyder
 ///
diff --git a/include/verilatedos.h b/include/verilatedos.h
index c2068f1..a82eb59 100644
--- a/include/verilatedos.h
+++ b/include/verilatedos.h
@@ -106,6 +106,13 @@
 #endif
 
 //=========================================================================
+// Optimization
+
+#ifndef VL_INLINE_OPT
+# define VL_INLINE_OPT		///< "inline" if compiling all objects in single compiler run
+#endif
+
+//=========================================================================
 // Warning disabled
 
 #ifndef VL_WARNINGS
diff --git a/internals.html b/internals.html
index d2890cf..e6e1c40 100644
--- a/internals.html
+++ b/internals.html
@@ -502,10 +502,10 @@ be warning free.</p>
 <dt><strong><a name="enable_longtests" class="item">--enable-longtests</a></strong></dt>
 
 <dd>
-<p>In addition to the standard C, SystemC and SystemPerl tests also run the
-tests in the <code>test_vcs</code>, <code>test_verilated</code> and <code>test_regress</code> directories
-when using <em>make test</em>.  This is disabled by default as SystemC/SystemPerl
-installation problems would otherwise falsely indicate a Verilator problem.</p>
+<p>In addition to the standard C, SystemC tests also run the tests in the
+<code>test_verilated</code> and <code>test_regress</code> directories when using <em>make test</em>.
+This is disabled by default as SystemC installation problems would
+otherwise falsely indicate a Verilator problem.</p>
 </dd>
 </dl>
 <p>When enabling the long tests, some additional PERL modules are needed, which
@@ -515,11 +515,6 @@ you can install using cpan.</p>
 <p>There are some traps to avoid when running regression tests</p>
 <ul>
 <li>
-<p>The regression tests will assume that you have a version of SystemPerl to
-match. Typically if working on Verilator from git, also use SystemPerl from
-git.</p>
-</li>
-<li>
 <p>When checking the MANIFEST, the test will barf on unexpected code in the
 Verilator tree. So make sure to keep any such code outside the tree.</p>
 </li>
diff --git a/internals.pdf b/internals.pdf
index 1f649cf..c5d025d 100644
Binary files a/internals.pdf and b/internals.pdf differ
diff --git a/internals.pod b/internals.pod
index 1a458ba..83ae109 100644
--- a/internals.pod
+++ b/internals.pod
@@ -473,10 +473,10 @@ be warning free.
 
 =item --enable-longtests
 
-In addition to the standard C, SystemC and SystemPerl tests also run the
-tests in the C<test_vcs>, C<test_verilated> and C<test_regress> directories
-when using I<make test>.  This is disabled by default as SystemC/SystemPerl
-installation problems would otherwise falsely indicate a Verilator problem.
+In addition to the standard C, SystemC tests also run the tests in the
+C<test_verilated> and C<test_regress> directories when using I<make test>.
+This is disabled by default as SystemC installation problems would
+otherwise falsely indicate a Verilator problem.
 
 =back
 
@@ -491,12 +491,6 @@ There are some traps to avoid when running regression tests
 
 =item *
 
-The regression tests will assume that you have a version of SystemPerl to
-match. Typically if working on Verilator from git, also use SystemPerl from
-git.
-
-=item *
-
 When checking the MANIFEST, the test will barf on unexpected code in the
 Verilator tree. So make sure to keep any such code outside the tree.
 
diff --git a/internals.txt b/internals.txt
index 59626e4..b47730b 100644
--- a/internals.txt
+++ b/internals.txt
@@ -441,11 +441,10 @@ TESTING
         SystemC) may not be warning free.
 
     --enable-longtests
-        In addition to the standard C, SystemC and SystemPerl tests also run
-        the tests in the "test_vcs", "test_verilated" and "test_regress"
-        directories when using *make test*. This is disabled by default as
-        SystemC/SystemPerl installation problems would otherwise falsely
-        indicate a Verilator problem.
+        In addition to the standard C, SystemC tests also run the tests in
+        the "test_verilated" and "test_regress" directories when using *make
+        test*. This is disabled by default as SystemC installation problems
+        would otherwise falsely indicate a Verilator problem.
 
     When enabling the long tests, some additional PERL modules are needed,
     which you can install using cpan.
@@ -454,10 +453,6 @@ TESTING
 
     There are some traps to avoid when running regression tests
 
-    *   The regression tests will assume that you have a version of
-        SystemPerl to match. Typically if working on Verilator from git,
-        also use SystemPerl from git.
-
     *   When checking the MANIFEST, the test will barf on unexpected code in
         the Verilator tree. So make sure to keep any such code outside the
         tree.
diff --git a/readme.pod b/readme.pod
index d4340f0..42b87db 100644
--- a/readme.pod
+++ b/readme.pod
@@ -76,14 +76,6 @@ instead.)
 
 =item
 
-If you will be using SystemPerl or coverage, download and install
-System-Perl, L<http://www.veripool.org/systemperl>.  Note you'll need to
-set a C<SYSTEMPERL> environment variable to point to the downloaded kit.
-Optionally also set C<SYSTEMPERL_INCLUDE> to point to the installed
-headers.
-
-=item
-
 You will need the C<flex> and C<bison> packages installed.
 
 =item
@@ -95,8 +87,8 @@ C<cd> to the Verilator directory containing this README.
 You now have to decide how you're going to eventually install the kit.
 
 Note Verilator builds the current value of VERILATOR_ROOT, SYSTEMC_INCLUDE,
-SYSTEMC_LIBDIR, SYSTEMPERL, and SYSTEMPERL_INCLUDE as defaults into the
-executable, so try to have them correct before configuring.
+and SYSTEMC_LIBDIR as defaults into the executable, so try to have them
+correct before configuring.
 
 =over 4
 
@@ -198,8 +190,6 @@ The directories in the kit after de-taring are as follows:
     test_v                      => Example Verilog code for other test dirs
     test_c                      => Example Verilog->C++ conversion
     test_sc                     => Example Verilog->SystemC conversion
-    test_sp                     => Example Verilog->SystemPerl conversion
-    test_vcs                    => Example Verilog->VCS conversion (test the test)
     test_verilated              => Internal tests
     test_regress                => Internal tests
 
diff --git a/src/Makefile.in b/src/Makefile.in
index efdd7b4..4fdd7ee 100644
--- a/src/Makefile.in
+++ b/src/Makefile.in
@@ -46,7 +46,7 @@ obj_opt:
 obj_dbg:
 	mkdir $@
 
-.PHONY: ../verilator_bin ../verilator_bin_dbg
+.PHONY: ../verilator_bin ../verilator_bin_dbg ../verilator_coverage_bin_dbg
 
 opt: ../verilator_bin
 ifeq ($(VERILATOR_NO_OPT_BUILD),1)	# Faster laptop development... One build
@@ -59,11 +59,15 @@ else
 	cd obj_opt && $(MAKE)       TGT=../$@ -f ../Makefile_obj
 endif
 
-dbg: ../verilator_bin_dbg
+dbg: ../verilator_bin_dbg ../verilator_coverage_bin_dbg
 ../verilator_bin_dbg: obj_dbg prefiles
 	cd obj_dbg && $(MAKE) -j 1  TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj serial
 	cd obj_dbg && $(MAKE)       TGT=../$@ VL_DEBUG=1 -f ../Makefile_obj
 
+../verilator_coverage_bin_dbg: obj_dbg prefiles
+	cd obj_dbg && $(MAKE)       TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj serial_vlcov
+	cd obj_dbg && $(MAKE)       TGT=../$@ VL_DEBUG=1 VL_VLCOV=1 -f ../Makefile_obj
+
 prefiles::
 prefiles:: config_rev.h
 ifneq ($(UNDER_GIT),)	# If local git tree... Else don't burden users
diff --git a/src/Makefile_obj.in b/src/Makefile_obj.in
index 57685d9..786030e 100644
--- a/src/Makefile_obj.in
+++ b/src/Makefile_obj.in
@@ -127,6 +127,7 @@ HEADERS = $(wildcard V*.h v*.h)
 ASTGEN = $(srcdir)/astgen
 BISONPRE = $(srcdir)/bisonpre
 FLEXFIX = $(srcdir)/flexfix
+VLCOVGEN = $(srcdir)/vlcovgen
 
 ######################################################################
 #### Top level
@@ -186,6 +187,7 @@ RAW_OBJS = \
 	V3Error.o \
 	V3Expand.o \
 	V3File.o \
+	V3FileLine.o \
 	V3Gate.o \
 	V3GenClk.o \
 	V3Graph.o \
@@ -233,26 +235,30 @@ RAW_OBJS = \
 	V3WidthSel.o \
 
 # Non-concatable
-OBJS += \
+NC_OBJS += \
 	V3ParseImp.o \
 	V3ParseGrammar.o \
 	V3ParseLex.o \
 	V3PreProc.o \
 
+# verilator_coverage
+VLCOV_OBJS = \
+	VlcMain.o \
+
 #### Linking
 
-ifeq ($(VL_DEBUG),)
-# Building with fewer objects to better optimize
-#OBJS += V3__CONCAT.o
-OBJS += $(RAW_OBJS)
+ifeq ($(VL_VLCOV),)
+PREDEP_H = V3Ast__gen_classes.h
+OBJS += $(RAW_OBJS) $(NC_OBJS)
 else
-OBJS += $(RAW_OBJS)
+PREDEP_H =
+OBJS += $(VLCOV_OBJS)
 endif
 
 V3__CONCAT.cpp: $(addsuffix .cpp, $(basename $(RAW_OBJS)))
 	$(PERL) $(srcdir)/../bin/verilator_includer $^ > $@
 
-$(TGT): V3Ast__gen_classes.h $(OBJS)
+$(TGT): $(PREDEP_H) $(OBJS)
 	@echo "      Linking $@..."
 	-rm -rf $@ $@.exe
 	${LINK} ${LDFLAGS} -o $@ $(OBJS) $(CCMALLOC) ${LIBS}
@@ -287,6 +293,12 @@ V3PreProc.o:	V3PreProc.cpp V3PreLex.yy.cpp
 # Target rule called before parallel build to make generated files
 serial:: V3Ast__gen_classes.h V3ParseBison.c
 
+serial_vlcov:: vlcovgen.d
+
+vlcovgen.d: $(VLCOVGEN) $(srcdir)/include/verilated_cov_key.h
+	$(PERL) $(VLCOVGEN) --srcdir $(srcdir)
+	touch $@
+
 V3Ast__gen_classes.h : $(ASTGEN) V3Ast.h V3AstNodes.h
 	$(PERL) $(ASTGEN) -I$(srcdir)  --classes
 
diff --git a/src/V3Assert.cpp b/src/V3Assert.cpp
index 4163c28..c2b3dc4 100644
--- a/src/V3Assert.cpp
+++ b/src/V3Assert.cpp
@@ -131,19 +131,13 @@ private:
 		if (message!="") covincp->declp()->comment(message);
 		bodysp = covincp;
 	    }
-	} else if (nodep->castPslAssert()) {
-	    bodysp = newFireAssert(nodep,message);
-	    // We assert the property is always true... so report when it fails
-	    // (Note this is opposite the behavior of coverage statements.)
-	    // Need: 'never' operator: not hold in current or any future cycle
-	    propp = new AstLogNot (nodep->fileline(), propp);
 	} else {
 	    nodep->v3fatalSrc("Unknown node type");
 	}
 	if (stmtsp) bodysp = bodysp->addNext(stmtsp);
 	AstIf* ifp = new AstIf (nodep->fileline(), propp, bodysp, NULL);
 	bodysp = ifp;
-	if (nodep->castPslAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
+	if (nodep->castVAssert()) ifp->branchPred(AstBranchPred::BP_UNLIKELY);
 	//
 	AstNode* newp = new AstAlways (nodep->fileline(),
 				       VAlwaysKwd::ALWAYS,
@@ -309,12 +303,6 @@ private:
 			nodep->stmtsp(), nodep->name()); nodep=NULL;
 	++m_statAsCover;
     }
-    virtual void visit(AstPslAssert* nodep, AstNUser*) {
-	nodep->iterateChildren(*this);
-	newPslAssertion(nodep, nodep->propp(), nodep->sentreep(),
-			NULL, nodep->name()); nodep=NULL;
-	++m_statAsPsl;
-    }
     virtual void visit(AstVAssert* nodep, AstNUser*) {
 	nodep->iterateChildren(*this);
 	newVAssertion(nodep, nodep->propp()); nodep=NULL;
@@ -339,14 +327,6 @@ private:
 	m_beginp = lastp;
     }
 
-    // VISITORS  //========== Temporal Layer
-
-    // VISITORS  //========== Boolean Layer
-    virtual void visit(AstPslBool* nodep, AstNUser*) {
-	nodep->replaceWith(nodep->exprp()->unlinkFrBack());
-	pushDeletep(nodep); nodep=NULL;
-    }
-
     virtual void visit(AstNode* nodep, AstNUser*) {
 	nodep->iterateChildren(*this);
     }
diff --git a/src/V3AssertPre.cpp b/src/V3AssertPre.cpp
index f80775b..2523891 100644
--- a/src/V3AssertPre.cpp
+++ b/src/V3AssertPre.cpp
@@ -73,14 +73,6 @@ private:
     }
 
     // VISITORS  //========== Statements
-    virtual void visit(AstPslDefClock* nodep, AstNUser*) {
-	nodep->iterateChildren(*this);
-	// Store the new default clock, reset on new module
-	m_seniDefaultp = nodep->sensesp();
-	// Trash it
-	nodep->unlinkFrBack();
-	pushDeletep(nodep); nodep=NULL;
-    }
     virtual void visit(AstClocking* nodep, AstNUser*) {
 	UINFO(8,"   CLOCKING"<<nodep<<endl);
 	// Store the new default clock, reset on new module
@@ -101,13 +93,6 @@ private:
 	nodep->sentreep(newSenTree(nodep));
 	clearAssertInfo();
     }
-    virtual void visit(AstPslAssert* nodep, AstNUser*) {
-	if (nodep->sentreep()) return;  // Already processed
-	clearAssertInfo();
-	nodep->iterateChildren(*this);
-	nodep->sentreep(newSenTree(nodep));
-	clearAssertInfo();
-    }
     virtual void visit(AstPslClocked* nodep, AstNUser*) {
 	nodep->iterateChildren(*this);
 	if (m_senip) {
diff --git a/src/V3Ast.cpp b/src/V3Ast.cpp
index 5b980d6..1fa1cb4 100644
--- a/src/V3Ast.cpp
+++ b/src/V3Ast.cpp
@@ -203,31 +203,6 @@ string AstNode::prettyTypeName() const {
     return string(typeName())+" '"+prettyName()+"'";
 }
 
-string AstNode::quoteName(const string& namein) {
-    // Encode control chars into C style escapes
-    // Reverse is V3Parse::deQuote
-    const char* start = namein.c_str();
-    string out;
-    for (const char* pos = start; *pos; pos++) {
-	if (pos[0]=='\\' || pos[0]=='"') {
-	    out += string("\\")+pos[0];
-	} else if (pos[0]=='\n') {
-	    out += "\\n";
-	} else if (pos[0]=='\r') {
-	    out += "\\r";
-	} else if (pos[0]=='\t') {
-	    out += "\\t";
-	} else if (isprint(pos[0])) {
-	    out += pos[0];
-	} else {
-	    // This will also cover \a etc
-	    char octal[10]; sprintf(octal,"\\%03o",pos[0]);
-	    out += octal;
-	}
-    }
-    return out;
-}
-
 //######################################################################
 // Insertion
 
diff --git a/src/V3Ast.h b/src/V3Ast.h
index f14284a..4099d28 100644
--- a/src/V3Ast.h
+++ b/src/V3Ast.h
@@ -23,6 +23,7 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
+#include "V3FileLine.h"
 #include "V3Number.h"
 #include "V3Global.h"
 #include <vector>
@@ -238,6 +239,13 @@ public:
 	//
 	DT_PUBLIC,			// V3LinkParse moves to AstTypedef::attrPublic
 	//
+	ENUM_FIRST,			// V3Width processes
+	ENUM_LAST,			// V3Width processes
+	ENUM_NUM,			// V3Width processes
+	ENUM_NEXT,			// V3Width processes
+	ENUM_PREV,			// V3Width processes
+	ENUM_NAME,			// V3Width processes
+	//
 	MEMBER_BASE,			// V3LinkResolve creates for AstPreSel, V3LinkParam removes
 	//
 	VAR_BASE,			// V3LinkResolve creates for AstPreSel, V3LinkParam removes
@@ -258,6 +266,7 @@ public:
 	    "DIM_BITS", "DIM_DIMENSIONS", "DIM_HIGH", "DIM_INCREMENT", "DIM_LEFT",
 	    "DIM_LOW", "DIM_RIGHT", "DIM_SIZE", "DIM_UNPK_DIMENSIONS",
 	    "DT_PUBLIC",
+	    "ENUM_FIRST", "ENUM_LAST", "ENUM_NUM", "ENUM_NEXT", "ENUM_PREV", "ENUM_NAME",
 	    "MEMBER_BASE",
 	    "VAR_BASE", "VAR_CLOCK", "VAR_CLOCK_ENABLE", "VAR_PUBLIC",
 	    "VAR_PUBLIC_FLAT", "VAR_PUBLIC_FLAT_RD","VAR_PUBLIC_FLAT_RW",
@@ -383,9 +392,8 @@ public:
     bool isOpaque() const {  // IE not a simple number we can bit optimize
 	return (m_e==STRING || m_e==SCOPEPTR || m_e==CHARPTR || m_e==DOUBLE || m_e==FLOAT);
     }
-    bool isDouble() const {
-	return (m_e==DOUBLE);
-    }
+    bool isDouble() const { return m_e==DOUBLE; }
+    bool isString() const { return m_e==STRING; }
   };
   inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd rhs) { return (lhs.m_e == rhs.m_e); }
   inline bool operator== (AstBasicDTypeKwd lhs, AstBasicDTypeKwd::en rhs) { return (lhs.m_e == rhs); }
@@ -1007,6 +1015,7 @@ public:
     static int	instrCountDouble() { return 8; }	///< Instruction cycles to convert or do floats
     static int	instrCountDoubleDiv() { return 40; }	///< Instruction cycles to divide floats
     static int	instrCountDoubleTrig() { return 200; }	///< Instruction cycles to do triganomics
+    static int	instrCountString() { return 100; }	///< Instruction cycles to do string ops
     static int	instrCountCall() { return instrCountBranch()+10; }	///< Instruction cycles to call subroutine
     static int	instrCountTime() { return instrCountCall()+5; }		///< Instruction cycles to determine simulation time
 
@@ -1016,7 +1025,6 @@ public:
     virtual string verilogKwd() const { return ""; }
     string 	shortName() const;	// Name with __PVT__ removed for concatenating scopes
     static string dedotName(const string& namein);	// Name with dots removed
-    static string quoteName(const string& namein);	// Name with control chars quoted
     static string prettyName(const string& namein);	// Name for printing out to the user
     static string encodeName(const string& namein);	// Encode user name into internal C representation
     static string encodeNumber(vlsint64_t numin);	// Encode number into internal C representation
@@ -1042,6 +1050,7 @@ public:
     bool	isWide() const { return (width()>VL_QUADSIZE); }
     bool	isDouble() const;
     bool	isSigned() const;
+    bool	isString() const;
 
     AstNUser*	user1p() const {
 	// Slows things down measurably, so disabled by default
@@ -1119,6 +1128,7 @@ public:
     void	dtypeSetLogicSized(int width, int widthMin, AstNumeric numeric) { dtypep(findLogicDType(width,widthMin,numeric)); }
     void	dtypeSetLogicBool()	{ dtypep(findLogicBoolDType()); }
     void	dtypeSetDouble()	{ dtypep(findDoubleDType()); }
+    void	dtypeSetString()	{ dtypep(findStringDType()); }
     void	dtypeSetSigned32()	{ dtypep(findSigned32DType()); }
     void	dtypeSetUInt32()	{ dtypep(findUInt32DType()); }  // Twostate
     void	dtypeSetUInt64()	{ dtypep(findUInt64DType()); }  // Twostate
@@ -1126,6 +1136,7 @@ public:
     // Data type locators
     AstNodeDType* findLogicBoolDType()	{ return findBasicDType(AstBasicDTypeKwd::LOGIC); }
     AstNodeDType* findDoubleDType()	{ return findBasicDType(AstBasicDTypeKwd::DOUBLE); }
+    AstNodeDType* findStringDType()	{ return findBasicDType(AstBasicDTypeKwd::STRING); }
     AstNodeDType* findSigned32DType()	{ return findBasicDType(AstBasicDTypeKwd::INTEGER); }
     AstNodeDType* findUInt32DType()	{ return findBasicDType(AstBasicDTypeKwd::UINT32); }  // Twostate
     AstNodeDType* findUInt64DType()	{ return findBasicDType(AstBasicDTypeKwd::UINT64); }  // Twostate
@@ -1263,8 +1274,9 @@ public:
     virtual void numberOperate(V3Number& out, const V3Number& lhs) = 0; // Set out to evaluation of a AstConst'ed lhs
     virtual bool cleanLhs() = 0;
     virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
-    virtual bool signedFlavor() const { return false; }	// Signed flavor of nodes with both flavors?
     virtual bool doubleFlavor() const { return false; }	// D flavor of nodes with both flavors?
+    virtual bool signedFlavor() const { return false; }	// Signed flavor of nodes with both flavors?
+    virtual bool stringFlavor() const { return false; }	// N flavor of nodes with both flavors?
     virtual int instrCount()	const { return widthInstrs(); }
     virtual V3Hash sameHash() const { return V3Hash(); }
     virtual bool same(AstNode*) const { return true; }
@@ -1287,8 +1299,9 @@ public:
     virtual bool cleanRhs() = 0; // True if RHS must have extra upper bits zero
     virtual bool sizeMattersLhs() = 0; // True if output result depends on lhs size
     virtual bool sizeMattersRhs() = 0; // True if output result depends on rhs size
-    virtual bool signedFlavor() const { return false; }	// Signed flavor of nodes with both flavors?
     virtual bool doubleFlavor() const { return false; }	// D flavor of nodes with both flavors?
+    virtual bool signedFlavor() const { return false; }	// Signed flavor of nodes with both flavors?
+    virtual bool stringFlavor() const { return false; }	// N flavor of nodes with both flavors?
     virtual int instrCount()	const { return widthInstrs(); }
     virtual V3Hash sameHash() const { return V3Hash(); }
     virtual bool same(AstNode*) const { return true; }
@@ -1886,6 +1899,7 @@ inline int AstNode::widthMin() const { return dtypep() ? dtypep()->widthMin() :
 inline bool AstNode::width1() const  { return dtypep() && dtypep()->width()==1; }  // V3Const uses to know it can optimize
 inline int  AstNode::widthInstrs() const { return (!dtypep() ? 1 : (dtypep()->isWide() ? dtypep()->widthWords() : 1)); }
 inline bool AstNode::isDouble() const { return dtypep() && dtypep()->castBasicDType() && dtypep()->castBasicDType()->isDouble(); }
+inline bool AstNode::isString() const { return dtypep() && dtypep()->basicp() && dtypep()->basicp()->isString(); }
 inline bool AstNode::isSigned() const { return dtypep() && dtypep()->isSigned(); }
 
 inline bool AstNode::isZero()     { return (this->castConst() && this->castConst()->num().isEqZero()); }
diff --git a/src/V3AstNodes.cpp b/src/V3AstNodes.cpp
index afd2ce3..fd3aa70 100644
--- a/src/V3AstNodes.cpp
+++ b/src/V3AstNodes.cpp
@@ -737,7 +737,10 @@ void AstNode::dump(ostream& str) {
     } else { // V3Broken will throw an error
 	if (dtypep()) str<<" %Error-dtype-exp=null,got="<<(void*)dtypep();
     }
-    if (name()!="") str<<"  "<<AstNode::quoteName(name());
+    if (name()!="") {
+	if (castConst()) str<<"  "<<name();  // Already quoted
+	else str<<"  "<<V3Number::quoteNameControls(name());
+    }
 }
 
 void AstAlways::dump(ostream& str) {
@@ -850,7 +853,10 @@ void AstNodeDType::dumpSmall(ostream& str) {
        <<((isSigned()&&!isDouble())?"s":"")
        <<(isNosign()?"n":"")
        <<(isDouble()?"d":"")
-       <<"w"<<(widthSized()?"":"u")<<width();
+       <<(isString()?"str":"");
+    if (!isDouble() && !isString()) {
+	str<<"w"<<(widthSized()?"":"u")<<width();
+    }
     if (!widthSized()) str<<"/"<<widthMin();
     str<<")";
 }
diff --git a/src/V3AstNodes.h b/src/V3AstNodes.h
index 391c434..a33d7ae 100644
--- a/src/V3AstNodes.h
+++ b/src/V3AstNodes.h
@@ -49,6 +49,8 @@ public:
 	,m_num(num) {
 	if (m_num.isDouble()) {
 	    dtypeSetDouble();
+	} else if (m_num.isString()) {
+	    dtypeSetString();
 	} else {
 	    dtypeSetLogicSized(m_num.width(), m_num.sized()?0:m_num.widthMin(),
 			       m_num.isSigned() ? AstNumeric::SIGNED
@@ -74,6 +76,10 @@ public:
     AstConst(FileLine* fl, RealDouble, double num)
 	:AstNodeMath(fl)
 	,m_num(V3Number(fl,64)) { m_num.setDouble(num); dtypeSetDouble(); }
+    class String {};		// for creator type-overload selection
+    AstConst(FileLine* fl, String, const string& num)
+	:AstNodeMath(fl)
+	,m_num(V3Number(V3Number::String(), fl, num)) { dtypeSetString(); }
     class LogicFalse {};
     AstConst(FileLine* fl, LogicFalse) // Shorthand const 0, know the dtype should be a logic of size 1
 	:AstNodeMath(fl)
@@ -100,34 +106,6 @@ public:
     bool isEqAllOnesV() const { return num().isEqAllOnes(widthMin()); }
 };
 
-class AstConstString : public AstNodeMath {
-    // A constant string
-private:
-    string	m_name;
-public:
-    AstConstString(FileLine* fl, const string& name)
-	: AstNodeMath(fl), m_name(name) {
-	rewidth();
-    }
-    void rewidth() {
-	if (m_name.length()==0) {
-	    dtypeSetLogicSized(1,1,AstNumeric::UNSIGNED);  // 0 width isn't allowed due to historic special cases
-	} else {
-	    dtypeSetLogicSized(((int)m_name.length())*8, ((int)m_name.length())*8, AstNumeric::UNSIGNED);
-	}
-    }
-    ASTNODE_NODE_FUNCS(ConstString, CONSTSTRING)
-    virtual string emitVerilog() { V3ERROR_NA; return ""; }  // Implemented specially
-    virtual string emitC() { V3ERROR_NA; return ""; }
-    virtual bool cleanOut() { return true; }
-    virtual V3Hash sameHash() const { return V3Hash(name()); }
-    virtual bool same(AstNode* samep) const {
-	return name()==samep->castConstString()->name(); }
-    virtual int instrCount() const { return 2; }  // C just loads a pointer
-    virtual string name() const { return m_name; }
-    void name(const string& flag) { m_name = flag; rewidth(); }
-};
-
 class AstRange : public AstNode {
     // Range specification, for use under variables and cells
 private:
@@ -400,6 +378,7 @@ public:
     bool	isBitLogic() const { return keyword().isBitLogic(); }
     bool	isDouble() const { return keyword().isDouble(); }
     bool	isOpaque() const { return keyword().isOpaque(); }
+    bool	isString() const { return keyword().isString(); }
     bool	isSloppy() const { return keyword().isSloppy(); }
     bool	isZeroInit() const { return keyword().isZeroInit(); }
     bool	isRanged() const { return rangep() || m.m_nrange.ranged(); }
@@ -902,6 +881,32 @@ public:
     void fromp(AstNode* nodep) { setOp1p(nodep); }
 };
 
+class AstMethodSel : public AstNode {
+    // A reference to a member task (or function)
+    // We do not support generic member calls yet, so this is only enough to make built-in methods work
+private:
+    string		m_name;		// Name of variable
+public:
+    AstMethodSel(FileLine* fl, AstNode* fromp, VFlagChildDType, const string& name, AstNode* pinsp)
+	: AstNode(fl), m_name(name) {
+	setOp1p(fromp);
+	dtypep(NULL);  // V3Width will resolve
+	addNOp2p(pinsp);
+    }
+    AstMethodSel(FileLine* fl, AstNode* fromp, const string& name, AstNode* pinsp)
+	:AstNode(fl), m_name(name) {
+	setOp1p(fromp);
+	addNOp2p(pinsp);
+    }
+    ASTNODE_NODE_FUNCS(MethodSel, METHODSEL)
+    virtual string name() const { return m_name; }		// * = Var name
+    virtual void name(const string& name) { m_name = name; }
+    AstNode* fromp() const { return op1p()->castNode(); }	// op1 = Extracting what (NULL=TBD during parsing)
+    void fromp(AstNode* nodep) { setOp1p(nodep); }
+    AstNode* pinsp() const { return op2p()->castNode(); }	// op2 = Pin interconnection list
+    void addPinsp(AstNode* nodep) { addOp2p(nodep); }
+};
+
 class AstVar : public AstNode {
     // A variable (in/out/wire/reg/param) inside a module
 private:
@@ -935,6 +940,7 @@ private:
     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_noSubst:1;	// Do not substitute out references
     bool	m_trace:1;	// Trace this variable
 
     void	init() {
@@ -947,6 +953,7 @@ private:
 	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_noSubst=false;
 	m_trace=false;
     }
 public:
@@ -1039,7 +1046,9 @@ public:
     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; }
+    void noSubst(bool flag) { m_noSubst=flag; }
+    bool noSubst() const { return m_noSubst; }
+    void trace(bool flag) { m_trace=flag; }
     // METHODS
     virtual void name(const string& name) { m_name = name; }
     virtual string directionName() const { return (isInout() ? "inout" : isInput() ? "input"
@@ -3521,10 +3530,10 @@ public:
 };
 
 class AstCvtPackString : public AstNodeUniop {
-    // Convert to Verilator Packed Pack (aka Pack)
+    // Convert to Verilator Packed String (aka verilog "string")
 public:
     AstCvtPackString(FileLine* fl, AstNode* lhsp) : AstNodeUniop(fl, lhsp) {
-	dtypeSetUInt64(); }  // Really, width should be dtypep -> STRING
+	dtypeSetString(); }  // Really, width should be dtypep -> STRING
     ASTNODE_NODE_FUNCS(CvtPackString, CVTPACKSTRING)
     virtual void numberOperate(V3Number& out, const V3Number& lhs) { V3ERROR_NA; }
     virtual string emitVerilog() { return "%f$_CAST(%l)"; }
@@ -3794,6 +3803,21 @@ public:
     virtual int instrCount()	const { return instrCountDouble(); }
     virtual bool doubleFlavor() const { return true; }
 };
+class AstEqN : public AstNodeBiCom {
+public:
+    AstEqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(EqN, EQN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opEqN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f== %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return "=="; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstNeq : public AstNodeBiCom {
 public:
     AstNeq(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
@@ -3822,6 +3846,21 @@ public:
     virtual int instrCount()	const { return instrCountDouble(); }
     virtual bool doubleFlavor() const { return true; }
 };
+class AstNeqN : public AstNodeBiCom {
+public:
+    AstNeqN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiCom(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(NeqN, NEQN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opNeqN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f!= %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return "!="; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstLt : public AstNodeBiop {
 public:
     AstLt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
@@ -3864,6 +3903,21 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual bool signedFlavor() const { return true; }
 };
+class AstLtN : public AstNodeBiop {
+public:
+    AstLtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(LtN, LTN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLtN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f< %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return "<"; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstGt : public AstNodeBiop {
 public:
     AstGt(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
@@ -3906,6 +3960,21 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual bool signedFlavor() const { return true; }
 };
+class AstGtN : public AstNodeBiop {
+public:
+    AstGtN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(GtN, GTN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGtN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f> %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return ">"; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstGte : public AstNodeBiop {
 public:
     AstGte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
@@ -3949,6 +4018,21 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual bool signedFlavor() const { return true; }
 };
+class AstGteN : public AstNodeBiop {
+public:
+    AstGteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(GteN, GTEN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opGteN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f>= %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return ">="; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstLte : public AstNodeBiop {
 public:
     AstLte(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
@@ -3992,6 +4076,21 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual bool signedFlavor() const { return true; }
 };
+class AstLteN : public AstNodeBiop {
+public:
+    AstLteN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
+	dtypeSetLogicBool(); }
+    ASTNODE_NODE_FUNCS(LteN, LTEN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opLteN(lhs,rhs); }
+    virtual string emitVerilog() { return "%k(%l %f<= %r)"; }
+    virtual string emitC() { V3ERROR_NA; return ""; }
+    virtual string emitSimpleOperator() { return "<="; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return false;} virtual bool cleanRhs() {return false;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstShiftL : public AstNodeBiop {
 public:
     AstShiftL(FileLine* fl, AstNode* lhsp, AstNode* rhsp, int setwidth=0)
@@ -4352,6 +4451,22 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual int instrCount()	const { return widthInstrs()*2; }
 };
+class AstConcatN : public AstNodeBiop {
+    // String concatenate
+public:
+    AstConcatN(FileLine* fl, AstNode* lhsp, AstNode* rhsp) : AstNodeBiop(fl, lhsp, rhsp) {
+	dtypeSetString();
+    }
+    ASTNODE_NODE_FUNCS(ConcatN, CONCATN)
+    virtual string emitVerilog() { return "%f{%l, %k%r}"; }
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opConcatN(lhs,rhs); }
+    virtual string emitC() { return "VL_CONCATN_NNN(%li, %ri)"; }
+    virtual bool cleanOut() {return true;}
+    virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return instrCountString(); }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstReplicate : public AstNodeBiop {
     // Also used as a "Uniop" flavor of Concat, e.g. "{a}"
     // Verilog {rhs{lhs}} - Note rhsp() is the replicate value, not the lhsp()
@@ -4377,6 +4492,25 @@ public:
     virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
     virtual int instrCount()	const { return widthInstrs()*2; }
 };
+class AstReplicateN : public AstNodeBiop {
+    // String replicate
+private:
+    void init() { dtypeSetString(); }
+public:
+    AstReplicateN(FileLine* fl, AstNode* lhsp, AstNode* rhsp)
+        : AstNodeBiop(fl, lhsp, rhsp) { init(); }
+    AstReplicateN(FileLine* fl, AstNode* lhsp, uint32_t repCount)
+	: AstNodeBiop(fl, lhsp, new AstConst(fl, repCount)) { init(); }
+    ASTNODE_NODE_FUNCS(ReplicateN, REPLICATEN)
+    virtual void numberOperate(V3Number& out, const V3Number& lhs, const V3Number& rhs) { out.opReplN(lhs,rhs); }
+    virtual string emitVerilog() { return "%f{%r{%k%l}}"; }
+    virtual string emitC() { return "VL_REPLICATEN_NN%rq(0,0,%rw, %li, %ri)"; }
+    virtual bool cleanOut() {return false;}
+    virtual bool cleanLhs() {return true;} virtual bool cleanRhs() {return true;}
+    virtual bool sizeMattersLhs() {return false;} virtual bool sizeMattersRhs() {return false;}
+    virtual int instrCount()	const { return widthInstrs()*2; }
+    virtual bool stringFlavor() const { return true; }
+};
 class AstStreamL : public AstNodeStream {
     // Verilog {rhs{lhs}} - Note rhsp() is the slice size, not the lhsp()
 public:
@@ -4520,19 +4654,6 @@ public:
 //======================================================================
 // PSL
 
-class AstPslDefClock : public AstNode {
-    // Set default PSL clock
-    // Parents:  MODULE
-    // Children: SENITEM
-public:
-    AstPslDefClock(FileLine* fl, AstNodeSenItem* sensesp)
-	: AstNode(fl) {
-	addNOp1p(sensesp);
-    }
-    ASTNODE_NODE_FUNCS(PslDefClock, PSLDEFCLOCK)
-    AstNodeSenItem* sensesp() const { return op1p()->castNodeSenItem(); }	// op1 = Sensitivity list
-};
-
 class AstPslClocked : public AstNode {
     // A clocked property
     // Parents:  ASSERT|COVER (property)
@@ -4551,27 +4672,6 @@ public:
     AstNode*	propp()		const { return op3p(); }	// op3 = property
 };
 
-class AstPslAssert : public AstNodeStmt {
-    // Psl Assertion
-    // Parents:  {statement list}
-    // Children: expression, report string
-private:
-    string	m_name;		// Name to report
-public:
-    AstPslAssert(FileLine* fl, AstNode* propp, const string& name="")
-	: AstNodeStmt(fl)
-	, m_name(name) {
-	addOp1p(propp);
-    }
-    ASTNODE_NODE_FUNCS(PslAssert, PSLASSERT)
-    virtual string name()	const { return m_name; }		// * = Var name
-    virtual V3Hash sameHash() const { return V3Hash(name()); }
-    virtual bool same(AstNode* samep) const { return samep->name() == name(); }
-    AstNode*	propp()		const { return op1p(); }	// op1 = property
-    AstSenTree*	sentreep()	const { return op2p()->castSenTree(); }	// op2 = clock domain
-    void sentreep(AstSenTree* sentreep)  { addOp2p(sentreep); }	// op2 = clock domain
-};
-
 class AstPslCover : public AstNodeStmt {
     // Psl Cover
     // Parents:  {statement list}
@@ -4599,29 +4699,6 @@ public:
 };
 
 //======================================================================
-// PSL Expressions
-
-class AstPslBool : public AstNode {
-    // Separates PSL Sere/sequences from the normal expression boolean layer below.
-    // Note this excludes next() and similar functions; they are time domain, so not under AstPslBool.
-    // Parents: Sequences, etc.
-    // Children: math
-public:
-    AstPslBool(FileLine* fileline, AstNode* exprp)
-	: AstNode(fileline) {
-	addOp1p(exprp);
-    }
-    ASTNODE_NODE_FUNCS(PslBool, PSLBOOL)
-    AstNode*	exprp()	const { return op1p()->castNode(); }	// op1= expression
-    virtual bool hasDType() const { return true; }
-    virtual bool isGateOptimizable() const { return false; }	// Not relevant
-    virtual bool isPredictOptimizable() const { return false; }	// Not relevant
-    virtual int instrCount()	const { return 0; }
-    virtual V3Hash sameHash() const { return V3Hash(); }
-    virtual bool same(AstNode* samep) const { return true; }
-};
-
-//======================================================================
 // Text based nodes
 
 class AstText : public AstNodeText {
@@ -4756,6 +4833,7 @@ private:
     bool	m_formCallTree:1;	// Make a global function to call entire tree of functions
     bool	m_slow:1;		// Slow routine, called once or just at init time
     bool	m_funcPublic:1;		// From user public task/function
+    bool	m_isInline:1;		// Inline function
     bool	m_isStatic:1;		// Function is declared static (no this)
     bool	m_symProlog:1;		// Setup symbol table for later instructions
     bool	m_entryPoint:1;		// User may call into this top level function
@@ -4776,6 +4854,7 @@ public:
 	m_formCallTree = false;
 	m_slow = false;
 	m_funcPublic = false;
+	m_isInline = false;
 	m_isStatic = true;	// Note defaults to static, later we see where thisp is needed
 	m_symProlog = false;
 	m_entryPoint = false;
@@ -4805,6 +4884,7 @@ public:
     string	rtnTypeVoid() const { return ((m_rtnType=="") ? "void" : m_rtnType); }
     bool	dontCombine() const { return m_dontCombine || funcType()!=AstCFuncType::FT_NORMAL; }
     void	dontCombine(bool flag) { m_dontCombine = flag; }
+    bool	dontInline() const { return dontCombine() || slow() || skipDecl() || funcPublic(); }
     bool	skipDecl() const { return m_skipDecl; }
     void	skipDecl(bool flag) { m_skipDecl = flag; }
     bool	declPrivate() const { return m_declPrivate; }
@@ -4819,6 +4899,8 @@ public:
     string	argTypes() const { return m_argTypes; }
     void	funcType(AstCFuncType flag) { m_funcType = flag; }
     AstCFuncType funcType() const { return m_funcType; }
+    bool	isInline() const { return m_isInline; }
+    void	isInline(bool flag) { m_isInline = flag; }
     bool	isStatic() const { return m_isStatic; }
     void	isStatic(bool flag) { m_isStatic = flag; }
     bool	symProlog() const { return m_symProlog; }
diff --git a/src/V3Branch.cpp b/src/V3Branch.cpp
index 699f9b8..c887d75 100644
--- a/src/V3Branch.cpp
+++ b/src/V3Branch.cpp
@@ -21,6 +21,9 @@
 //	At each IF/(IF else).
 //	   Count underneath $display/$stop statements.
 //	   If more on if than else, this branch is unlikely, or vice-versa.
+//	At each FTASKREF,
+//	   Count calls into the function
+//	Then, if FTASK is called only once, add inline attribute
 //
 //*************************************************************************
 

@@ -40,9 +43,18 @@
 
 class BranchVisitor : public AstNVisitor {
 private:
+    // NODE STATE
+    // Entire netlist:
+    //  AstFTask::user1()	-> int.  Number of references
+    AstUser1InUse	m_inuser1;
+
+    // TYPES
+    typedef vector<AstCFunc*> CFuncVec;
+
     // STATE
     int		m_likely;	// Excuses for branch likely taken
     int		m_unlikely;	// Excuses for branch likely not taken
+    CFuncVec	m_cfuncsp;	// List of all tasks
 
     // METHODS
     static int debug() {
@@ -55,6 +67,12 @@ private:
 	m_likely = false;
 	m_unlikely = false;
     }
+    void checkUnlikely(AstNode* nodep) {
+	if (nodep->isUnlikely()) {
+	    UINFO(4,"  UNLIKELY: "<<nodep<<endl);
+	    m_unlikely++;
+	}
+    }
 
     // VISITORS
     virtual void visit(AstNodeIf* nodep, AstNUser*) {
@@ -83,20 +101,37 @@ private:
 	m_likely = lastLikely;
 	m_unlikely = lastUnlikely;
     }
+    virtual void visit(AstCCall* nodep, AstNUser*) {
+	checkUnlikely(nodep);
+	nodep->funcp()->user1Inc();
+	nodep->iterateChildren(*this);
+    }
+    virtual void visit(AstCFunc* nodep, AstNUser*) {
+	checkUnlikely(nodep);
+	m_cfuncsp.push_back(nodep);
+	nodep->iterateChildren(*this);
+    }
     virtual void visit(AstNode* nodep, AstNUser*) {
-	// Default: Just iterate
-	if (nodep->isUnlikely()) {
-	    UINFO(4,"  UNLIKELY: "<<nodep<<endl);
-	    m_unlikely++;
-	}
+	checkUnlikely(nodep);
 	nodep->iterateChildren(*this);
     }
 
+    // METHODS
+    void calc_tasks() {
+	for (CFuncVec::iterator it=m_cfuncsp.begin(); it!=m_cfuncsp.end(); ++it) {
+	    AstCFunc* nodep = *it;
+	    if (!nodep->dontInline()) {
+		nodep->isInline(true);
+	    }
+	}
+    }
+
 public:
     // CONSTUCTORS
     BranchVisitor(AstNetlist* nodep) {
 	reset();
 	nodep->iterateChildren(*this);
+	calc_tasks();
     }
     virtual ~BranchVisitor() {}
 };
diff --git a/src/V3Config.h b/src/V3Config.h
index d9098fc..c129277 100644
--- a/src/V3Config.h
+++ b/src/V3Config.h
@@ -24,6 +24,7 @@
 #include "verilatedos.h"
 #include <string>
 #include "V3Error.h"
+#include "V3FileLine.h"
 
 //######################################################################
 
diff --git a/src/V3Const.cpp b/src/V3Const.cpp
index 259c5a5..a0b7484 100644
--- a/src/V3Const.cpp
+++ b/src/V3Const.cpp
@@ -624,7 +624,7 @@ private:
     void replaceConstString (AstNode* oldp, const string& num) {
 	// Replace oldp node with a constant set to specified value
 	UASSERT (oldp, "Null old\n");
-	AstNode* newp = new AstConstString(oldp->fileline(), num);
+	AstNode* newp = new AstConst(oldp->fileline(), AstConst::String(), num);
 	if (debug()>5) oldp->dumpTree(cout,"  const_old: ");
 	if (debug()>5) newp->dumpTree(cout,"       _new: ");
 	oldp->replaceWith(newp);
@@ -1457,6 +1457,7 @@ private:
 		     && v3Global.opt.oConst()
 		     && !(nodep->varp()->isFuncLocal() // Default value, not a "known" constant for this usage
 			  && nodep->varp()->isInput())
+		     && !nodep->varp()->noSubst()
 		     && !nodep->varp()->isSigPublic())
 		    || nodep->varp()->isParam())) {
 		if (operandConst(valuep)) {
@@ -2141,22 +2142,28 @@ private:
     TREEOP ("AstXor    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstEq     {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");  // We let X==X -> 1, although in a true 4-state sim it's X.
     TREEOP ("AstEqD    {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");  // We let X==X -> 1, although in a true 4-state sim it's X.
+    TREEOP ("AstEqN    {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");  // We let X==X -> 1, although in a true 4-state sim it's X.
     TREEOP ("AstEqCase {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstEqWild {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstGt     {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstGtD    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
+    TREEOP ("AstGtN    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstGtS    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstGte    {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstGteD   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
+    TREEOP ("AstGteN   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstGteS   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstLt     {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstLtD    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
+    TREEOP ("AstLtN    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstLtS    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstLte    {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstLteD   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
+    TREEOP ("AstLteN   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstLteS   {operandsSame($lhsp,,$rhsp)}",	"replaceNum(nodep,1)");
     TREEOP ("AstNeq    {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstNeqD   {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
+    TREEOP ("AstNeqN   {operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstNeqCase{operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstNeqWild{operandsSame($lhsp,,$rhsp)}",	"replaceZero(nodep)");
     TREEOP ("AstLogAnd {operandsSame($lhsp,,$rhsp), $lhsp.width1}",	"replaceWLhs(nodep)");
@@ -2212,6 +2219,7 @@ private:
     TREEOPV("AstExtend {$lhsp.castExtend}",		"replaceExtend(nodep, nodep->lhsp()->castExtend()->lhsp())");
     TREEOPV("AstExtendS{$lhsp.castExtendS}",		"replaceExtend(nodep, nodep->lhsp()->castExtendS()->lhsp())");
     TREEOPV("AstReplicate{$lhsp, $rhsp.isOne, $lhsp->width()==nodep->width()}",	"replaceWLhs(nodep)");  // {1{lhs}}->lhs
+    TREEOPV("AstReplicateN{$lhsp, $rhsp.isOne, $lhsp->width()==nodep->width()}", "replaceWLhs(nodep)");  // {1{lhs}}->lhs
     // Next rule because AUTOINST puts the width of bits in
     // to pins, even when the widths are exactly the same across the hierarchy.
     TREEOPV("AstSel{operandSelExtend(nodep)}",	"DONE");
diff --git a/src/V3EmitC.cpp b/src/V3EmitC.cpp
index 3d3d69a..a26f9c6 100644
--- a/src/V3EmitC.cpp
+++ b/src/V3EmitC.cpp
@@ -227,9 +227,9 @@ public:
 	puts("&(vlSymsp->__Vcoverage[");
 	puts(cvtToStr(nodep->dataDeclThisp()->binNum())); puts("])");
 	// If this isn't the first instantiation of this module under this
-	// design, don't really count the bucket, and rely on SystemPerl to
+	// design, don't really count the bucket, and rely on verilator_cov to
 	// aggregate counts.  This is because Verilator combines all
-	// hiearchies itself, and if SystemPerl also did it, you'd end up
+	// hiearchies itself, and if verilator_cov also did it, you'd end up
 	// with (number-of-instant) times too many counts in this bin.
 	puts(", first");  // Enable, passed from __Vconfigure parameter
 	puts(", ");	putsQuoted(nodep->fileline()->filename());
@@ -620,6 +620,10 @@ public:
 	// Put out constant set to the specified variable, or given variable in a string
 	if (nodep->num().isFourState()) {
 	    nodep->v3error("Unsupported: 4-state numbers in this context");
+	} else if (nodep->num().isString()) {
+	    putbs("string(");
+	    putsQuoted(nodep->num().toString());
+	    puts(")");
 	} else if (nodep->isWide()) {
 	    putbs("VL_CONST_W_");
 	    puts(cvtToStr(VL_WORDS_I(nodep->num().widthMin())));
@@ -680,9 +684,6 @@ public:
 	    emitConstant(nodep, NULL, "");
 	}
     }
-    virtual void visit(AstConstString* nodep, AstNUser*) {
-	putsQuoted(nodep->name());
-    }
 
     // Just iterate
     virtual void visit(AstNetlist* nodep, AstNUser*) {
@@ -829,6 +830,7 @@ class EmitCImp : EmitCStmts {
 	splitSizeInc(nodep);
 
 	puts("\n");
+	if (nodep->isInline()) puts("VL_INLINE_OPT ");
 	puts(nodep->rtnTypeVoid()); puts(" ");
 	puts(modClassName(m_modp)+"::"+nodep->name()
 	     +"("+cFuncArgs(nodep)+") {\n");
@@ -1167,17 +1169,20 @@ void EmitCStmts::emitOpName(AstNode* nodep, const string& format,
 
 struct EmitDispState {
     string		m_format;	// "%s" and text from user
+    vector<char>	m_argsChar;	// Format of each argument to be printed
     vector<AstNode*>	m_argsp;	// Each argument to be printed
     vector<string>	m_argsFunc;	// Function before each argument to be printed
     EmitDispState() { clear(); }
     void clear() {
 	m_format = "";
+	m_argsChar.clear();
 	m_argsp.clear();
 	m_argsFunc.clear();
     }
     void pushFormat(const string& fmt) { m_format += fmt; }
     void pushFormat(char fmt) { m_format += fmt; }
-    void pushArg(AstNode* nodep, const string& func) {
+    void pushArg(char fmtChar, AstNode* nodep, const string& func) {
+	m_argsChar.push_back(fmtChar);
 	m_argsp.push_back(nodep); m_argsFunc.push_back(func);
     }
 } emitDispState;
@@ -1230,6 +1235,7 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
 	// Arguments
 	for (unsigned i=0; i < emitDispState.m_argsp.size(); i++) {
 	    puts(",");
+	    char     fmt  = emitDispState.m_argsChar[i];
 	    AstNode* argp = emitDispState.m_argsp[i];
 	    string   func = emitDispState.m_argsFunc[i];
 	    ofp()->indentInc();
@@ -1237,8 +1243,10 @@ void EmitCStmts::displayEmit(AstNode* nodep, bool isScan) {
 	    if (func!="") puts(func);
 	    if (argp) {
 		if (isScan) puts("&(");
+		else if (fmt == '@') puts("&(");
 		argp->iterate(*this);
 		if (isScan) puts(")");
+		else if (fmt == '@') puts(")");
 	    }
 	    ofp()->indentDec();
 	}
@@ -1287,8 +1295,8 @@ void EmitCStmts::displayArg(AstNode* dispp, AstNode** elistp, bool isScan,
 	pfmt = string("%") + vfmt + fmtLetter;
     }
     emitDispState.pushFormat(pfmt);
-    emitDispState.pushArg(NULL,cvtToStr(argp->widthMin()));
-    emitDispState.pushArg(argp,"");
+    emitDispState.pushArg(' ',NULL,cvtToStr(argp->widthMin()));
+    emitDispState.pushArg(fmtLetter,argp,"");
 
     // Next parameter
     *elistp = (*elistp)->nextp();
@@ -1327,6 +1335,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
 		break;
 	    // Special codes
 	    case '~': displayArg(nodep,&elistp,isScan, vfmt,'d'); break;  // Signed decimal
+	    case '@': displayArg(nodep,&elistp,isScan, vfmt,'@'); break;  // Packed string
 	    // Spec: h d o b c l
 	    case 'b': displayArg(nodep,&elistp,isScan, vfmt,'b'); break;
 	    case 'c': displayArg(nodep,&elistp,isScan, vfmt,'c'); break;
@@ -1344,7 +1353,7 @@ void EmitCStmts::displayNode(AstNode* nodep, AstScopeName* scopenamep,
 		string suffix = scopenamep->scopePrettyName();
 		if (suffix=="") emitDispState.pushFormat("%S");
 		else emitDispState.pushFormat("%N");  // Add a . when needed
-		emitDispState.pushArg(NULL, "vlSymsp->name()");
+		emitDispState.pushArg(' ',NULL, "vlSymsp->name()");
 		emitDispState.pushFormat(suffix);
 		break;
 	    }
@@ -1383,9 +1392,6 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
 	    if (varp->isIO() && modp->isTop() && optSystemC()) {
 		// System C top I/O doesn't need loading, as the lower level subinst code does it.
 	    }
-	    else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
-		// Constructor deals with it
-	    }
 	    else if (varp->isParam()) {
 		if (!varp->valuep()) nodep->v3fatalSrc("No init for a param?");
 		// If a simple CONST value we initialize it using an enum
@@ -1404,6 +1410,9 @@ void EmitCImp::emitVarResets(AstNodeModule* modp) {
 		    varp->v3fatalSrc("InitArray under non-arrayed var");
 		}
 	    }
+	    else if (varp->basicp() && varp->basicp()->keyword() == AstBasicDTypeKwd::STRING) {
+		// Constructor deals with it
+	    }
 	    else {
 		int vects = 0;
 		// This isn't very robust and may need cleanup for other data types
@@ -1508,7 +1517,7 @@ void EmitCImp::emitConfigureImp(AstNodeModule* modp) {
 void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
     if (v3Global.opt.coverage() ) {
 	puts("\n// Coverage\n");
-	// Rather than putting out SP_COVER_INSERT calls directly, we do it via this function
+	// Rather than putting out VL_COVER_INSERT calls directly, we do it via this function
 	// This gets around gcc slowness constructing all of the template arguments
 	// SystemPerl 1.301 is much faster, but it's nice to remain back
 	// compatible, and have a common wrapper.
@@ -1517,7 +1526,7 @@ void EmitCImp::emitCoverageImp(AstNodeModule* modp) {
 	puts(   "static uint32_t fake_zero_count = 0;\n");  // static doesn't need save-restore as constant
 	puts(   "if (!enable) countp = &fake_zero_count;\n");  // Used for second++ instantiation of identical bin
 	puts(   "*countp = 0;\n");
-	puts(   "SP_COVER_INSERT(countp,");
+	puts(   "VL_COVER_INSERT(countp,");
 	puts(	"  \"filename\",filenamep,");
 	puts(	"  \"lineno\",lineno,");
 	puts(	"  \"column\",column,\n");
@@ -1827,7 +1836,7 @@ void EmitCImp::emitInt(AstNodeModule* modp) {
 	puts("#include \"verilated_save.h\"\n");
     }
     if (v3Global.opt.coverage()) {
-	puts("#include \"SpCoverage.h\"\n");
+	puts("#include \"verilated_cov.h\"\n");
 	if (v3Global.opt.savable()) v3error("--coverage and --savable not supported together");
     }
     if (v3Global.needHInlines()) {   // Set by V3EmitCInlines; should have been called before us
diff --git a/src/V3EmitMk.cpp b/src/V3EmitMk.cpp
index 272b007..1c7a827 100644
--- a/src/V3EmitMk.cpp
+++ b/src/V3EmitMk.cpp
@@ -83,13 +83,13 @@ public:
 		    if (v3Global.opt.savable()) {
 			putMakeClassEntry(of, "verilated_save.cpp");
 		    }
+		    if (v3Global.opt.coverage()) {
+			putMakeClassEntry(of, "verilated_cov.cpp");
+		    }
 		    if (v3Global.opt.systemPerl()) {
 			putMakeClassEntry(of, "Sp.cpp");  // Note Sp.cpp includes SpTraceVcdC
 		    }
 		    else {
-			if (v3Global.opt.coverage()) {
-			    putMakeClassEntry(of, "SpCoverage.cpp");
-			}
 			if (v3Global.opt.trace()) {
 			    putMakeClassEntry(of, "verilated_vcd_c.cpp");
 			    if (v3Global.opt.systemC()) {
diff --git a/src/V3EmitV.cpp b/src/V3EmitV.cpp
index b7c7c99..35d8cc6 100644
--- a/src/V3EmitV.cpp
+++ b/src/V3EmitV.cpp
@@ -57,7 +57,7 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
 	// Don't use to quote a filename for #include - #include doesn't \ escape.
 	// Duplicate in V3File - here so we can print to string
 	putsNoTracking("\"");
-	putsNoTracking(AstNode::quoteName(str));
+	putsNoTracking(V3Number::quoteNameControls(str));
 	putsNoTracking("\"");
     }
 
@@ -553,10 +553,6 @@ class EmitVBaseVisitor : public EmitCBaseVisitor {
     virtual void visit(AstConst* nodep, AstNUser*) {
 	putfs(nodep,nodep->num().ascii(true,true));
     }
-    virtual void visit(AstConstString* nodep, AstNUser*) {
-	putfs(nodep,"");
-	putsQuoted(nodep->name());
-    }
 
     // Just iterate
     virtual void visit(AstTopScope* nodep, AstNUser*) {
diff --git a/src/V3EmitXml.cpp b/src/V3EmitXml.cpp
index 851bd26..9e2dd8c 100644
--- a/src/V3EmitXml.cpp
+++ b/src/V3EmitXml.cpp
@@ -59,7 +59,7 @@ class EmitXmlFileVisitor : public EmitCBaseVisitor {
 	// Don't use to quote a filename for #include - #include doesn't \ escape.
 	// Duplicate in V3File - here so we can print to string
 	putsNoTracking("\"");
-	putsNoTracking(AstNode::quoteName(str));
+	putsNoTracking(V3Number::quoteNameControls(str));
 	putsNoTracking("\"");
     }
 
diff --git a/src/V3Error.cpp b/src/V3Error.cpp
index 8eb7c56..514a40f 100644
--- a/src/V3Error.cpp
+++ b/src/V3Error.cpp
@@ -27,7 +27,6 @@
 # include "V3Ast.h"
 # include "V3Global.h"
 # include "V3Stats.h"
-# include "V3Config.h"
 #endif
 
 //======================================================================
@@ -36,6 +35,8 @@
 int V3Error::s_errCount = 0;
 int V3Error::s_warnCount = 0;
 int V3Error::s_debugDefault = 0;
+int V3Error::s_errorLimit = V3Error::MAX_ERRORS;
+bool V3Error::s_warnFatal = true;
 int V3Error::s_tellManual = 0;
 ostringstream V3Error::s_errorStr;		// Error string being formed
 V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL;
@@ -66,270 +67,6 @@ V3ErrorCode::V3ErrorCode(const char* msgp) {
 }
 
 //######################################################################
-// FileLineSingleton class functions
-
-const string FileLineSingleton::filenameLetters(int no) {
-    const int size = 1 + (64 / 4);  // Each letter retires more than 4 bits of a > 64 bit number
-    char out[size];
-    char* op = out+size-1;
-    *--op = '\0';  // We build backwards
-    int num = no;
-    do {
-	*--op = 'a'+num%26;
-	num /= 26;
-    } while (num);
-    return op;
-}
-
-//! Convert filenames to a filenameno
-
-//! This lets us assign a nice small identifier for debug messages, but more
-//! importantly lets us use a 4 byte int instead of 8 byte pointer in every
-//! FileLine.
-
-//! 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 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());
-    m_namemap.insert(make_pair(filename,num));
-    return num;
-}
-
-//! Support XML output
-
-//! Experimental. Updated to also put out the language.
-void FileLineSingleton::fileNameNumMapDumpXml(ostream& os) {
-    os<<"<files>\n";
-    for (FileNameNumMap::const_iterator it = m_namemap.begin(); it != m_namemap.end(); ++it) {
-	os<<"<file id=\""<<filenameLetters(it->second)
-	  <<"\" filename=\""<<it->first
-	  <<"\" language=\""<<numberToLang(it->second).ascii()<<"\"/>\n";
-    }
-    os<<"</files>\n";
-}
-
-//######################################################################
-// FileLine class functions
-
-FileLine::FileLine(FileLine::EmptySecret) {
-    // Sort of a singleton
-    m_lineno=0;
-    m_filenameno=singleton().nameToNumber("AstRoot");
-
-    m_warnOn=0;
-    for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
-	V3ErrorCode code = (V3ErrorCode)codei;
-	warnOff(code, code.defaultsOff());
-    }
-}
-
-string FileLine::lineDirectiveStrg(int enterExit) const {
-    char numbuf[20]; sprintf(numbuf, "%d", lineno());
-    char levelbuf[20]; sprintf(levelbuf, "%d", enterExit);
-    return ((string)"`line "+numbuf+" \""+filename()+"\" "+levelbuf+"\n");
-}
-
-void FileLine::lineDirective(const char* textp, int& enterExitRef) {
-    // Handle `line directive
-    // Skip `line
-    while (*textp && isspace(*textp)) textp++;
-    while (*textp && !isspace(*textp)) textp++;
-    while (*textp && (isspace(*textp) || *textp=='"')) textp++;
-
-    // Grab linenumber
-    const char *ln = textp;
-    while (*textp && !isspace(*textp)) textp++;
-    if (isdigit(*ln)) {
-	this->lineno(atoi(ln));
-    }
-    while (*textp && (isspace(*textp) || *textp=='"')) textp++;
-
-    // Grab filename
-    const char *fn = textp;
-    while (*textp && !(isspace(*textp) || *textp=='"')) textp++;
-    if (textp != fn) {
-	string strfn = fn;
-	strfn = strfn.substr(0, textp-fn);
-	this->filename(strfn);
-    }
-
-    // Grab level
-    while (*textp && (isspace(*textp) || *textp=='"')) textp++;
-    if (isdigit(*textp)) enterExitRef = atoi(textp);
-    else enterExitRef = 0;
-
-    //printf ("PPLINE %d '%s'\n", s_lineno, s_filename.c_str());
-}
-
-FileLine* FileLine::copyOrSameFileLine() {
-    // When a fileline is "used" to produce a node, calls this function.
-    // Return this, or a copy of this
-    // There are often more than one token per line, thus we use the
-    // same pointer as long as we're on the same line, file & warn state.
-#ifndef _V3ERROR_NO_GLOBAL_
-    V3Config::applyIgnores(this);  // Toggle warnings based on global config file
-#endif
-    static FileLine* lastNewp = NULL;
-    if (lastNewp && *lastNewp == *this) {  // Compares lineno, filename, etc
-	return lastNewp;
-    }
-    FileLine* newp = new FileLine(this);
-    lastNewp = newp;
-    return newp;
-}
-
-void FileLine::updateLanguage () {
-     language(v3Global.opt.fileLanguage(filename()));
-}
-
-const string FileLine::filebasename() const {
-    string name = filename();
-    string::size_type pos;
-    if ((pos = name.rfind("/")) != string::npos) {
-	name.erase(0,pos+1);
-    }
-    return name;
-}
-
-const string FileLine::filebasenameNoExt() const {
-    string name = filebasename();
-    string::size_type pos;
-    if ((pos = name.find(".")) != string::npos) {
-	name = name.substr(0,pos);
-    }
-    return name;
-}
-
-const string FileLine::profileFuncname() const {
-    // Return string that is OK as a function name - for profiling
-    string name  = filebasenameNoExt();
-    string::size_type pos;
-    while ((pos = name.find_first_not_of("abcdefghijlkmnopqrstuvwxyzABCDEFGHIJLKMNOPQRSTUVWXYZ0123456789_"))
-	   != string::npos) {
-	name.replace(pos, 1, "_");
-    }
-    name += "__l"+cvtToStr(lineno());
-    return name;
-}
-
-string FileLine::ascii() const {
-    return filename()+":"+cvtToStr(lineno());
-}
-ostream& operator<<(ostream& os, FileLine* fileline) {
-    os <<fileline->ascii()<<": "<<hex;
-    return(os);
-}
-
-bool FileLine::warnOff(const string& msg, bool flag) {
-    V3ErrorCode code (msg.c_str());
-    if (code < V3ErrorCode::EC_FIRST_WARN) {
-	return false;
-    } else if (v3Global.opt.lintOnly()   // Lint mode is allowed to suppress some errors
-	       && code < V3ErrorCode::EC_MIN) {
-	return false;
-    } else {
-	warnOff(code, flag);
-	return true;
-    }
-}
-
-void FileLine::warnLintOff(bool flag) {
-    for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
-	V3ErrorCode code = (V3ErrorCode)codei;
-	if (code.lintError()) warnOff(code, flag);
-    }
-}
-
-void FileLine::warnStyleOff(bool flag) {
-    for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
-	V3ErrorCode code = (V3ErrorCode)codei;
-	if (code.styleError()) warnOff(code, flag);
-    }
-}
-
-bool FileLine::warnIsOff(V3ErrorCode code) const {
-    if (!m_warnOn.test(code)) return true;
-    if (!defaultFileLine().m_warnOn.test(code)) return true;  // Global overrides local
-    // UNOPTFLAT implies UNOPT
-    if (code==V3ErrorCode::UNOPT && !m_warnOn.test(V3ErrorCode::UNOPTFLAT)) return true;
-    if ((code.lintError() || code.styleError()) && !m_warnOn.test(V3ErrorCode::I_LINT)) return true;
-    return false;
-}
-
-void FileLine::modifyStateInherit(const FileLine* fromp) {
-    // Any warnings that are off in "from", become off in "this".
-    for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
-	V3ErrorCode code = (V3ErrorCode)codei;
-	if (fromp->warnIsOff(code)) {
-	    this->warnOff(code, true);
-	}
-    }
-}
-
-void FileLine::v3errorEnd(ostringstream& str) {
-    if (this && m_lineno) {
-	ostringstream nsstr;
-	nsstr<<this<<str.str();
-	if (warnIsOff(V3Error::errorCode())) V3Error::suppressThisWarning();
-	V3Error::v3errorEnd(nsstr);
-    } else {
-	V3Error::v3errorEnd(str);
-    }
-}
-
-string FileLine::warnMore() const {
-    if (this && m_lineno) {
-	return V3Error::warnMore()+ascii()+": ";
-    } else {
-	return V3Error::warnMore();
-    }
-}
-
-#ifdef VL_LEAK_CHECKS
-typedef set<FileLine*> FileLineCheckSet;
-FileLineCheckSet fileLineLeakChecks;
-
-void* FileLine::operator new(size_t size) {
-    FileLine* objp = static_cast<FileLine*>(::operator new(size));
-    fileLineLeakChecks.insert(objp);
-    return objp;
-}
-
-void FileLine::operator delete(void* objp, size_t size) {
-    if (!objp) return;
-    FileLine* flp = static_cast<FileLine*>(objp);
-    FileLineCheckSet::iterator it = fileLineLeakChecks.find(flp);
-    if (it != fileLineLeakChecks.end()) {
-	fileLineLeakChecks.erase(it);
-    } else {
-	flp->v3fatalSrc("Deleting FileLine object that was never tracked\n");
-    }
-    ::operator delete(objp);
-}
-#endif
-
-void FileLine::deleteAllRemaining() {
-#ifdef VL_LEAK_CHECKS
-    // FileLines are allocated, but never nicely freed, as it's much faster
-    // that way.  Unfortunately this makes our leak checking a big mess, so
-    // only when leak checking we'll track them all and cleanup.
-    while (1) {
-	FileLineCheckSet::iterator it=fileLineLeakChecks.begin();
-	if (it==fileLineLeakChecks.end()) break;
-	delete *it;
-	// Operator delete will remove the iterated object from the list.
-	// Eventually the list will be empty and terminate the loop.
-    }
-    fileLineLeakChecks.clear();
-    singleton().clear();
-#endif
-}
-
-//######################################################################
 // V3Error class functions
 
 void V3Error::init() {
@@ -354,26 +91,15 @@ string V3Error::lineStr (const char* filename, int lineno) {
     return out.str();
 }
 
-void V3Error::incWarnings() {
-    s_warnCount++;
-    // We don't exit on a lot of warnings.
-}
-
 void V3Error::incErrors() {
     s_errCount++;
-    if (errorCount() == v3Global.opt.errorLimit()) {  // Not >= as would otherwise recurse
+    if (errorCount() == errorLimit()) {  // Not >= as would otherwise recurse
 	v3fatal ("Exiting due to too many errors encountered; --error-limit="<<errorCount()<<endl);
     }
 }
 
-void V3Error::abortIfErrors() {
-    if (errorCount()) {
-	abortIfWarnings();
-    }
-}
-
 void V3Error::abortIfWarnings() {
-    bool exwarn = v3Global.opt.warnFatal() && warnCount();
+    bool exwarn = warnFatal() && warnCount();
     if (errorCount() && exwarn) {
 	v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s), "<<warnCount()<<" warning(s)\n");
     } else if (errorCount()) {
@@ -423,7 +149,9 @@ void V3Error::vlAbort () {
 
 void V3Error::suppressThisWarning() {
     if (s_errorCode>=V3ErrorCode::EC_MIN) {
+#ifndef _V3ERROR_NO_GLOBAL_
 	V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1);
+#endif
 	s_errorSuppressed = true;
     }
 }
diff --git a/src/V3Error.h b/src/V3Error.h
index 441a791..2e810ec 100644
--- a/src/V3Error.h
+++ b/src/V3Error.h
@@ -30,8 +30,6 @@
 #include <set>
 #include <deque>
 
-#include "V3LangCode.h"
-
 //######################################################################
 
 class V3ErrorCode {
@@ -191,9 +189,11 @@ class V3Error {
     static bool 	s_describedWarnings;	// Told user how to disable warns
     static bool 	s_describedEachWarn[V3ErrorCode::_ENUM_MAX]; // Told user specifics about this warning
     static bool 	s_pretendError[V3ErrorCode::_ENUM_MAX]; // Pretend this warning is an error
-    static int		s_debugDefault;		// Default debugging level
+    static int		s_debugDefault;		// Option: --debugi Default debugging level
+    static int		s_errorLimit;		// Option: --error-limit Number of errors before exit
+    static bool		s_warnFatal;		// Option: --warnFatal Warnings are fatal
     static int		s_errCount;		// Error count
-    static int		s_warnCount;		// Error count
+    static int		s_warnCount;		// Warning count
     static int 		s_tellManual;		// Tell user to see manual, 0=not yet, 1=doit, 2=disable
     static ostringstream s_errorStr;		// Error string being formed
     static V3ErrorCode	s_errorCode;		// Error string being formed will abort
@@ -210,15 +210,19 @@ class V3Error {
     // ACCESSORS
     static void		debugDefault(int level) { s_debugDefault = level; }
     static int		debugDefault() { return s_debugDefault; }
+    static void		errorLimit(int level) { s_errorLimit = level; }
+    static int		errorLimit() { return s_errorLimit; }
+    static void		warnFatal(bool flag) { s_warnFatal = flag; }
+    static bool		warnFatal() { return s_warnFatal; }
     static string	msgPrefix();	// returns %Error/%Warn
     static int		errorCount() { return s_errCount; }
     static int		warnCount() { return s_warnCount; }
     static int		errorOrWarnCount() { return errorCount()+warnCount(); }
     // METHODS
     static void		incErrors();
-    static void		incWarnings();
+    static void		incWarnings() { s_warnCount++; }
     static void		init();
-    static void		abortIfErrors();
+    static void		abortIfErrors() { if (errorCount()) abortIfWarnings(); }
     static void		abortIfWarnings();
     static void		suppressThisWarning();	// Suppress next %Warn if user has it off
     static void		pretendError(V3ErrorCode code, bool flag) { s_pretendError[code]=flag; }
@@ -243,7 +247,7 @@ class V3Error {
 inline int debug() { return V3Error::debugDefault(); }
 inline void v3errorEnd(ostringstream& sstr) { V3Error::v3errorEnd(sstr); }
 
-// These allow errors using << operators: v3error("foo"<<"bar");
+// Theses allow errors using << operators: v3error("foo"<<"bar");
 // Careful, you can't put () around msg, as you would in most macro definitions
 // Note the commas are the comma operator, not separating arguments. These are needed to insure
 // evaluation order as otherwise we couldn't insure v3errorPrep is called first.
@@ -285,140 +289,4 @@ inline string ucfirst(const string& text) {
     return out;
 }
 
-//######################################################################
-
-class FileLine;
-
-//! Singleton class with tables of per-file data.
-
-//! This singleton class contains tables of data that are unchanging in each
-//! source file (each with its own unique filename number).
-class FileLineSingleton {
-    // TYPES
-    typedef map<string,int> FileNameNumMap;
-    typedef map<string,V3LangCode> FileLangNumMap;
-    // MEMBERS
-    FileNameNumMap	m_namemap;	// filenameno for each filename
-    deque<string>	m_names;	// filename text for each filenameno
-    deque<V3LangCode>	m_languages;	// language for each filenameno
-    // COSNTRUCTORS
-    FileLineSingleton() { }
-    ~FileLineSingleton() { }
-protected:
-    friend class FileLine;
-    // METHODS
-    int nameToNumber(const string& filename);
-    const string numberToName(int filenameno) const { return m_names[filenameno]; }
-    const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
-    void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
-    void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
-    void fileNameNumMapDumpXml(ostream& os);
-    static const string filenameLetters(int fileno);
-};
-
-//! File and line number of an object, mostly for error reporting
-
-//! This class is instantiated for every source code line (potentially
-//! millions). To save space, per-file information (e.g. filename, source
-//! language is held in tables in the FileLineSingleton class.
-class FileLine {
-    int		m_lineno;
-    int		m_filenameno;
-    bitset<V3ErrorCode::_ENUM_MAX>	m_warnOn;
-
-private:
-    struct EmptySecret {};
-    inline static FileLineSingleton& singleton() {
-	static FileLineSingleton s;
-	return s;
-    }
-    inline static FileLine& defaultFileLine() {
-	static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
-	return *defFilelinep;
-    }
-protected:
-    // User routines should never need to change line numbers
-    // We are storing pointers, so we CAN'T change them after initial reading.
-    friend class FileLineSingleton;
-    friend class V3ParseImp;
-    friend class V3PreLex;
-    friend class V3PreProcImp;
-    void lineno(int num) { m_lineno = num; }
-    void language (V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
-    void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
-    void lineDirective(const char* textp, int& enterExitRef);
-    void linenoInc() { m_lineno++; }
-    void linenoIncInPlace() { m_lineno++; }
-    FileLine* copyOrSameFileLine();
-public:
-    FileLine (const string& filename, int lineno) {
-	m_lineno=lineno; m_filenameno = singleton().nameToNumber(filename);
-	m_warnOn=defaultFileLine().m_warnOn; }
-    FileLine (FileLine* fromp) {
-	m_lineno=fromp->m_lineno; m_filenameno = fromp->m_filenameno; m_warnOn=fromp->m_warnOn; }
-    FileLine (EmptySecret);
-    ~FileLine() { }
-    FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
-    FileLine* create(int lineno) { return create(filename(), lineno); }
-    static void deleteAllRemaining();
-#ifdef VL_LEAK_CHECKS
-    static void* operator new(size_t size);
-    static void operator delete(void* obj, size_t size);
-#endif
-
-    int lineno () const { return m_lineno; }
-    V3LangCode language () const { return singleton().numberToLang(m_filenameno); }
-    void updateLanguage ();
-    string ascii() const;
-    const string filename () const { return singleton().numberToName(m_filenameno); }
-    const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
-    const string filebasename () const;
-    const string filebasenameNoExt () const;
-    const string profileFuncname() const;
-    const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
-    string lineDirectiveStrg(int enter_exit_level) const;
-    void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); }	// Turn on/off warning messages on this line.
-    void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
-    bool warnOff(const string& code, bool flag);  // Returns 1 if ok
-    bool warnIsOff(V3ErrorCode code) const;
-    void warnLintOff(bool flag);
-    void warnStyleOff(bool flag);
-    void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; }
-    void warnResetDefault() { warnStateFrom(defaultFileLine()); }
-
-    // Specific flag ACCESSORS/METHODS
-    bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
-    void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE,flag); }
-    bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
-    void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); }
-
-    // METHODS - Global
-    static void globalWarnLintOff(bool flag) {
-	defaultFileLine().warnLintOff(flag); }
-    static void globalWarnStyleOff(bool flag) {
-	defaultFileLine().warnStyleOff(flag); }
-    static void globalWarnOff(V3ErrorCode code, bool flag) {
-	defaultFileLine().warnOff(code, flag); }
-    static bool globalWarnOff(const string& code, bool flag) {
-	return defaultFileLine().warnOff(code, flag); }
-    static void fileNameNumMapDumpXml(ostream& os) {
-	singleton().fileNameNumMapDumpXml(os); }
-
-    // METHODS - Called from netlist
-    // Merge warning disables from another fileline
-    void modifyStateInherit(const FileLine* fromp);
-    // Change the current fileline due to actions discovered after parsing
-    // and may have side effects on other nodes sharing this FileLine.
-    // Use only when this is intended
-    void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code,flag); }
-
-    // OPERATORS
-    void v3errorEnd(ostringstream& str);
-    string warnMore() const;
-    inline bool operator==(FileLine rhs) const {
-	return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn);
-    }
-};
-ostream& operator<<(ostream& os, FileLine* fileline);
-
 #endif // Guard
diff --git a/src/V3File.cpp b/src/V3File.cpp
index aad16a6..0247b73 100644
--- a/src/V3File.cpp
+++ b/src/V3File.cpp
@@ -757,7 +757,7 @@ void V3OutFormatter::putsQuoted(const char* strg) {
     // Quote \ and " for use inside C programs
     // Don't use to quote a filename for #include - #include doesn't \ escape.
     putcNoTracking('"');
-    string quoted = AstNode::quoteName(strg);
+    string quoted = V3Number::quoteNameControls(strg);
     for (const char* cp=quoted.c_str(); *cp; cp++) {
 	putcNoTracking (*cp);
     }
diff --git a/src/V3Error.cpp b/src/V3FileLine.cpp
similarity index 56%
copy from src/V3Error.cpp
copy to src/V3FileLine.cpp
index 8eb7c56..7286a59 100644
--- a/src/V3Error.cpp
+++ b/src/V3FileLine.cpp
@@ -23,6 +23,7 @@
 #include <cstring>
 #include <set>
 #include "V3Error.h"
+#include "V3FileLine.h"
 #ifndef _V3ERROR_NO_GLOBAL_
 # include "V3Ast.h"
 # include "V3Global.h"
@@ -30,41 +31,6 @@
 # include "V3Config.h"
 #endif
 
-//======================================================================
-// Statics
-
-int V3Error::s_errCount = 0;
-int V3Error::s_warnCount = 0;
-int V3Error::s_debugDefault = 0;
-int V3Error::s_tellManual = 0;
-ostringstream V3Error::s_errorStr;		// Error string being formed
-V3ErrorCode V3Error::s_errorCode = V3ErrorCode::EC_FATAL;
-bool V3Error::s_errorSuppressed = false;
-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(); }
-};
-v3errorIniter v3errorInit;
-
-//######################################################################
-// ErrorCode class functions
-
-V3ErrorCode::V3ErrorCode(const char* msgp) {
-    // Return error encoding for given string, or ERROR, which is a bad code
-    for (int codei=V3ErrorCode::EC_MIN; codei<V3ErrorCode::_ENUM_MAX; codei++) {
-	V3ErrorCode code = (V3ErrorCode)codei;
-	if (0==strcasecmp(msgp,code.ascii())) {
-	    m_e = code; return;
-	}
-    }
-    m_e = V3ErrorCode::EC_ERROR;
-}
-
 //######################################################################
 // FileLineSingleton class functions
 
@@ -182,10 +148,6 @@ FileLine* FileLine::copyOrSameFileLine() {
     return newp;
 }
 
-void FileLine::updateLanguage () {
-     language(v3Global.opt.fileLanguage(filename()));
-}
-
 const string FileLine::filebasename() const {
     string name = filename();
     string::size_type pos;
@@ -228,9 +190,11 @@ bool FileLine::warnOff(const string& msg, bool flag) {
     V3ErrorCode code (msg.c_str());
     if (code < V3ErrorCode::EC_FIRST_WARN) {
 	return false;
+#ifndef _V3ERROR_NO_GLOBAL_
     } else if (v3Global.opt.lintOnly()   // Lint mode is allowed to suppress some errors
 	       && code < V3ErrorCode::EC_MIN) {
 	return false;
+#endif
     } else {
 	warnOff(code, flag);
 	return true;
@@ -328,176 +292,3 @@ void FileLine::deleteAllRemaining() {
     singleton().clear();
 #endif
 }
-
-//######################################################################
-// V3Error class functions
-
-void V3Error::init() {
-    for (int i=0; i<V3ErrorCode::_ENUM_MAX; i++) {
-	s_describedEachWarn[i] = false;
-	s_pretendError[i] = V3ErrorCode(i).pretendError();
-    }
-
-    if (string(V3ErrorCode(V3ErrorCode::_ENUM_MAX).ascii()) != " MAX") {
-	v3fatalSrc("Enum table in V3ErrorCode::EC_ascii() is munged");
-    }
-}
-
-string V3Error::lineStr (const char* filename, int lineno) {
-    ostringstream out;
-    const char* fnslashp = strrchr (filename, '/');
-    if (fnslashp) filename = fnslashp+1;
-    out<<filename<<":"<<dec<<lineno<<":";
-    const char* spaces = "                    ";
-    size_t numsp = out.str().length(); if (numsp>20) numsp = 20;
-    out<<(spaces + numsp);
-    return out.str();
-}
-
-void V3Error::incWarnings() {
-    s_warnCount++;
-    // We don't exit on a lot of warnings.
-}
-
-void V3Error::incErrors() {
-    s_errCount++;
-    if (errorCount() == v3Global.opt.errorLimit()) {  // Not >= as would otherwise recurse
-	v3fatal ("Exiting due to too many errors encountered; --error-limit="<<errorCount()<<endl);
-    }
-}
-
-void V3Error::abortIfErrors() {
-    if (errorCount()) {
-	abortIfWarnings();
-    }
-}
-
-void V3Error::abortIfWarnings() {
-    bool exwarn = v3Global.opt.warnFatal() && warnCount();
-    if (errorCount() && exwarn) {
-	v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s), "<<warnCount()<<" warning(s)\n");
-    } else if (errorCount()) {
-	v3fatal ("Exiting due to "<<dec<<errorCount()<<" error(s)\n");
-    } else if (exwarn) {
-	v3fatal ("Exiting due to "<<dec<<warnCount()<<" warning(s)\n");
-    }
-}
-
-bool V3Error::isError(V3ErrorCode code, bool supp) {
-    if (supp) return false;
-    else if (code==V3ErrorCode::EC_INFO) return false;
-    else if (code==V3ErrorCode::EC_FATAL) return true;
-    else if (code==V3ErrorCode::EC_FATALSRC) return true;
-    else if (code==V3ErrorCode::EC_ERROR) return true;
-    else if (code<V3ErrorCode::EC_FIRST_WARN
-	     || s_pretendError[code]) return true;
-    else return false;
-}
-
-string V3Error::msgPrefix() {
-    V3ErrorCode code=s_errorCode;
-    bool supp=s_errorSuppressed;
-    if (supp) return "-arning-suppressed: ";
-    else if (code==V3ErrorCode::EC_INFO) return "-Info: ";
-    else if (code==V3ErrorCode::EC_FATAL) return "%Error: ";
-    else if (code==V3ErrorCode::EC_FATALSRC) return "%Error: Internal Error: ";
-    else if (code==V3ErrorCode::EC_ERROR) return "%Error: ";
-    else if (isError(code, supp)) return "%Error-"+(string)code.ascii()+": ";
-    else return "%Warning-"+(string)code.ascii()+": ";
-}
-
-//======================================================================
-// Abort/exit
-
-void V3Error::vlAbort () {
-    if (V3Error::debugDefault()) {
-	cerr<<msgPrefix()<<"Aborting since under --debug"<<endl;
-	abort();
-    } else {
-	exit(10);
-    }
-}
-
-//======================================================================
-// Global Functions
-
-void V3Error::suppressThisWarning() {
-    if (s_errorCode>=V3ErrorCode::EC_MIN) {
-	V3Stats::addStatSum(string("Warnings, Suppressed ")+s_errorCode.ascii(), 1);
-	s_errorSuppressed = true;
-    }
-}
-
-string V3Error::warnMore() {
-    return msgPrefix();
-}
-
-void V3Error::v3errorEnd (ostringstream& sstr) {
-#if defined(__COVERITY__) || defined(__cppcheck__)
-    if (s_errorCode==V3ErrorCode::EC_FATAL) __coverity_panic__(x);
-#endif
-    // Skip suppressed messages
-    if (s_errorSuppressed
-	// On debug, show only non default-off warning to prevent pages of warnings
-	&& (!debug() || s_errorCode.defaultsOff())) return;
-    string msg = msgPrefix()+sstr.str();
-    if (msg[msg.length()-1] != '\n') msg += '\n';
-    // Suppress duplicates
-    if (s_messages.find(msg) != s_messages.end()) return;
-    s_messages.insert(msg);
-    // Output
-    cerr<<msg;
-    if (!s_errorSuppressed && s_errorCode!=V3ErrorCode::EC_INFO) {
-	if (!s_describedEachWarn[s_errorCode]
-	    && !s_pretendError[s_errorCode]) {
-	    s_describedEachWarn[s_errorCode] = true;
-	    if (s_errorCode>=V3ErrorCode::EC_FIRST_WARN && !s_describedWarnings) {
-		cerr<<msgPrefix()<<"Use \"/* verilator lint_off "<<s_errorCode.ascii()
-		    <<" */\" and lint_on around source to disable this message."<<endl;
-		s_describedWarnings = true;
-	    }
-	    if (s_errorCode.dangerous()) {
-		cerr<<msgPrefix()<<"*** See the manual before disabling this,"<<endl;
-		cerr<<msgPrefix()<<"else you may end up with different sim results."<<endl;
-	    }
-	}
-	// If first warning is not the user's fault (internal/unsupported) then give the website
-	// Not later warnings, as a internal may be caused by an earlier problem
-	if (s_tellManual == 0) {
-	    if (s_errorCode.mentionManual()
-		|| sstr.str().find("Unsupported") != string::npos) {
-		s_tellManual = 1;
-	    } else {
-		s_tellManual = 2;
-	    }
-	}
-	if (isError(s_errorCode, s_errorSuppressed)) incErrors();
-	else incWarnings();
-	if (s_errorCode==V3ErrorCode::EC_FATAL
-	    || s_errorCode==V3ErrorCode::EC_FATALSRC) {
-	    static bool inFatal = false;
-	    if (!inFatal) {
-		inFatal = true;
-		if (s_tellManual==1) {
-		    cerr<<msgPrefix()<<"See the manual and http://www.veripool.org/verilator for more assistance."<<endl;
-		    s_tellManual = 2;
-		}
-#ifndef _V3ERROR_NO_GLOBAL_
-		if (debug()) {
-		    v3Global.rootp()->dumpTreeFile(v3Global.debugFilename("final.tree",990));
-		    if (s_errorExitCb) s_errorExitCb();
-		    V3Stats::statsFinalAll(v3Global.rootp());
-		    V3Stats::statsReport();
-		}
-#endif
-	    }
-
-	    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/V3FileLine.h b/src/V3FileLine.h
new file mode 100644
index 0000000..93d1144
--- /dev/null
+++ b/src/V3FileLine.h
@@ -0,0 +1,171 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: Verilator: Error handling
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _V3FileLine_H_
+#define _V3FileLine_H_ 1
+#include "config_build.h"
+#include "verilatedos.h"
+#include <string>
+#include <iostream>
+#include <sstream>
+#include <bitset>
+#include <map>
+#include <set>
+#include <deque>
+
+#include "V3Error.h"
+#include "V3LangCode.h"
+
+//######################################################################
+
+class FileLine;
+
+//! Singleton class with tables of per-file data.
+
+//! This singleton class contains tables of data that are unchanging in each
+//! source file (each with its own unique filename number).
+class FileLineSingleton {
+    // TYPES
+    typedef map<string,int> FileNameNumMap;
+    typedef map<string,V3LangCode> FileLangNumMap;
+    // MEMBERS
+    FileNameNumMap	m_namemap;	// filenameno for each filename
+    deque<string>	m_names;	// filename text for each filenameno
+    deque<V3LangCode>	m_languages;	// language for each filenameno
+    // COSNTRUCTORS
+    FileLineSingleton() { }
+    ~FileLineSingleton() { }
+protected:
+    friend class FileLine;
+    // METHODS
+    int nameToNumber(const string& filename);
+    const string numberToName(int filenameno) const { return m_names[filenameno]; }
+    const V3LangCode numberToLang(int filenameno) const { return m_languages[filenameno]; }
+    void numberToLang(int filenameno, const V3LangCode& l) { m_languages[filenameno] = l; }
+    void clear() { m_namemap.clear(); m_names.clear(); m_languages.clear(); }
+    void fileNameNumMapDumpXml(ostream& os);
+    static const string filenameLetters(int fileno);
+};
+
+//! File and line number of an object, mostly for error reporting
+
+//! This class is instantiated for every source code line (potentially
+//! millions). To save space, per-file information (e.g. filename, source
+//! language is held in tables in the FileLineSingleton class.
+class FileLine {
+    int		m_lineno;
+    int		m_filenameno;
+    bitset<V3ErrorCode::_ENUM_MAX>	m_warnOn;
+
+private:
+    struct EmptySecret {};
+    inline static FileLineSingleton& singleton() {
+	static FileLineSingleton s;
+	return s;
+    }
+    inline static FileLine& defaultFileLine() {
+	static FileLine* defFilelinep = new FileLine(FileLine::EmptySecret());
+	return *defFilelinep;
+    }
+protected:
+    // User routines should never need to change line numbers
+    // We are storing pointers, so we CAN'T change them after initial reading.
+    friend class FileLineSingleton;
+    friend class V3ParseImp;
+    friend class V3PreLex;
+    friend class V3PreProcImp;
+    void lineno(int num) { m_lineno = num; }
+    void language (V3LangCode lang) { singleton().numberToLang(m_filenameno, lang); }
+    void filename(const string& name) { m_filenameno = singleton().nameToNumber(name); }
+    void lineDirective(const char* textp, int& enterExitRef);
+    void linenoInc() { m_lineno++; }
+    void linenoIncInPlace() { m_lineno++; }
+    FileLine* copyOrSameFileLine();
+public:
+    FileLine (const string& filename, int lineno) {
+	m_lineno=lineno; m_filenameno = singleton().nameToNumber(filename);
+	m_warnOn=defaultFileLine().m_warnOn; }
+    FileLine (FileLine* fromp) {
+	m_lineno=fromp->m_lineno; m_filenameno = fromp->m_filenameno; m_warnOn=fromp->m_warnOn; }
+    FileLine (EmptySecret);
+    ~FileLine() { }
+    FileLine* create(const string& filename, int lineno) { return new FileLine(filename,lineno); }
+    FileLine* create(int lineno) { return create(filename(), lineno); }
+    static void deleteAllRemaining();
+#ifdef VL_LEAK_CHECKS
+    static void* operator new(size_t size);
+    static void operator delete(void* obj, size_t size);
+#endif
+
+    int lineno () const { return m_lineno; }
+    V3LangCode language () const { return singleton().numberToLang(m_filenameno); }
+    string ascii() const;
+    const string filename () const { return singleton().numberToName(m_filenameno); }
+    const string filenameLetters() const { return singleton().filenameLetters(m_filenameno); }
+    const string filebasename () const;
+    const string filebasenameNoExt () const;
+    const string profileFuncname() const;
+    const string xml() const { return "fl=\""+filenameLetters()+cvtToStr(lineno())+"\""; }
+    string lineDirectiveStrg(int enter_exit_level) const;
+    void warnOn(V3ErrorCode code, bool flag) { m_warnOn.set(code,flag); }	// Turn on/off warning messages on this line.
+    void warnOff(V3ErrorCode code, bool flag) { warnOn(code,!flag); }
+    bool warnOff(const string& code, bool flag);  // Returns 1 if ok
+    bool warnIsOff(V3ErrorCode code) const;
+    void warnLintOff(bool flag);
+    void warnStyleOff(bool flag);
+    void warnStateFrom(const FileLine& from) { m_warnOn=from.m_warnOn; }
+    void warnResetDefault() { warnStateFrom(defaultFileLine()); }
+
+    // Specific flag ACCESSORS/METHODS
+    bool coverageOn() const { return m_warnOn.test(V3ErrorCode::I_COVERAGE); }
+    void coverageOn(bool flag) { warnOn(V3ErrorCode::I_COVERAGE,flag); }
+    bool tracingOn() const { return m_warnOn.test(V3ErrorCode::I_TRACING); }
+    void tracingOn(bool flag) { warnOn(V3ErrorCode::I_TRACING,flag); }
+
+    // METHODS - Global
+    static void globalWarnLintOff(bool flag) {
+	defaultFileLine().warnLintOff(flag); }
+    static void globalWarnStyleOff(bool flag) {
+	defaultFileLine().warnStyleOff(flag); }
+    static void globalWarnOff(V3ErrorCode code, bool flag) {
+	defaultFileLine().warnOff(code, flag); }
+    static bool globalWarnOff(const string& code, bool flag) {
+	return defaultFileLine().warnOff(code, flag); }
+    static void fileNameNumMapDumpXml(ostream& os) {
+	singleton().fileNameNumMapDumpXml(os); }
+
+    // METHODS - Called from netlist
+    // Merge warning disables from another fileline
+    void modifyStateInherit(const FileLine* fromp);
+    // Change the current fileline due to actions discovered after parsing
+    // and may have side effects on other nodes sharing this FileLine.
+    // Use only when this is intended
+    void modifyWarnOff(V3ErrorCode code, bool flag) { warnOff(code,flag); }
+
+    // OPERATORS
+    void v3errorEnd(ostringstream& str);
+    string warnMore() const;
+    inline bool operator==(FileLine rhs) const {
+	return (m_lineno==rhs.m_lineno && m_filenameno==rhs.m_filenameno && m_warnOn==rhs.m_warnOn);
+    }
+};
+ostream& operator<<(ostream& os, FileLine* fileline);
+
+#endif // Guard
diff --git a/src/V3Global.h b/src/V3Global.h
index af98327..a4b4fac 100644
--- a/src/V3Global.h
+++ b/src/V3Global.h
@@ -26,6 +26,7 @@
 #include <string>
 
 #include "V3Error.h"
+#include "V3FileLine.h"
 #include "V3Options.h"
 
 class AstNetlist;
diff --git a/src/V3LinkDot.cpp b/src/V3LinkDot.cpp
index 82b0937..204d29b 100644
--- a/src/V3LinkDot.cpp
+++ b/src/V3LinkDot.cpp
@@ -1805,6 +1805,15 @@ private:
 	// EnumItemRef may be under a dot.  Should already be resolved.
 	nodep->iterateChildren(*this);
     }
+    virtual void visit(AstMethodSel* nodep, AstNUser*) {
+	// Created here so should already be resolved.
+	DotStates lastStates = m_ds;
+	{
+	    m_ds.init(m_curSymp);
+	    nodep->iterateChildren(*this);
+	}
+	m_ds = lastStates;
+    }
     virtual void visit(AstVar* nodep, AstNUser*) {
 	checkNoDot(nodep);
 	nodep->iterateChildren(*this);
@@ -1823,6 +1832,14 @@ private:
 	    m_ds.m_dotp = NULL;
 	} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_FINAL) {
 	    nodep->dotted(m_ds.m_dotText);  // Maybe ""
+	} else if (m_ds.m_dotp && m_ds.m_dotPos == DP_MEMBER) {
+	    // Found a Var, everything following is method call.  {scope}.{var}.HERE {method} ( ARGS )
+	    AstNode* varEtcp = m_ds.m_dotp->lhsp()->unlinkFrBack();
+	    AstNode* argsp = NULL; if (nodep->pinsp()) argsp = nodep->pinsp()->unlinkFrBackWithNext();
+	    AstNode* newp = new AstMethodSel(nodep->fileline(), varEtcp, VFlagChildDType(), nodep->name(), argsp);
+	    nodep->replaceWith(newp);
+	    pushDeletep(nodep); nodep=NULL;
+	    return;
 	} else {
 	    checkNoDot(nodep);
 	}
diff --git a/src/V3LinkLevel.cpp b/src/V3LinkLevel.cpp
index 3b924c7..9d9c393 100644
--- a/src/V3LinkLevel.cpp
+++ b/src/V3LinkLevel.cpp
@@ -130,7 +130,12 @@ void V3LinkLevel::wrapTopCell(AstNetlist* netlistp) {
 		    oldvarp->primaryIO(true);
 		    varp->primaryIO(true);
 		}
-		if (varp->isIO() && v3Global.opt.systemC()) varp->sc(true);
+		if (varp->isIO() && v3Global.opt.systemC()) {
+		    varp->sc(true);
+		    // User can see trace one level down from the wrapper
+		    // Avoids packing & unpacking SC signals a second time
+		    varp->trace(false);
+		}
 
 		AstPin* pinp = new AstPin(oldvarp->fileline(),0,oldvarp->name(),
 					  new AstVarRef(varp->fileline(),
diff --git a/src/V3Number.cpp b/src/V3Number.cpp
index 79c6814..73606a7 100644
--- a/src/V3Number.cpp
+++ b/src/V3Number.cpp
@@ -34,7 +34,7 @@
 // Read class functions
 // CREATION
 
-V3Number::V3Number(VerilogString, FileLine* fileline, const string& str) {
+V3Number::V3Number(VerilogStringLiteral, FileLine* fileline, const string& str) {
     // Create a number using a verilog string as the value, thus 8 bits per character.
     // cppcheck bug - doesn't see init() resets these
     // cppcheck: Member variable 'm_sized/m_width' is not initialized in the constructor
@@ -365,6 +365,8 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
 	if (width()!=64) out<<"%E-bad-width-double";
 	else out<<toDouble();
 	return out.str();
+    } else if (isString()) {
+	return '"'+toString()+'"';
     } else {
 	if ((m_value[words()-1] | m_valueX[words()-1]) & ~hiWordMask()) out<<"%E-hidden-bits";
     }
@@ -404,6 +406,31 @@ string V3Number::ascii(bool prefixed, bool cleanVerilog) const {
     return out.str();
 }
 
+string V3Number::quoteNameControls(const string& namein) {
+    // Encode control chars into C style escapes
+    // Reverse is V3Parse::deQuote
+    const char* start = namein.c_str();
+    string out;
+    for (const char* pos = start; *pos; pos++) {
+	if (pos[0]=='\\' || pos[0]=='"') {
+	    out += string("\\")+pos[0];
+	} else if (pos[0]=='\n') {
+	    out += "\\n";
+	} else if (pos[0]=='\r') {
+	    out += "\\r";
+	} else if (pos[0]=='\t') {
+	    out += "\\t";
+	} else if (isprint(pos[0])) {
+	    out += pos[0];
+	} else {
+	    // This will also cover \a etc
+	    char octal[10]; sprintf(octal,"\\%03o",pos[0]);
+	    out += octal;
+	}
+    }
+    return out;
+}
+
 bool V3Number::displayedFmtLegal(char format) {
     // Is this a valid format letter?
     switch (tolower(format)) {
@@ -418,6 +445,7 @@ bool V3Number::displayedFmtLegal(char format) {
     case 's': return true;
     case 't': return true;
     case 'x': return true;
+    case '@': return true; // Packed string
     case '~': return true; // Signed decimal
     default: return false;
     }
@@ -473,6 +501,9 @@ string V3Number::displayed(const string& vformat) const {
 	str += (char)(v);
 	return str;
     }
+    case '@': {  // Packed string
+	return toString();
+    }
     case 's': {
 	// Spec says always drop leading zeros, this isn't quite right, we space pad.
 	int bit=this->width()-1;
@@ -581,6 +612,7 @@ vlsint64_t V3Number::toSQuad() const {
 string V3Number::toString() const {
     UASSERT(!isFourState(),"toString with 4-state "<<*this);
     // Spec says always drop leading zeros, this isn't quite right, we space pad.
+    if (isString()) return m_stringVal;
     int bit=this->width()-1;
     bool start=true;
     while ((bit%8)!=7) bit++;
@@ -1626,3 +1658,38 @@ V3Number& V3Number::opLtD (const V3Number& lhs, const V3Number& rhs) {
 V3Number& V3Number::opLteD (const V3Number& lhs, const V3Number& rhs) {
     return setSingleBits(lhs.toDouble() <= rhs.toDouble());
 }
+
+//======================================================================
+// Ops - String
+
+V3Number& V3Number::opConcatN (const V3Number& lhs, const V3Number& rhs) {
+    return setString(lhs.toString() + rhs.toString());
+}
+V3Number& V3Number::opReplN (const V3Number& lhs, const V3Number& rhs) {
+    return opReplN(lhs, rhs.toUInt());
+}
+V3Number& V3Number::opReplN (const V3Number& lhs, uint32_t rhsval) {
+    string out; out.reserve(lhs.toString().length() * rhsval);
+    for (unsigned times=0; times<rhsval; times++) {
+	out += lhs.toString();
+    }
+    return setString(out);
+}
+V3Number& V3Number::opEqN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() == rhs.toString());
+}
+V3Number& V3Number::opNeqN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() != rhs.toString());
+}
+V3Number& V3Number::opGtN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() > rhs.toString());
+}
+V3Number& V3Number::opGteN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() >= rhs.toString());
+}
+V3Number& V3Number::opLtN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() < rhs.toString());
+}
+V3Number& V3Number::opLteN (const V3Number& lhs, const V3Number& rhs) {
+    return setSingleBits(lhs.toString() <= rhs.toString());
+}
diff --git a/src/V3Number.h b/src/V3Number.h
index c6bfd53..e002eaa 100644
--- a/src/V3Number.h
+++ b/src/V3Number.h
@@ -25,6 +25,7 @@
 #include <vector>
 
 #include "V3Error.h"
+#include "V3FileLine.h"
 
 //============================================================================
 
@@ -34,13 +35,16 @@ class V3Number {
     bool	m_sized:1;	// True if the user specified the width, else we track it.
     bool	m_signed:1;	// True if signed value
     bool	m_double:1;	// True if double real value
-    bool	m_fromString:1;	// True if from string
+    bool	m_isString:1;	// True if string
+    bool	m_fromString:1;	// True if from string literal
     bool	m_autoExtend:1;	// True if SystemVerilog extend-to-any-width
     FileLine*	m_fileline;
     vector<uint32_t>	m_value;	// The Value, with bit 0 being in bit 0 of this vector (unless X/Z)
     vector<uint32_t>	m_valueX;	// Each bit is true if it's X or Z, 10=z, 11=x
+    string		m_stringVal;	// If isString, the value of the string
     // METHODS
     V3Number& setSingleBits(char value);
+    V3Number& setString(const string& str) { m_isString=true; m_stringVal=str; return *this; }
     void opCleanThis();
 public:
     FileLine*	fileline() const { return m_fileline; }
@@ -115,19 +119,22 @@ private:
     V3Number& opModDivGuts(const V3Number& lhs, const V3Number& rhs, bool is_modulus);
 
 public:
-    class VerilogString {};	// for creator type-overload selection
     // CONSTRUCTORS
     V3Number(FileLine* fileline) { init(fileline, 1); }
     V3Number(FileLine* fileline, int width) { init(fileline, width); }  // 0=unsized
     V3Number(FileLine* fileline, int width, uint32_t value) { init(fileline, width); m_value[0]=value; opCleanThis(); }
     V3Number(FileLine* fileline, const char* source);	// Create from a verilog 32'hxxxx number.
-    V3Number(VerilogString, FileLine* fileline, const string& vvalue);
+    class VerilogStringLiteral {};	// for creator type-overload selection
+    V3Number(VerilogStringLiteral, FileLine* fileline, const string& vvalue);
+    class String {};
+    V3Number(String, FileLine* fileline, const string& value) { init(fileline, 0); setString(value); }
 
 private:
     void init(FileLine* fileline, int swidth) {
 	m_fileline = fileline;
 	m_signed = false;
 	m_double = false;
+	m_isString = false;
 	m_autoExtend = false;
 	m_fromString = false;
 	width(swidth);
@@ -154,6 +161,7 @@ public:
 
     // ACCESSORS
     string ascii(bool prefixed=true, bool cleanVerilog=false) const;
+    static string quoteNameControls(const string& namein); // Add backslash quotes to strings
     string displayed(const string& format) const;
     static bool displayedFmtLegal(char format);  // Is this a valid format letter?
     int width() const { return m_width; }
@@ -164,6 +172,8 @@ public:
     bool isSigned() const { return m_signed; }	// Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
     bool isDouble() const { return m_double; }	// Only correct for parsing of numbers from strings, otherwise not used (use AstConst::isSigned())
     void isDouble(bool flag)  { m_double=flag; } // Only if have 64 bit value loaded, and want to indicate it's real
+    bool isString() const { return m_isString; }
+    void isString(bool flag)  { m_isString=flag; }
     bool isNegative() const { return bitIs1(width()-1); }
     bool isFourState() const { for (int i=0;i<words();i++) {if (m_valueX[i]) return true;} return false; }
     bool hasZ() const { for(int i=0;i<words();i++) {if((~m_value[i]) & m_valueX[i]) return true;} return false;}
@@ -293,6 +303,17 @@ public:
     V3Number& opGteD	(const V3Number& lhs, const V3Number& rhs);
     V3Number& opLtD	(const V3Number& lhs, const V3Number& rhs);
     V3Number& opLteD	(const V3Number& lhs, const V3Number& rhs);
+
+    // "N" - string operations
+    V3Number& opConcatN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opReplN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opReplN	(const V3Number& lhs, uint32_t rhs);
+    V3Number& opEqN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opNeqN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opGtN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opGteN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opLtN	(const V3Number& lhs, const V3Number& rhs);
+    V3Number& opLteN	(const V3Number& lhs, const V3Number& rhs);
 };
 inline ostream& operator<<(ostream& os, V3Number rhs) { return os<<rhs.ascii(); }
 
diff --git a/src/V3Number_test.cpp b/src/V3Number_test.cpp
index fe3321d..868ba32 100644
--- a/src/V3Number_test.cpp
+++ b/src/V3Number_test.cpp
@@ -22,6 +22,7 @@
 #define V3NUMBER_ASCII_BINARY
 #define _V3ERROR_NO_GLOBAL_ 1
 #include "V3Error.cpp"
+#include "V3FileLine.cpp"
 #include "V3Number.cpp"
 
 #include <config_build.h>
diff --git a/src/V3Options.cpp b/src/V3Options.cpp
index a5b582d..3f81aeb 100644
--- a/src/V3Options.cpp
+++ b/src/V3Options.cpp
@@ -275,18 +275,18 @@ bool V3Options::filenameIsRel(const string& filename) {
 }
 
 bool V3Options::fileStatDir(const string& filename) {
-    struct stat	m_stat;		// Stat information
-    int err = stat(filename.c_str(), &m_stat);
+    struct stat	sstat;		// Stat information
+    int err = stat(filename.c_str(), &sstat);
     if (err!=0) return false;
-    if (!S_ISDIR(m_stat.st_mode)) return false;
+    if (!S_ISDIR(sstat.st_mode)) return false;
     return true;
 }
 
 bool V3Options::fileStatNormal(const string& filename) {
-    struct stat	m_stat;		// Stat information
-    int err = stat(filename.c_str(), &m_stat);
+    struct stat	sstat;		// Stat information
+    int err = stat(filename.c_str(), &sstat);
     if (err!=0) return false;
-    if (S_ISDIR(m_stat.st_mode)) return false;
+    if (S_ISDIR(sstat.st_mode)) return false;
     return true;
 }
 
@@ -754,14 +754,14 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
 	    else if ( onoff   (sw, "-pins-uint8", flag/*ref*/) ){ m_pinsUint8 = flag; }
 	    else if ( !strcmp (sw, "-private") )		{ m_public = false; }
 	    else if ( onoff   (sw, "-profile-cfuncs", flag/*ref*/) )	{ m_profileCFuncs = flag; }
-	    else if ( onoff   (sw, "-psl-deprecated", flag/*ref*/) )	{ m_psl = flag; }  // Undocumented
 	    else if ( onoff   (sw, "-public", flag/*ref*/) )		{ m_public = flag; }
 	    else if ( onoff   (sw, "-report-unoptflat", flag/*ref*/) )	{ m_reportUnoptflat = flag; }
 	    else if ( onoff   (sw, "-savable", flag/*ref*/) )		{ m_savable = flag; }
 	    else if ( !strcmp (sw, "-sc") )				{ m_outFormatOk = true; m_systemC = true; m_systemPerl = false; }
 	    else if ( onoff   (sw, "-skip-identical", flag/*ref*/) )	{ m_skipIdentical = flag; }
-	    else if ( !strcmp (sw, "-sp") )				{ m_outFormatOk = true; m_systemC = true; m_systemPerl = true; }
+	    else if ( !strcmp (sw, "-sp-deprecated") )			{ m_outFormatOk = true; m_systemC = true; m_systemPerl = true; } // Undocumented, old
 	    else if ( onoff   (sw, "-stats", flag/*ref*/) )		{ m_stats = flag; }
+	    else if ( onoff   (sw, "-stats-vars", flag/*ref*/) )	{ m_statsVars = flag; m_stats |= flag; }
 	    else if ( !strcmp (sw, "-sv") )				{ m_defaultLanguage = V3LangCode::L1800_2005; }
 	    else if ( onoff   (sw, "-trace", flag/*ref*/) )		{ m_trace = flag; }
 	    else if ( onoff   (sw, "-trace-dups", flag/*ref*/) )	{ m_traceDups = flag; }
@@ -833,7 +833,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
 	    }
 	    else if ( !strcmp (sw, "-error-limit") && (i+1)<argc ) {
 		shift;
-		m_errorLimit = atoi(argv[i]);
+		V3Error::errorLimit(atoi(argv[i]));
 	    }
 	    else if ( !strncmp (sw, "-I", 2)) {
 		addIncDirUser (parseFileArg(optdir, string (sw+strlen("-I"))));
@@ -947,7 +947,7 @@ void V3Options::parseOptsList(FileLine* fl, const string& optdir, int argc, char
 		    FileLine::globalWarnStyleOff(true);
 		}
 		else if (!strcmp (sw, "-Wno-fatal")) {
-		    m_warnFatal = false;
+		    V3Error::warnFatal(false);
 		}
 		else {
 		    string msg = sw+strlen("-Wno-");
@@ -1221,16 +1221,15 @@ V3Options::V3Options() {
     m_makePhony = false;
     m_orderClockDly = true;
     m_outFormatOk = false;
-    m_warnFatal = true;
     m_pinsBv = 65;
     m_profileCFuncs = false;
     m_preprocOnly = false;
     m_preprocNoLine = false;
-    m_psl = false;
     m_public = false;
     m_savable = false;
     m_skipIdentical = true;
     m_stats = false;
+    m_statsVars = false;
     m_systemC = false;
     m_systemPerl = false;
     m_trace = false;
@@ -1245,7 +1244,6 @@ V3Options::V3Options() {
 
     m_convergeLimit = 100;
     m_dumpTree = 0;
-    m_errorLimit = 50;
     m_ifDepth = 0;
     m_inlineMult = 2000;
     m_outputSplit = 0;
diff --git a/src/V3Options.h b/src/V3Options.h
index 4e1c936..6eb2200 100644
--- a/src/V3Options.h
+++ b/src/V3Options.h
@@ -77,18 +77,17 @@ class V3Options {
     bool	m_lintOnly;	// main switch: --lint-only
     bool	m_orderClockDly;// main switch: --order-clock-delay
     bool	m_outFormatOk;	// main switch: --cc, --sc or --sp was specified
-    bool	m_warnFatal;	// main switch: --warnFatal
     bool	m_pinsScUint;   // main switch: --pins-sc-uint
     bool	m_pinsScBigUint;// main switch: --pins-sc-biguint
     bool	m_pinsUint8;	// main switch: --pins-uint8
     bool	m_profileCFuncs;// main switch: --profile-cfuncs
-    bool	m_psl;		// main switch: --psl
     bool	m_public;	// main switch: --public
     bool	m_savable;	// main switch: --savable
     bool	m_systemC;	// main switch: --sc: System C instead of simple C++
     bool	m_skipIdentical;// main switch: --skip-identical
     bool	m_systemPerl;	// main switch: --sp: System Perl instead of SystemC (m_systemC also set)
     bool	m_stats;	// main switch: --stats
+    bool	m_statsVars;	// main switch: --stats-vars
     bool	m_trace;	// main switch: --trace
     bool	m_traceDups;	// main switch: --trace-dups
     bool	m_traceParams;	// main switch: --trace-params
@@ -101,7 +100,6 @@ class V3Options {
 
     int		m_convergeLimit;// main switch: --converge-limit
     int		m_dumpTree;	// main switch: --dump-tree
-    int		m_errorLimit;	// main switch: --error-limit
     int		m_ifDepth;	// main switch: --if-depth
     int		m_inlineMult;	// main switch: --inline-mult
     int		m_outputSplit;	// main switch: --output-split
@@ -201,10 +199,11 @@ class V3Options {
     bool systemC() const { return m_systemC; }
     bool systemPerl() const { return m_systemPerl; }
     bool usingSystemCLibs() const { return !lintOnly() && (systemPerl() || systemC()); }
-    bool usingSystemPerlLibs() const { return !lintOnly() && (systemPerl() || coverage()); }
+    bool usingSystemPerlLibs() const { return !lintOnly() && systemPerl(); }
     bool savable() const { return m_savable; }
     bool skipIdentical() const { return m_skipIdentical; }
     bool stats() const { return m_stats; }
+    bool statsVars() const { return m_statsVars; }
     bool assertOn() const { return m_assert; }  // assertOn as __FILE__ may be defined
     bool autoflush() const { return m_autoflush; }
     bool bboxSys() const { return m_bboxSys; }
@@ -225,12 +224,10 @@ class V3Options {
     bool orderClockDly() const { return m_orderClockDly; }
     bool outFormatOk() const { return m_outFormatOk; }
     bool keepTempFiles() const { return (V3Error::debugDefault()!=0); }
-    bool warnFatal() const { return m_warnFatal; }
     bool pinsScUint() const { return m_pinsScUint; }
     bool pinsScBigUint() const { return m_pinsScBigUint; }
     bool pinsUint8() const { return m_pinsUint8; }
     bool profileCFuncs() const { return m_profileCFuncs; }
-    bool psl() const { return m_psl; }
     bool allPublic() const { return m_public; }
     bool l2Name() const { return m_l2Name; }
     bool lintOnly() const { return m_lintOnly; }
@@ -242,7 +239,6 @@ class V3Options {
 
     int	   convergeLimit() const { return m_convergeLimit; }
     int    dumpTree() const { return m_dumpTree; }
-    int	   errorLimit() const { return m_errorLimit; }
     int	   ifDepth() const { return m_ifDepth; }
     int	   inlineMult() const { return m_inlineMult; }
     int	   outputSplit() const { return m_outputSplit; }
diff --git a/src/V3ParseImp.cpp b/src/V3ParseImp.cpp
index 48fb58b..819a743 100644
--- a/src/V3ParseImp.cpp
+++ b/src/V3ParseImp.cpp
@@ -104,7 +104,7 @@ void V3ParseImp::parseFile(FileLine* fileline, const string& modfilename, bool i
 	// of this source file is updated here, in case there have been any
 	// intervening +<lang>ext+ options since it was first ecountered.
 	FileLine *modfileline = new FileLine (modfilename, 0);
-	modfileline->updateLanguage();
+	modfileline->language(v3Global.opt.fileLanguage(modfilename));
 	ppPushText((string)"`begin_keywords \""+modfileline->language().ascii()+"\"\n");
     }
 
diff --git a/src/V3ParseImp.h b/src/V3ParseImp.h
index 84b9085..b439ca6 100644
--- a/src/V3ParseImp.h
+++ b/src/V3ParseImp.h
@@ -23,6 +23,7 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
+#include "V3FileLine.h"
 #include "V3Global.h"
 #include "V3Parse.h"
 #include "V3ParseSym.h"
@@ -131,7 +132,6 @@ public:
 
     // Functions called by lex rules:
     int yylexThis();
-    static bool optPsl() { return v3Global.opt.psl(); }
     static bool optFuture(const string& flag) { return v3Global.opt.isFuture(flag); }
 
     void ppline (const char* text);
@@ -190,8 +190,6 @@ public:
     // Interactions with lexer
     void lexNew(int debug);
     void lexDestroy();
-    void stateExitPsl();	// Parser -> lexer communication
-    void statePushVlg();	// Parser -> lexer communication
     void statePop();		// Parser -> lexer communication
     static int stateVerilogRecent();	// Parser -> lexer communication
     int	prevLexToken() { return m_prevLexToken; } // Parser -> lexer communication
diff --git a/src/V3ParseLex.cpp b/src/V3ParseLex.cpp
index 1379734..f412ae7 100644
--- a/src/V3ParseLex.cpp
+++ b/src/V3ParseLex.cpp
@@ -47,13 +47,6 @@ public:
     V3Lexer() : V3LexerBase(NULL) {}
     ~V3Lexer() {}
     // METHODS
-    void stateExitPsl() {
-	if (YY_START != PSL) yyerrorf("Internal error: Exiting PSL state when not in PSL state");
-	yy_pop_state();
-    }
-    void statePushVlg() {
-	yy_push_state(STATE_VERILOG_RECENT);
-    }
     void statePop() {
 	yy_pop_state();
     }
@@ -65,8 +58,6 @@ public:
 	}
     }
 };
-void V3ParseImp::stateExitPsl() { parsep()->m_lexerp->stateExitPsl(); }
-void V3ParseImp::statePushVlg() { parsep()->m_lexerp->stateExitPsl(); }
 void V3ParseImp::statePop()	{ parsep()->m_lexerp->statePop(); }
 
 void V3ParseImp::unputString(const char* textp, size_t length) { parsep()->m_lexerp->unputString(textp, length); }
diff --git a/src/V3ParseSym.h b/src/V3ParseSym.h
index cb7d507..da68ddd 100644
--- a/src/V3ParseSym.h
+++ b/src/V3ParseSym.h
@@ -23,6 +23,7 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
+#include "V3FileLine.h"
 #include "V3Global.h"
 #include "V3SymTable.h"
 #include <deque>
diff --git a/src/V3PreLex.h b/src/V3PreLex.h
index 1c5cf17..589d8d2 100644
--- a/src/V3PreLex.h
+++ b/src/V3PreLex.h
@@ -31,6 +31,7 @@
 #include <stack>
 
 #include "V3Error.h"
+#include "V3FileLine.h"
 
 //======================================================================
 
@@ -166,8 +167,6 @@ class V3PreLex {
     // State from lexer
     int		m_formalLevel;	// Parenthesis counting inside def formals
     int		m_parenLevel;	// Parenthesis counting inside def args
-    int		m_pslParenLevel;// PSL Parenthesis (){} counting, so we can find final ;
-    bool	m_pslMoreNeeded;// Next // comment is really psl
     bool	m_defCmtSlash;	// /*...*/ comment in define had \ ending
     bool	m_defQuote;	// Definition value inside quote
     string	m_defValue;	// Definition value being built.
@@ -186,8 +185,6 @@ class V3PreLex {
 	m_defCmtSlash = false;
 	m_tokFilelinep = filelinep;
 	m_enterExit = 0;
-	m_pslParenLevel = 0;
-	m_pslMoreNeeded = false;
 	initFirstBuffer(filelinep);
     }
     ~V3PreLex() {
diff --git a/src/V3PreLex.l b/src/V3PreLex.l
index 58191a9..2592a29 100644
--- a/src/V3PreLex.l
+++ b/src/V3PreLex.l
@@ -42,24 +42,14 @@ void yyourtext(const char* textp, size_t size) { yytext=(char*)textp; yyleng=siz
 
 // Prevent conflicts from perl version
 static void linenoInc()  {LEXP->linenoInc();}
-static bool optPsl() { return V3PreProc::optPsl(); }
 static bool pedantic() { return LEXP->m_pedantic; }
 static void yyerror(char* msg) { LEXP->curFilelinep()->v3error(msg); }
 static void yyerrorf(const char* msg) { LEXP->curFilelinep()->v3error(msg); }
 static void appendDefValue(const char* t, size_t l) { LEXP->appendDefValue(t,l); }
-static int  pslParenLevel()    { return LEXP->m_pslParenLevel; }
-static void pslParenLevelInc() { LEXP->m_pslParenLevel++; }
-static void pslParenLevelDec() { if (pslParenLevel()) LEXP->m_pslParenLevel--; }
-static bool pslMoreNeeded()    { return LEXP->m_pslMoreNeeded; }
-static void pslMoreNeeded(bool flag) { LEXP->m_pslMoreNeeded = flag; }
 
 /**********************************************************************/
 %}
 
-%x PSLONEM
-%x PSLONEE
-%x PSLMULM
-%x PSLMUL1
 %x CMTONEM
 %x CMTBEGM
 %x CMTMODE
@@ -86,7 +76,6 @@ symb		([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n]+)
 symbdef		([a-zA-Z_][a-zA-Z0-9_$]*|\\[^ \t\f\r\n`]+)
 word		[a-zA-Z0-9_]+
 drop		[\032]
-psl		[p]sl
 
 	/**************************************************************/
 %%
@@ -117,7 +106,7 @@ psl		[p]sl
 <INITIAL>"`error"	{ if (!pedantic()) return (VP_ERROR); else return(VP_DEFREF); }
 
 	/* Pass-through strings */
-<INITIAL,PSLMULM,PSLONEM>{quote}	{ yy_push_state(STRMODE); yymore(); }
+<INITIAL>{quote}	{ yy_push_state(STRMODE); yymore(); }
 <STRMODE><<EOF>>	{ linenoInc(); yyerrorf("EOF in unterminated string"); yyleng=0; yyterminate(); }
 <STRMODE>{crnl}		{ linenoInc(); yyerrorf("Unterminated string"); BEGIN(INITIAL); }
 <STRMODE>{word}		{ yymore(); }
@@ -233,57 +222,36 @@ psl		[p]sl
 <ARGMODE>.		{ appendDefValue(yytext,yyleng); }
 
 	/* One line comments. */
-<INITIAL>"//"{ws}*{psl} { if (optPsl())        { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
-			  else { yy_push_state(CMTONEM); yymore(); } }
 <INITIAL>"//"{ws}*{crnl} { linenoInc(); yytext=(char*)"\n"; yyleng=1; return (VP_WHITE); }
-<INITIAL>"//" 		{ if (pslMoreNeeded()) { pslMoreNeeded(true); yy_push_state(PSLONEM); return(VP_PSL); }
-			  else { yy_push_state(CMTONEM); yymore(); } }
+<INITIAL>"//" 		{ yy_push_state(CMTONEM); yymore(); }
 <CMTONEM>[^\n\r]* 	{ yy_pop_state(); return (VP_COMMENT); }
 
-	/* Psl oneline comments */
-<PSLONEM>[{(]		{ pslParenLevelInc(); return (VP_TEXT); }
-<PSLONEM>[})]		{ pslParenLevelDec(); return (VP_TEXT); }
-<PSLONEM>[;]		{ if (!pslParenLevel()) {BEGIN PSLONEE; pslMoreNeeded(false);} return (VP_TEXT); }
-<PSLONEM>{crnl}		{ linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
-
-	/* Completed psl oneline comments */
-<PSLONEE>{crnl}		{ linenoInc(); yy_pop_state(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
-<PSLONEE>{ws}+		{ yymore(); }
-<PSLONEE>.		{ yyerrorf("Unexpected text following psl assertion\n"); }
-
 	/* C-style comments. */
 	/**** See also DEFCMT */
-	/* We distinguish between the start of a comment, and later, so we may find a "psl" prefix */
-<INITIAL>"/*"		{ yy_push_state(optPsl() ? CMTBEGM : CMTMODE); yymore(); }
-<CMTBEGM>{psl}		{ yyleng -= 3; BEGIN PSLMUL1; return (VP_COMMENT); }
+	/* We distinguish between the start of a comment, and later, to look for prefix comments (deprecated) */
+<INITIAL>"/*"		{ yy_push_state(CMTMODE); yymore(); }
 <CMTBEGM>{ws}+		{ yymore(); }
 <CMTBEGM,CMTMODE>"*/"		{ yy_pop_state(); return(VP_COMMENT); }
 <CMTBEGM,CMTMODE>{crnl}		{ linenoInc(); yymore(); }
 <CMTBEGM,CMTMODE><<EOF>>	{ yyerrorf("EOF in '/* ... */' block comment\n"); yyleng=0; yyterminate(); }
 <CMTMODE>{word}			{ yymore(); }
-<CMTBEGM>.			{ BEGIN CMTMODE; yymore(); }	/* Non 'psl' beginning in comment */
+<CMTBEGM>.			{ BEGIN CMTMODE; yymore(); }	/* beginning in comment */
 <CMTMODE>.			{ yymore(); }
 
-	/* Psl C-style comments. */
-	/* EOFs are normal because / * `foo(..) * / hits a unputString EOF */
-<PSLMUL1>.|{crnl}	{ yyless(0); BEGIN PSLMULM; return(VP_PSL); }
-<PSLMULM>"*/"		{ yy_pop_state(); return(VP_COMMENT); }
-<PSLMULM>"//"[^\n\r]*	{ return (VP_COMMENT); }	/* Comments inside block comments get literal inclusion (later removal) */
-
 	/* Define calls */
 	/* symbdef prevents normal lex rules from making `\`"foo a symbol {`"foo} instead of a BACKQUOTE */
-<INITIAL,PSLMULM,PSLONEM>"`"{symbdef}	{ return (VP_DEFREF); }
-<INITIAL,PSLMULM,PSLONEM>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
+<INITIAL>"`"{symbdef}	{ return (VP_DEFREF); }
+<INITIAL>"`"{symbdef}`` { yyleng-=2; return (VP_DEFREF_JOIN); }
 
 	/* Generics */
-<INITIAL,PSLMULM>{crnl}		{ linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
-<INITIAL,PSLMULM,PSLONEM><<EOF>>  { yyterminate(); }  /* A "normal" EOF */
-<INITIAL,PSLMULM,PSLONEM>{symb}	  { return (VP_SYMBOL); }
-<INITIAL,PSLMULM,PSLONEM>{symb}`` { yyleng-=2; return (VP_SYMBOL_JOIN); }
-<INITIAL,PSLMULM,PSLONEM>{wsn}+	{ return (VP_WHITE); }
-<INITIAL,PSLMULM,PSLONEM>{drop}	{ }
-<INITIAL,PSLMULM,PSLONEM>[\r]	{ }
-<INITIAL,PSLMULM,PSLONEM>.	{ return (VP_TEXT); }
+<INITIAL>{crnl}		{ linenoInc(); yytext=(char*)"\n"; yyleng=1; return(VP_WHITE); }
+<INITIAL><<EOF>>	{ yyterminate(); }  /* A "normal" EOF */
+<INITIAL>{symb} 	{ return (VP_SYMBOL); }
+<INITIAL>{symb}``	{ yyleng-=2; return (VP_SYMBOL_JOIN); }
+<INITIAL>{wsn}+		{ return (VP_WHITE); }
+<INITIAL>{drop}		{ }
+<INITIAL>[\r]		{ }
+<INITIAL>.		{ return (VP_TEXT); }
 %%
 
 void V3PreLex::pushStateDefArg(int level) {
diff --git a/src/V3PreProc.cpp b/src/V3PreProc.cpp
index e5b7b16..f83e1d4 100644
--- a/src/V3PreProc.cpp
+++ b/src/V3PreProc.cpp
@@ -282,10 +282,6 @@ V3PreProc* V3PreProc::createPreProc(FileLine* fl) {
     return preprocp;
 }
 
-bool V3PreProc::optPsl() {
-    return v3Global.opt.psl();
-}
-
 //*************************************************************************
 // Defines
 
@@ -483,7 +479,6 @@ const char* V3PreProcImp::tokenName(int tok) {
     case VP_IFNDEF	: return("IFNDEF");
     case VP_INCLUDE	: return("INCLUDE");
     case VP_LINE	: return("LINE");
-    case VP_PSL		: return("PSL");
     case VP_STRIFY	: return("STRIFY");
     case VP_STRING	: return("STRING");
     case VP_SYMBOL	: return("SYMBOL");
@@ -1103,7 +1098,7 @@ int V3PreProcImp::getStateToken() {
 		// Value of building argument is data before the lower defref
 		// we'll append it when we push the argument.
 		break;
-	    } else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE || VP_PSL) {
+	    } else if (tok==VP_SYMBOL || tok==VP_STRING || VP_TEXT || VP_WHITE) {
 		string rtn; rtn.assign(yyourtext(),yyourleng());
 		refp->nextarg(refp->nextarg()+rtn);
 		goto next_tok;
@@ -1340,7 +1335,6 @@ int V3PreProcImp::getStateToken() {
 	    goto next_tok;
 	case VP_SYMBOL:
 	case VP_STRING:
-	case VP_PSL:
 	case VP_TEXT: {
 	    m_defDepth = 0;
 	    if (!m_off) return tok;
@@ -1436,9 +1430,6 @@ string V3PreProcImp::getline() {
 	    }
 	    gotEof = true;
 	}
-	else if (tok==VP_PSL) {
-	    m_lineChars.append(" psl ");
-	}
 	else {
 	    m_lineChars.append(buf);
 	}
diff --git a/src/V3PreProc.h b/src/V3PreProc.h
index 9e47d3c..ff2feed 100644
--- a/src/V3PreProc.h
+++ b/src/V3PreProc.h
@@ -26,6 +26,7 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
+#include "V3FileLine.h"
 
 #include <string>
 #include <map>
@@ -75,7 +76,6 @@ public:
 	return !(v3Global.opt.preprocOnly() && v3Global.opt.preprocNoLine());
     }
     static bool pedantic() { return false; }		// Obey standard; Don't substitute `error
-    static bool optPsl();
 
     // CALLBACK METHODS
     // This probably will want to be overridden for given child users of this class.
diff --git a/src/V3PreShell.h b/src/V3PreShell.h
index 42cbfd9..b59e2a5 100644
--- a/src/V3PreShell.h
+++ b/src/V3PreShell.h
@@ -24,6 +24,7 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
+#include "V3FileLine.h"
 
 class V3ParseImp;
 class V3InFilter;
diff --git a/src/V3Premit.cpp b/src/V3Premit.cpp
index 1fe71fb..23e0c31 100644
--- a/src/V3Premit.cpp
+++ b/src/V3Premit.cpp
@@ -138,7 +138,7 @@ private:
 	//UINFO(9, "     Detail stmtp="<<(m_stmtp?"Y":"N")<<" U="<<(nodep->user1()?"Y":"N")<<" IW "<<(nodep->isWide()?"Y":"N")<<endl);
 	if (m_stmtp
 	    && !nodep->user1()) {	// Not already done
-	    if (nodep->isWide()) {		// Else might be cell interconnect or something
+	    if (nodep->isWide()) {
 		if (m_assignLhs) {
 		} else if (nodep->firstAbovep()
 			   && nodep->firstAbovep()->castNodeAssign()
@@ -148,7 +148,7 @@ private:
 			   && nodep->firstAbovep()->castArraySel()) {  // ArraySel's are pointer refs, ignore
 		} else {
 		    UINFO(4,"Cre Temp: "<<nodep<<endl);
-		    createDeepTemp(nodep);
+		    createDeepTemp(nodep, false);
 		}
 	    }
 	}
@@ -157,7 +157,7 @@ private:
     AstVar* getBlockTemp(AstNode* nodep) {
 	string newvarname = ((string)"__Vtemp"+cvtToStr(m_modp->varNumGetInc()));
 	AstVar* varp = new AstVar (nodep->fileline(), AstVarType::STMTTEMP, newvarname,
-				   VFlagLogicPacked(), nodep->widthMin());
+				   nodep->dtypep());
 	m_funcp->addInitsp(varp);
 	return varp;
     }
@@ -180,13 +180,14 @@ private:
 	}
     }
 
-    void createDeepTemp(AstNode* nodep) {
+    void createDeepTemp(AstNode* nodep, bool noSubst) {
 	if (debug()>8) nodep->dumpTree(cout,"deepin:");
 
 	AstNRelinker linker;
 	nodep->unlinkFrBack(&linker);
 
 	AstVar* varp = getBlockTemp(nodep);
+	if (noSubst) varp->noSubst(true); // Do not remove varrefs to this in V3Const
 	// Replace node tree with reference to var
 	AstVarRef* newp = new AstVarRef (nodep->fileline(), varp, false);
 	linker.relink(newp);
@@ -236,7 +237,7 @@ private:
 	    if (noopt && !nodep->user1()) {
 		// Need to do this even if not wide, as e.g. a select may be on a wide operator
 		UINFO(4,"Deep temp for LHS/RHS\n");
-		createDeepTemp(nodep->rhsp());
+		createDeepTemp(nodep->rhsp(), false);
 	    }
 	}
 	nodep->rhsp()->iterateAndNext(*this);
@@ -337,7 +338,7 @@ private:
 	    && !nodep->condp()->castVarRef()) {
 	    // We're going to need the expression several times in the expanded code,
 	    // so might as well make it a common expression
-	    createDeepTemp(nodep->condp());
+	    createDeepTemp(nodep->condp(), false);
 	}
 	checkNode(nodep);
     }
@@ -361,6 +362,17 @@ private:
 	    }
 	}
     }
+    virtual void visit(AstSFormatF* nodep, AstNUser*) {
+	nodep->iterateChildren(*this);
+	// Any strings sent to a display must be var of string data type,
+	// to avoid passing a pointer to a temporary.
+	for (AstNode* expp=nodep->exprsp(); expp; expp = expp->nextp()) {
+	    if (expp->dtypep()->basicp()->isString()
+		&& !expp->castVarRef()) {
+		createDeepTemp(expp, true);
+	    }
+	}
+    }
 
     //--------------------
     // Default: Just iterate
diff --git a/src/V3Stats.cpp b/src/V3Stats.cpp
index 5299bc0..ab36974 100644
--- a/src/V3Stats.cpp
+++ b/src/V3Stats.cpp
@@ -40,6 +40,9 @@
 class StatsVisitor : public AstNVisitor {
 private:
     // NODE STATE/TYPES
+
+    typedef map<string,int>	NameMap;	// Number of times a name appears
+
     // STATE
     string	m_stage;		// Name of the stage we are scanning
     bool	m_fast;			// Counting only fastpath
@@ -54,7 +57,8 @@ private:
     V3Double0		m_statPred[AstBranchPred::_ENUM_END];	// Nodes of given type
     V3Double0		m_statInstr;		// Instruction count
     V3Double0		m_statInstrFast;	// Instruction count
-    vector<V3Double0>	m_statVarWidths;	// Variables of given type
+    vector<V3Double0>	m_statVarWidths;	// Variables of given width
+    vector<NameMap>	m_statVarWidthNames;	// Var names of given width
     V3Double0		m_statVarArray;		// Statistic tracking
     V3Double0		m_statVarBytes;		// Statistic tracking
     V3Double0		m_statVarClock;		// Statistic tracking
@@ -100,8 +104,18 @@ private:
 	    else m_statVarBytes += nodep->dtypeSkipRefp()->widthTotalBytes();
 	    if (int(m_statVarWidths.size()) <= nodep->width()) {
 		m_statVarWidths.resize(nodep->width()+5);
+		if (v3Global.opt.statsVars()) m_statVarWidthNames.resize(nodep->width()+5);
 	    }
 	    ++ m_statVarWidths.at(nodep->width());
+	    string pn = nodep->prettyName();
+	    if (v3Global.opt.statsVars()) {
+		NameMap& nameMapr = m_statVarWidthNames.at(nodep->width());
+		if (nameMapr.find(pn) != nameMapr.end()) {
+		    nameMapr[pn]++;
+		} else {
+		    nameMapr[pn]=1;
+		}
+	    }
 	}
     }
     virtual void visit(AstVarScope* nodep, AstNUser*) {
@@ -208,8 +222,16 @@ public:
 	}
 	for (unsigned i=0; i<m_statVarWidths.size(); i++) {
 	    if (double count = double(m_statVarWidths.at(i))) {
-		ostringstream os; os<<"Vars, width "<<setw(4)<<dec<<i;
-		V3Stats::addStat(m_stage, os.str(), count);
+		if (v3Global.opt.statsVars()) {
+		    NameMap& nameMapr = m_statVarWidthNames.at(i);
+		    for (NameMap::iterator it=nameMapr.begin(); it!=nameMapr.end(); ++it) {
+			ostringstream os; os<<"Vars, width "<<setw(5)<<dec<<i<<" "<<it->first;
+			V3Stats::addStat(m_stage, os.str(), it->second);
+		    }
+		} else {
+		    ostringstream os; os<<"Vars, width "<<setw(5)<<dec<<i;
+		    V3Stats::addStat(m_stage, os.str(), count);
+		}
 	    }
 	}
 	// Node types
diff --git a/src/V3Stats.h b/src/V3Stats.h
index 59fe5a8..df49adf 100644
--- a/src/V3Stats.h
+++ b/src/V3Stats.h
@@ -23,7 +23,8 @@
 #include "config_build.h"
 #include "verilatedos.h"
 #include "V3Error.h"
-#include "V3Ast.h"
+
+class AstNetlist;
 
 //============================================================================
 
diff --git a/src/V3Subst.cpp b/src/V3Subst.cpp
index 150e6f4..e44e2d6 100644
--- a/src/V3Subst.cpp
+++ b/src/V3Subst.cpp
@@ -258,6 +258,9 @@ private:
 	    return entryp;
 	}
     }
+    inline bool isSubstVar(AstVar* nodep) {
+	return nodep->isStatementTemp() && !nodep->noSubst();
+    }
 
     // VISITORS
     virtual void visit(AstNodeAssign* nodep, AstNUser*) {
@@ -266,7 +269,7 @@ private:
 	nodep->rhsp()->iterateAndNext(*this);
 	bool hit=false;
 	if (AstVarRef* varrefp = nodep->lhsp()->castVarRef()) {
-	    if (varrefp->varp()->isStatementTemp()) {
+	    if (isSubstVar(varrefp->varp())) {
 		SubstVarEntry* entryp = getEntryp(varrefp);
 		hit = true;
 		if (m_ops > SUBST_MAX_OPS_SUBST) {
@@ -281,7 +284,7 @@ private:
 	else if (AstWordSel* wordp = nodep->lhsp()->castWordSel()) {
 	    if (AstVarRef* varrefp = wordp->lhsp()->castVarRef()) {
 		if (wordp->rhsp()->castConst()
-		    && varrefp->varp()->isStatementTemp()) {
+		    && isSubstVar(varrefp->varp())) {
 		    int word = wordp->rhsp()->castConst()->toUInt();
 		    SubstVarEntry* entryp = getEntryp(varrefp);
 		    hit = true;
@@ -314,7 +317,7 @@ private:
 	nodep->rhsp()->accept(*this);
 	AstVarRef* varrefp = nodep->lhsp()->castVarRef();
 	AstConst* constp = nodep->rhsp()->castConst();
-	if (varrefp && varrefp->varp()->isStatementTemp()
+	if (varrefp && isSubstVar(varrefp->varp())
 	    && !varrefp->lvalue()
 	    && constp) {
 	    // Nicely formed lvalues handled in NodeAssign
@@ -344,7 +347,7 @@ private:
 	    nodep->varp()->user2(m_assignStep);
 	    UINFO(9, " ASSIGNstep u2="<<nodep->varp()->user2()<<" "<<nodep<<endl);
 	}
-	if (nodep->varp()->isStatementTemp()) {
+	if (isSubstVar(nodep->varp())) {
 	    SubstVarEntry* entryp = getEntryp (nodep);
 	    if (nodep->lvalue()) {
 		UINFO(8," ASSIGNcpx "<<nodep<<endl);
diff --git a/src/V3Unknown.cpp b/src/V3Unknown.cpp
index d1d9f70..79e39e7 100644
--- a/src/V3Unknown.cpp
+++ b/src/V3Unknown.cpp
@@ -410,12 +410,16 @@ private:
 		condp->deleteTree();
 	    }
 	    else if (!lvalue
-		&& !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
+		     && !nodep->backp()->castArraySel()) {	// Too complicated and slow if mid-multidimension
 		// ARRAYSEL(...) -> COND(LT(bit<maxbit), ARRAYSEL(...), {width{1'bx}})
 		AstNRelinker replaceHandle;
 		nodep->unlinkFrBack(&replaceHandle);
 		V3Number xnum (nodep->fileline(), nodep->width());
-		xnum.setAllBitsX();
+		if (nodep->isString()) {
+		    xnum = V3Number(V3Number::String(), nodep->fileline(), "");
+		} else {
+		    xnum.setAllBitsX();
+		}
 		AstNode* newp = new AstCondBound (nodep->fileline(),
 						  condp,
 						  nodep,
diff --git a/src/V3Width.cpp b/src/V3Width.cpp
index 2a8fd9d..bb77134 100644
--- a/src/V3Width.cpp
+++ b/src/V3Width.cpp
@@ -77,6 +77,7 @@
 #include "V3Width.h"
 #include "V3Number.h"
 #include "V3Const.h"
+#include "V3String.h"
 #include "V3Task.h"
 
 // More code; this file was getting too large; see actions there
@@ -154,6 +155,10 @@ ostream& operator<<(ostream& str, const WidthVP* vup) {
 
 class WidthVisitor : public AstNVisitor {
 private:
+    // TYPES
+    typedef map<pair<AstNodeDType*,AstAttrType>, AstVar*> TableMap;
+    typedef map<int,AstPatMember*> PatVecMap;
+
     // STATE
     bool	m_paramsOnly;	// Computing parameter value; limit operation
     AstRange*	m_cellRangep;	// Range for arrayed instantiations, NULL for normal instantiations
@@ -162,9 +167,7 @@ private:
     AstAttrOf*	m_attrp;	// Current attribute
     bool	m_doGenerate;	// Do errors later inside generate statement
     int		m_dtTables;	// Number of created data type tables
-
-    // TYPES
-    typedef map<int,AstPatMember*> PatVecMap;
+    TableMap	m_tableMap;	// Created tables so can remove duplicates
 
     // ENUMS
     enum ExtendRule {
@@ -189,7 +192,6 @@ private:
 
     // Widths: 1 bit out, lhs 1 bit; Real: converts via compare with 0
     virtual void visit(AstLogNot* nodep, AstNUser* vup) {	visit_log_not(nodep,vup); }
-    virtual void visit(AstPslBool* nodep, AstNUser* vup) {	visit_log_not(nodep,vup); }
     // Widths: 1 bit out, lhs 1 bit, rhs 1 bit; Real: converts via compare with 0
     virtual void visit(AstLogAnd* nodep, AstNUser* vup) {	visit_log_and_or(nodep,vup); }
     virtual void visit(AstLogOr* nodep, AstNUser* vup) {	visit_log_and_or(nodep,vup); }
@@ -230,6 +232,13 @@ private:
     virtual void visit(AstLteD* nodep, AstNUser* vup) {		visit_cmp_real(nodep,vup); }
     virtual void visit(AstGtD* nodep, AstNUser* vup) {		visit_cmp_real(nodep,vup); }
     virtual void visit(AstGteD* nodep, AstNUser* vup) {		visit_cmp_real(nodep,vup); }
+    // ...    String compares
+    virtual void visit(AstEqN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
+    virtual void visit(AstNeqN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
+    virtual void visit(AstLtN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
+    virtual void visit(AstLteN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
+    virtual void visit(AstGtN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
+    virtual void visit(AstGteN* nodep, AstNUser* vup) {		visit_cmp_string(nodep,vup); }
 
     // Widths: out width = lhs width = rhs width
     // Signed: Output signed iff LHS & RHS signed.
@@ -369,6 +378,29 @@ private:
 		    return;
 		}
 	    }
+	    if (nodep->lhsp()->isString()
+		|| nodep->rhsp()->isString()) {
+		AstNode* newp = new AstConcatN (nodep->fileline(),nodep->lhsp()->unlinkFrBack(),
+						nodep->rhsp()->unlinkFrBack());
+		nodep->replaceWith(newp);
+		pushDeletep(nodep); nodep=NULL;
+		return;
+	    }
+	}
+	if (vup->c()->final()) {
+	    if (!nodep->dtypep()->widthSized()) {
+		// See also error in V3Number
+		nodep->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in concatenations.");
+	    }
+	}
+    }
+    virtual void visit(AstConcatN* nodep, AstNUser* vup) {
+	// String concatenate.
+	// Already did AstConcat simplifications
+	if (vup->c()->prelim()) {
+	    iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
+	    iterateCheckString(nodep,"RHS",nodep->rhsp(),BOTH);
+	    nodep->dtypeSetString();
 	}
 	if (vup->c()->final()) {
 	    if (!nodep->dtypep()->widthSized()) {
@@ -391,9 +423,38 @@ private:
 	    if (times==0 && !nodep->backp()->castConcat()) {  // Concat Visitor will clean it up.
 		nodep->v3error("Replication value of 0 is only legal under a concatenation."); times=1;
 	    }
-	    nodep->dtypeSetLogicSized((nodep->lhsp()->width() * times),
-				      (nodep->lhsp()->widthMin() * times),
-				      AstNumeric::UNSIGNED);
+	    if (nodep->lhsp()->isString()) {
+		AstNode* newp = new AstReplicateN(nodep->fileline(),nodep->lhsp()->unlinkFrBack(),
+						  nodep->rhsp()->unlinkFrBack());
+		nodep->replaceWith(newp);
+		pushDeletep(nodep); nodep=NULL;
+		return;
+	    } else {
+		nodep->dtypeSetLogicSized((nodep->lhsp()->width() * times),
+					  (nodep->lhsp()->widthMin() * times),
+					  AstNumeric::UNSIGNED);
+	    }
+	}
+	if (vup->c()->final()) {
+	    if (!nodep->dtypep()->widthSized()) {
+		// See also error in V3Number
+		nodep->v3warn(WIDTHCONCAT,"Unsized numbers/parameters not allowed in replications.");
+	    }
+	}
+    }
+    virtual void visit(AstReplicateN* nodep, AstNUser* vup) {
+	// Replicate with string
+	if (vup->c()->prelim()) {
+	    iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
+	    iterateCheckSizedSelf(nodep,"RHS",nodep->rhsp(),SELF,BOTH);
+	    V3Const::constifyParamsEdit(nodep->rhsp()); // rhsp may change
+	    AstConst* constp = nodep->rhsp()->castConst();
+	    if (!constp) { nodep->v3error("Replication value isn't a constant."); return; }
+	    uint32_t times = constp->toUInt();
+	    if (times==0 && !nodep->backp()->castConcat()) {  // Concat Visitor will clean it up.
+		nodep->v3error("Replication value of 0 is only legal under a concatenation."); times=1;
+	    }
+	    nodep->dtypeSetString();
 	}
 	if (vup->c()->final()) {
 	    if (!nodep->dtypep()->widthSized()) {
@@ -650,7 +711,9 @@ private:
 	// However a later operation may have changed the node->signed w/o changing
 	// the number's sign.  So we don't: nodep->dtypeChgSigned(nodep->num().isSigned());
 	if (vup && vup->c()->prelim()) {
-	    if (nodep->num().sized()) {
+	    if (nodep->num().isString()) {
+		nodep->dtypeSetString();
+	    } else if (nodep->num().sized()) {
 		nodep->dtypeChgWidth(nodep->num().width(), nodep->num().width());
 	    } else {
 		nodep->dtypeChgWidth(nodep->num().width(), nodep->num().widthMin());
@@ -659,9 +722,6 @@ private:
 	// We don't size the constant until we commit the widths, as need parameters
 	// to remain unsized, and numbers to remain unsized to avoid backp() warnings
     }
-    virtual void visit(AstConstString* nodep, AstNUser* vup) {
-	nodep->rewidth();
-    }
     virtual void visit(AstRand* nodep, AstNUser* vup) {
 	if (vup->c()->prelim()) {
 	    nodep->dtypeSetSigned32();  // Says the spec
@@ -763,45 +823,55 @@ private:
 	m_attrp = nodep;
 	nodep->fromp()->iterateAndNext(*this,WidthVP(SELF,BOTH).p());
 	// Don't iterate children, don't want to lose VarRef.
-	if (nodep->attrType()==AstAttrType::VAR_BASE) {
+	switch (nodep->attrType()) {
+	case AstAttrType::VAR_BASE:
 	    // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
-	} else if (nodep->attrType()==AstAttrType::MEMBER_BASE) {
+	    break;
+	case AstAttrType::MEMBER_BASE:
 	    // Soon to be handled in V3LinkWidth SEL generation, under attrp() and newSubLsbOf
-	} else if (nodep->attrType()==AstAttrType::DIM_DIMENSIONS
-		   || nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS) {
+	    break;
+	case AstAttrType::DIM_DIMENSIONS:
+	case AstAttrType::DIM_UNPK_DIMENSIONS: {
 	    if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
 	    pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->dimensions(true);
 	    int val = (nodep->attrType()==AstAttrType::DIM_UNPK_DIMENSIONS
 		       ? dim.second : (dim.first+dim.second));
 	    nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
-	} else if (nodep->attrType()==AstAttrType::DIM_BITS
-		   || nodep->attrType()==AstAttrType::DIM_HIGH
-		   || nodep->attrType()==AstAttrType::DIM_INCREMENT
-		   || nodep->attrType()==AstAttrType::DIM_LEFT
-		   || nodep->attrType()==AstAttrType::DIM_LOW
-		   || nodep->attrType()==AstAttrType::DIM_RIGHT
-		   || nodep->attrType()==AstAttrType::DIM_SIZE) {
+	    break;
+	}
+	case AstAttrType::DIM_BITS:
+	case AstAttrType::DIM_HIGH:
+	case AstAttrType::DIM_INCREMENT:
+	case AstAttrType::DIM_LEFT:
+	case AstAttrType::DIM_LOW:
+	case AstAttrType::DIM_RIGHT:
+	case AstAttrType::DIM_SIZE: {
 	    if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
 	    pair<uint32_t,uint32_t> dim = nodep->fromp()->dtypep()->skipRefp()->dimensions(true);
-	    uint32_t maxdim = dim.first+dim.second;
-	    if (!nodep->dimp() || nodep->dimp()->castConst() || maxdim<1) {
+	    uint32_t msbdim = dim.first+dim.second;
+	    if (!nodep->dimp() || nodep->dimp()->castConst() || msbdim<1) {
 		int dim = !nodep->dimp() ? 1 : nodep->dimp()->castConst()->toSInt();
-		int val = dimensionValue(nodep->fromp()->dtypep(), nodep->attrType(), dim);
-		nodep->replaceWith(new AstConst(nodep->fileline(), AstConst::Signed32(), val)); nodep->deleteTree(); nodep=NULL;
+		AstConst* newp = dimensionValue(nodep->fromp()->dtypep(), nodep->attrType(), dim);
+		nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
 	    }
 	    else {  // Need a runtime lookup table.  Yuk.
 		if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
-		AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType());
+		AstVar* varp = dimensionVarp(nodep->fromp()->dtypep(), nodep->attrType(), msbdim);
 		AstNode* dimp = nodep->dimp()->unlinkFrBack();
 		AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
 		varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
 		AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, dimp);
 		nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
 	    }
-	} else {  // Everything else resolved earlier
+	    break;
+	}
+	default: {
+	    // Everything else resolved earlier
 	    nodep->dtypeSetLogicSized(32,1,AstNumeric::UNSIGNED);	// Approximation, unsized 32
 	    UINFO(1,"Missing ATTR type case node: "<<nodep<<endl);
 	    nodep->v3fatalSrc("Missing ATTR type case");
+	    break;
+	}
 	}
 	m_attrp = oldAttr;
     }
@@ -1244,21 +1314,29 @@ private:
 	if (debug()>=9) nodep->dumpTree("-ms-in-");
 	nodep->iterateChildren(*this,WidthVP(SELF,BOTH).p());
 	// Find the fromp dtype - should be a class
-	AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefp();
+	AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
 	UINFO(9,"     from dt "<<fromDtp<<endl);
-	AstNodeClassDType* fromClassp = fromDtp->castNodeClassDType();
 	AstMemberDType* memberp = NULL;  // NULL=error below
-	if (!fromClassp) {
-	    nodep->v3error("Member selection of non-struct/union object '"
-			   <<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
-	}
-	else {
-	    // No need to width-resolve the fromClassp, as it was done when we did the child
-	    memberp = fromClassp->findMember(nodep->name());
+	if (AstNodeClassDType* adtypep = fromDtp->castNodeClassDType()) {
+	    // No need to width-resolve the class, as it was done when we did the child
+	    memberp = adtypep->findMember(nodep->name());
 	    if (!memberp) {
 		nodep->v3error("Member '"<<nodep->prettyName()<<"' not found in structure");
 	    }
 	}
+	else if (fromDtp->castEnumDType()) {
+	    // Method call on enum without following parenthesis, e.g. "ENUM.next"
+	    // Convert this into a method call, and let that visitor figure out what to do next
+	    AstNode* newp = new AstMethodSel(nodep->fileline(), nodep->fromp()->unlinkFrBack(), nodep->name(), NULL);
+	    nodep->replaceWith(newp);
+	    pushDeletep(nodep); nodep=NULL;
+	    newp->accept(*this,vup);
+	    return;
+	}
+	else {
+	    nodep->v3error("Member selection of non-struct/union object '"
+			   <<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
+	}
 	if (memberp) {
 	    if (m_attrp) {  // Looking for the base of the attribute
 		nodep->dtypep(memberp);
@@ -1280,6 +1358,94 @@ private:
 	}
     }
 
+    virtual void visit(AstMethodSel* nodep, AstNUser* vup) {
+	UINFO(5,"   METHODSEL "<<nodep<<endl);
+	if (debug()>=9) nodep->dumpTree("-ms-in-");
+	// Should check types the method requires, but at present we don't do much
+	nodep->fromp()->accept(*this,WidthVP(SELF,BOTH).p());
+	for (AstArg* argp = nodep->pinsp()->castArg(); argp; argp = argp->nextp()->castArg()) {
+	    if (argp->exprp()) argp->exprp()->accept(*this,WidthVP(SELF,BOTH).p());
+	}
+	// Find the fromp dtype - should be a class
+	if (!nodep->fromp() || !nodep->fromp()->dtypep()) nodep->v3fatalSrc("Unsized expression");
+	AstNodeDType* fromDtp = nodep->fromp()->dtypep()->skipRefToEnump();
+	UINFO(9,"     from dt "<<fromDtp<<endl);
+	if (AstEnumDType* adtypep = fromDtp->castEnumDType()) {
+	    // Method call on enum without following parenthesis, e.g. "ENUM.next"
+	    // Convert this into a method call, and let that visitor figure out what to do next
+	    if (adtypep) {}
+	    if (nodep->name() == "num"
+		|| nodep->name() == "first"
+		|| nodep->name() == "last") {
+		// Constant value
+		AstConst* newp = NULL;
+		if (nodep->pinsp()) nodep->v3error("Arguments passed to enum.num method, but it does not take arguments");
+		if (nodep->name() == "num") {
+		    int items = 0;
+		    for (AstNode* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()) ++items;
+		    newp = new AstConst(nodep->fileline(), AstConst::Signed32(), items);
+		} else if (nodep->name() == "first") {
+		    AstEnumItem* itemp = adtypep->itemsp();
+		    if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);  // Spec doesn't say what to do
+		    else newp = itemp->valuep()->cloneTree(false)->castConst();  // A const
+		} else if (nodep->name() == "last") {
+		    AstEnumItem* itemp = adtypep->itemsp();
+		    while (itemp && itemp->nextp()) itemp = itemp->nextp()->castEnumItem();
+		    if (!itemp) newp = new AstConst(nodep->fileline(), AstConst::Signed32(), 0);  // Spec doesn't say what to do
+		    else newp = itemp->valuep()->cloneTree(false)->castConst();  // A const
+		}
+		if (!newp) nodep->v3fatalSrc("Enum method (perhaps enum item) not const");
+		newp->fileline(nodep->fileline());  // Use method's filename/line number to be clearer; may have warning disables
+		nodep->replaceWith(newp);
+		pushDeletep(nodep); nodep=NULL;
+	    }
+	    else if (nodep->name() == "name"
+		     || nodep->name() == "next"
+		     || nodep->name() == "prev") {
+		AstAttrType attrType;
+		if (nodep->name() == "name") attrType = AstAttrType::ENUM_NAME;
+		else if (nodep->name() == "next") attrType = AstAttrType::ENUM_NEXT;
+		else if (nodep->name() == "prev") attrType = AstAttrType::ENUM_PREV;
+		else nodep->v3fatalSrc("Bad case");
+
+		if (nodep->pinsp() && nodep->name() == "name") {
+		    nodep->v3error("Arguments passed to enum.name method, but it does not take arguments");
+		} else if (nodep->pinsp() && !(nodep->pinsp()->castArg()->exprp()->castConst()
+					       && nodep->pinsp()->castArg()->exprp()->castConst()->toUInt()==1
+					       && !nodep->pinsp()->nextp())) {
+		    nodep->v3error("Unsupported: Arguments passed to enum.next method");
+		}
+		// Need a runtime lookup table.  Yuk.
+		// Ideally we would have a fast algorithm when a number is
+		// of small width and complete and so can use an array, and
+		// a map for when the value is many bits and sparse.
+		uint64_t msbdim = 0;
+		{
+		    for (AstEnumItem* itemp = adtypep->itemsp(); itemp; itemp = itemp->nextp()->castEnumItem()) {
+			AstConst* vconstp = itemp->valuep()->castConst();
+			if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
+			if (vconstp->toUQuad() >= msbdim) msbdim = vconstp->toUQuad();
+		    }
+		    if (adtypep->itemsp()->width() > 64 || msbdim >= 1024) {
+			nodep->v3error("Unsupported; enum next/prev method on enum with > 10 bits");
+			return;
+		    }
+		}
+		AstVar* varp = enumVarp(adtypep, attrType, msbdim);
+		AstVarRef* varrefp = new AstVarRef(nodep->fileline(), varp, false);
+		varrefp->packagep(v3Global.rootp()->dollarUnitPkgAddp());
+		AstNode* newp = new AstArraySel(nodep->fileline(), varrefp, nodep->fromp()->unlinkFrBack());
+		nodep->replaceWith(newp); nodep->deleteTree(); nodep=NULL;
+	    } else {
+		nodep->v3error("Unknown built-in enum method '"<<nodep->fromp()->prettyTypeName()<<"'");
+	    }
+	}
+	else {
+	    nodep->v3error("Unsupported: Member call on non-enum object '"
+			   <<nodep->fromp()->prettyTypeName()<<"' which is a '"<<nodep->fromp()->dtypep()->prettyTypeName()<<"'");
+	}
+    }
+
     virtual void visit(AstPattern* nodep, AstNUser* vup) {
 	if (nodep->didWidthAndSet()) return;
 	UINFO(9,"PATTERN "<<nodep<<endl);
@@ -1702,6 +1868,13 @@ private:
 		    if (argp) argp=argp->nextp();
 		    break;
 		}
+		case 's': {  // Convert string to pack string
+		    if (argp && argp->dtypep()->basicp()->isString()) { // Convert it
+			ch = '@';
+		    }
+		    if (argp) argp=argp->nextp();
+		    break;
+		}
 		default: {  // Most operators, just move to next argument
 		    if (argp) argp=argp->nextp();
 		    break;
@@ -1810,10 +1983,6 @@ private:
 	iterateCheckBool(nodep,"Property",nodep->propp(),BOTH);	// it's like an if() condition.
 	nodep->stmtsp()->iterateAndNext(*this);
     }
-    virtual void visit(AstPslAssert* nodep, AstNUser* vup) {
-	assertAtStatement(nodep,vup);
-	iterateCheckBool(nodep,"Property",nodep->propp(),BOTH);	// it's like an if() condition.
-    }
     virtual void visit(AstVAssert* nodep, AstNUser* vup) {
 	assertAtStatement(nodep,vup);
 	iterateCheckBool(nodep,"Property",nodep->propp(),BOTH);	// it's like an if() condition.
@@ -2131,8 +2300,7 @@ private:
     }
 
     void visit_log_not(AstNode* nodep, AstNUser* vup) {
-	// CALLER: LogNot, PslBool
-	// Note AstPslBool isn't a AstNodeUniop, or we'd only allow that here
+	// CALLER: LogNot
 	// Width-check: lhs 1 bit
 	// Real: Allowed; implicitly compares with zero
 	// We calculate the width of the UNDER expression.
@@ -2207,6 +2375,12 @@ private:
 		    iterateCheckReal(nodep,"LHS",nodep->lhsp(),FINAL);
 		    iterateCheckReal(nodep,"RHS",nodep->rhsp(),FINAL);
 		}
+	    } else if (nodep->lhsp()->isString() || nodep->rhsp()->isString()) {
+		if (AstNodeBiop* newp=replaceWithNVersion(nodep)) { nodep=NULL;
+		    nodep = newp;  // Process new node instead
+		    iterateCheckString(nodep,"LHS",nodep->lhsp(),FINAL);
+		    iterateCheckString(nodep,"RHS",nodep->rhsp(),FINAL);
+		}
 	    } else {
 		bool signedFl = nodep->lhsp()->isSigned() && nodep->rhsp()->isSigned();
 		if (AstNodeBiop* newp=replaceWithUOrSVersion(nodep, signedFl)) { nodep=NULL;
@@ -2236,6 +2410,19 @@ private:
 	    nodep->dtypeSetLogicBool();
 	}
     }
+    void visit_cmp_string(AstNodeBiop* nodep, AstNUser* vup) {
+	// CALLER: EqN, LtN
+	// Widths: 1 bit out, lhs width == rhs width
+	// String compare (not output)
+	// Real if and only if real_allow set
+	if (!nodep->rhsp()) nodep->v3fatalSrc("For binary ops only!");
+	if (vup->c()->prelim()) {
+	    // See similar handling in visit_cmp_eq_gt where created
+	    iterateCheckString(nodep,"LHS",nodep->lhsp(),BOTH);
+	    iterateCheckString(nodep,"RHS",nodep->rhsp(),BOTH);
+	    nodep->dtypeSetLogicBool();
+	}
+    }
 
     void visit_negate_not(AstNodeUniop* nodep, AstNUser* vup, bool real_ok) {
 	// CALLER: (real_ok=false) Not
@@ -2602,6 +2789,15 @@ private:
 	    underp = iterateCheck(nodep,side,underp,SELF,FINAL,expDTypep,EXTEND_EXP);
 	}
     }
+    void iterateCheckString (AstNode* nodep, const char* side, AstNode* underp, Stage stage) {
+	if (stage & PRELIM) {
+	    underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,PRELIM).p());
+	}
+	if (stage & FINAL) {
+	    AstNodeDType* expDTypep = nodep->findStringDType();
+	    underp = iterateCheck(nodep,side,underp,SELF,FINAL,expDTypep,EXTEND_EXP);
+	}
+    }
     void iterateCheckSizedSelf (AstNode* nodep, const char* side, AstNode* underp,
 				Determ determ, Stage stage) {
 	// Coerce child to any sized-number data type; child is self-determined i.e. isolated from expected type.
@@ -2685,6 +2881,9 @@ private:
 	} else if (!expDTypep->isDouble() && underp->isDouble()) {
 	    underp = spliceCvtS(underp, true);  // Round RHS
 	    underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,FINAL).p());
+	} else if (expDTypep->isString() && !underp->dtypep()->isString()) {
+	    underp = spliceCvtString(underp);
+	    underp = underp->acceptSubtreeReturnEdits(*this,WidthVP(SELF,FINAL).p());
 	} else {
 	    AstBasicDType* expBasicp = expDTypep->basicp();
 	    AstBasicDType* underBasicp = underp->dtypep()->basicp();
@@ -2828,6 +3027,20 @@ private:
 	    return nodep;
 	}
     }
+    AstNode* spliceCvtString(AstNode* nodep) {
+	// IEEE-2012 11.8.1: Signed: Type coercion creates signed
+	// 11.8.2: Argument to convert is self-determined
+	if (nodep && !nodep->dtypep()->basicp()->isString()) {
+	    UINFO(6,"   spliceCvtString: "<<nodep<<endl);
+	    AstNRelinker linker;
+	    nodep->unlinkFrBack(&linker);
+	    AstNode* newp = new AstCvtPackString(nodep->fileline(), nodep);
+	    linker.relink(newp);
+	    return newp;
+	} else {
+	    return nodep;
+	}
+    }
     AstNodeBiop* replaceWithUOrSVersion(AstNodeBiop* nodep, bool signedFlavorNeeded) {
 	// Given a signed/unsigned node type, create the opposite type
 	// Return new node or NULL if nothing
@@ -2910,6 +3123,34 @@ private:
 	pushDeletep(nodep); nodep=NULL;
 	return newp;
     }
+    AstNodeBiop* replaceWithNVersion(AstNodeBiop* nodep) {
+	// Given a signed/unsigned node type, replace with string version
+	// Return new node or NULL if nothing
+	if (nodep->stringFlavor()) {
+	    return NULL;
+	}
+	FileLine* fl = nodep->fileline();
+	AstNode* lhsp = nodep->lhsp()->unlinkFrBack();
+	AstNode* rhsp = nodep->rhsp()->unlinkFrBack();
+	AstNodeBiop* newp = NULL;
+	// No width change on output;...		// All below have bool or double outputs
+	switch (nodep->type()) {
+	case AstType::atEQ:	case AstType::atEQCASE:	newp = new AstEqN	(fl,lhsp,rhsp); break;
+	case AstType::atNEQ:	case AstType::atNEQCASE: newp = new AstNeqN	(fl,lhsp,rhsp); break;
+	case AstType::atGT:	case AstType::atGTS:	newp = new AstGtN	(fl,lhsp,rhsp); break;
+	case AstType::atGTE:	case AstType::atGTES:	newp = new AstGteN	(fl,lhsp,rhsp); break;
+	case AstType::atLT:	case AstType::atLTS:	newp = new AstLtN	(fl,lhsp,rhsp); break;
+	case AstType::atLTE:	case AstType::atLTES:	newp = new AstLteN	(fl,lhsp,rhsp); break;
+	default:
+	    nodep->v3fatalSrc("Node needs conversion to string, but bad case: "<<nodep<<endl);
+	    break;
+	}
+	UINFO(6,"   ReplaceWithNVersion: "<<nodep<<" w/ "<<newp<<endl);
+	nodep->replaceWith(newp);
+	// No width change; the default created type (bool or string) is correct
+	pushDeletep(nodep); nodep=NULL;
+	return newp;
+    }
     AstNodeUniop* replaceWithDVersion(AstNodeUniop* nodep) {
 	// Given a signed/unsigned node type, create the opposite type
 	// Return new node or NULL if nothing
@@ -2960,7 +3201,7 @@ private:
 	return nodep;
     }
 
-    int dimensionValue(AstNodeDType* nodep, AstAttrType attrType, int dim) {
+    AstConst* dimensionValue(AstNodeDType* nodep, AstAttrType attrType, int dim) {
 	// Return the dimension value for the specified attribute and constant dimension
 	AstNodeDType* dtypep = nodep->skipRefp();
 	VNumRange declRange;  // ranged() set false
@@ -2981,8 +3222,10 @@ private:
 	    }
 	    break;
 	}
+	AstConst* valp = NULL;  // If NULL, construct from val
 	int val = 0;
-	if (attrType==AstAttrType::DIM_BITS) {
+	switch (attrType) {
+	case AstAttrType::DIM_BITS: {
 	    int bits = 1;
 	    while (dtypep) {
 		//UINFO(9, "   bits at "<<bits<<"  "<<dtypep<<endl);
@@ -3006,36 +3249,46 @@ private:
 	    } else {
 		val = bits;
 	    }
-	} else if (attrType==AstAttrType::DIM_HIGH) {
+	    break; }
+	case AstAttrType::DIM_HIGH:
 	    val = !declRange.ranged() ? 0 : declRange.hi();
-	} else if (attrType==AstAttrType::DIM_LEFT) {
+	    break;
+	case AstAttrType::DIM_LEFT:
 	    val = !declRange.ranged() ? 0 : declRange.left();
-	} else if (attrType==AstAttrType::DIM_LOW) {
+	    break;
+	case AstAttrType::DIM_LOW:
 	    val = !declRange.ranged() ? 0 : declRange.lo();
-	} else if (attrType==AstAttrType::DIM_RIGHT) {
+	    break;
+	case AstAttrType::DIM_RIGHT:
 	    val = !declRange.ranged() ? 0 : declRange.right();
-	} else if (attrType==AstAttrType::DIM_INCREMENT) {
+	    break;
+	case AstAttrType::DIM_INCREMENT:
 	    val = (declRange.ranged() && declRange.littleEndian()) ? -1 : 1;
-	} else if (attrType==AstAttrType::DIM_SIZE) {
+	    break;
+	case AstAttrType::DIM_SIZE:
 	    val = !declRange.ranged() ? 0 : declRange.elements();
-	} else {
+	    break;
+	default:
 	    nodep->v3fatalSrc("Missing DIM ATTR type case");
+	    break;
 	}
-	UINFO(9," $dimension "<<attrType.ascii()<<"("<<((void*)dtypep)<<","<<dim<<")="<<val<<endl);
-	return val;
+	if (!valp) valp = new AstConst(nodep->fileline(), AstConst::Signed32(), val);
+	UINFO(9," $dimension "<<attrType.ascii()<<"("<<((void*)dtypep)<<","<<dim<<")="<<valp<<endl);
+	return valp;
     }
-    AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType) {
+    AstVar* dimensionVarp(AstNodeDType* nodep, AstAttrType attrType, uint32_t msbdim) {
 	// Return a variable table which has specified dimension properties for this variable
-	pair<uint32_t,uint32_t> dim = nodep->skipRefp()->dimensions(true);
-	uint32_t maxdim = dim.first+dim.second;
-	//
+	TableMap::iterator pos = m_tableMap.find(make_pair(nodep,attrType));
+	if (pos != m_tableMap.end()) {
+	    return pos->second;
+	}
 	AstNodeArrayDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
 							       nodep->findSigned32DType(),
-							       new AstRange(nodep->fileline(), maxdim, 0));
+							       new AstRange(nodep->fileline(), msbdim, 0));
 	AstInitArray* initp = new AstInitArray (nodep->fileline(), vardtypep, NULL);
 	v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
 	AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
-				   "__Vdimtable" + cvtToStr(m_dtTables++),
+				   "__Vdimtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++),
 				   vardtypep);
 	varp->isConst(true);
 	varp->isStatic(true);
@@ -3043,13 +3296,87 @@ private:
 	// Add to root, as don't know module we are in, and aids later structure sharing
 	v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
 	// Element 0 is a non-index and has speced values
-	initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
-				      dimensionValue(nodep, attrType, 0)));
-	for (unsigned i=1; i<maxdim+1; ++i) {
-	    initp->addInitsp(new AstConst(nodep->fileline(), AstConst::Signed32(),
-					  dimensionValue(nodep, attrType, i)));
+	initp->addInitsp(dimensionValue(nodep, attrType, 0));
+	for (unsigned i=1; i<msbdim+1; ++i) {
+	    initp->addInitsp(dimensionValue(nodep, attrType, i));
+	}
+	varp->iterate(*this);  // May have already done $unit so must do this var
+	m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
+	return varp;
+    }
+    AstVar* enumVarp(AstEnumDType* nodep, AstAttrType attrType, uint32_t msbdim) {
+	// Return a variable table which has specified dimension properties for this variable
+	TableMap::iterator pos = m_tableMap.find(make_pair(nodep,attrType));
+	if (pos != m_tableMap.end()) {
+	    return pos->second;
+	}
+	UINFO(9, "Construct Venumtab attr="<<attrType.ascii()<<" max="<<msbdim<<" for "<<nodep<<endl);
+	AstNodeDType* basep;
+	if (attrType == AstAttrType::ENUM_NAME) {
+	    basep = nodep->findStringDType();
+	} else {
+	    basep = nodep->findSigned32DType();
+	}
+	AstNodeArrayDType* vardtypep = new AstUnpackArrayDType(nodep->fileline(),
+							       basep,
+							       new AstRange(nodep->fileline(), msbdim, 0));
+	AstInitArray* initp = new AstInitArray (nodep->fileline(), vardtypep, NULL);
+	v3Global.rootp()->typeTablep()->addTypesp(vardtypep);
+	AstVar* varp = new AstVar (nodep->fileline(), AstVarType::MODULETEMP,
+				   "__Venumtab_" + VString::downcase(attrType.ascii()) + cvtToStr(m_dtTables++),
+				   vardtypep);
+	varp->isConst(true);
+	varp->isStatic(true);
+	varp->valuep(initp);
+	// Add to root, as don't know module we are in, and aids later structure sharing
+	v3Global.rootp()->dollarUnitPkgAddp()->addStmtp(varp);
+
+	// Find valid values and populate
+	if (!nodep->itemsp()) nodep->v3fatalSrc("enum without items");
+	vector<AstNode*> values;
+	values.reserve(msbdim+1);
+	for (unsigned i=0; i<(msbdim+1); ++i) {
+	    values[i] = NULL;
+	}
+	{
+	    AstEnumItem* firstp = nodep->itemsp();
+	    AstEnumItem* prevp = firstp; // Prev must start with last item
+	    while (prevp->nextp()) prevp = prevp->nextp()->castEnumItem();
+	    for (AstEnumItem* itemp = firstp; itemp;) {
+		AstEnumItem* nextp = itemp->nextp()->castEnumItem();
+		AstConst* vconstp = itemp->valuep()->castConst();
+		if (!vconstp) nodep->v3fatalSrc("Enum item without constified value");
+		uint32_t i = vconstp->toUInt();
+		if (attrType == AstAttrType::ENUM_NAME) {
+		    values[i] = new AstConst(nodep->fileline(), AstConst::String(), itemp->name());
+		} else if (attrType == AstAttrType::ENUM_NEXT) {
+		    values[i] = (nextp ? nextp : firstp)->valuep()->cloneTree(false); // A const
+		} else if (attrType == AstAttrType::ENUM_PREV) {
+		    values[i] = prevp->valuep()->cloneTree(false); // A const
+		} else {
+		    nodep->v3fatalSrc("Bad case");
+		}
+		prevp = itemp;
+		itemp = nextp;
+	    }
+	}
+	// Fill in all unspecified values and add to table
+	for (unsigned i=0; i<(msbdim+1); ++i) {
+	    AstNode* valp = values[i];
+	    if (!valp) {
+		if (attrType == AstAttrType::ENUM_NAME) {
+		    valp = new AstConst(nodep->fileline(), AstConst::String(), "");
+		} else if (attrType == AstAttrType::ENUM_NEXT
+			   || attrType == AstAttrType::ENUM_PREV) {
+		    valp = new AstConst(nodep->fileline(), V3Number(nodep->fileline(), nodep->width(), 0));
+		} else {
+		    nodep->v3fatalSrc("Bad case");
+		}
+	    }
+	    initp->addInitsp(valp);
 	}
 	varp->iterate(*this);  // May have already done $unit so must do this var
+	m_tableMap.insert(make_pair(make_pair(nodep,attrType), varp));
 	return varp;
     }
 
diff --git a/src/V3WidthCommit.h b/src/V3WidthCommit.h
index ba2a8d1..e2deb28 100644
--- a/src/V3WidthCommit.h
+++ b/src/V3WidthCommit.h
@@ -72,8 +72,9 @@ class WidthCommitVisitor : public AstNVisitor {
 public:
     // METHODS
     static AstConst* newIfConstCommitSize (AstConst* nodep) {
-	if ((nodep->dtypep()->width() != nodep->num().width())
-	    || !nodep->num().sized()) {  // Need to force the number rrom unsized to sized
+	if (((nodep->dtypep()->width() != nodep->num().width())
+	     || !nodep->num().sized())
+	    && !nodep->num().isString()) {  // Need to force the number rrom unsized to sized
 	    V3Number num (nodep->fileline(), nodep->dtypep()->width());
 	    num.opAssign(nodep->num());
 	    num.isSigned(nodep->isSigned());
diff --git a/src/Verilator.cpp b/src/Verilator.cpp
index 44c30bd..a33eb76 100644
--- a/src/Verilator.cpp
+++ b/src/Verilator.cpp
@@ -630,7 +630,7 @@ int main(int argc, char** argv, char** env) {
 	&& !v3Global.opt.lintOnly()
 	&& !v3Global.opt.xmlOnly()
 	&& !v3Global.opt.cdc()) {
-	v3fatal("verilator: Need --cc, --sc, --sp, --cdc, --lint-only, --xml_only or --E option");
+	v3fatal("verilator: Need --cc, --sc, --cdc, --lint-only, --xml_only or --E option");
     }
     // Check environment
     V3Options::getenvSYSTEMC();
diff --git a/src/VlcBucket.h b/src/VlcBucket.h
new file mode 100644
index 0000000..1dd9bf1
--- /dev/null
+++ b/src/VlcBucket.h
@@ -0,0 +1,133 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Bucket container
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCBUCKET_H_
+#define _VLCBUCKET_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+
+//********************************************************************
+// VlcBuckets - Container of all coverage point hits for a given test
+// This is a bitmap array - we store a single bit to indicate a test
+// has hit that point with sufficient coverage.
+
+class VlcBuckets {
+private:
+    // MEMBERS
+    vluint64_t*		m_datap;		///< Pointer to first bucket (dynamically allocated)
+    vluint64_t		m_dataSize;		///< Current entries in m_datap
+    vluint64_t		m_bucketsCovered;	///< Num buckets with sufficient coverage
+
+private:
+    static inline vluint64_t covBit(vluint64_t point) { return 1ULL<<(point & 63); }
+    inline vluint64_t allocSize() const { return sizeof(vluint64_t) * m_dataSize / 64; }
+    void allocate(vluint64_t point) {
+	vluint64_t oldsize = m_dataSize;
+	if (m_dataSize<point) m_dataSize=(point+64) & ~63ULL;  // Keep power of two
+	m_dataSize *= 2;
+	//UINFO(9, "Realloc "<<allocSize()<<" for "<<point<<"  "<<(void*)(m_datap)<<endl);
+	m_datap = (vluint64_t*)realloc(m_datap, allocSize());
+	if (!m_datap) {v3fatal("Out of memory increasing buckets"); }
+	for (vluint64_t i=oldsize; i<m_dataSize; i+=64) m_datap[i/64] = 0;
+    }
+
+public:
+    // CONSTRUCTORS
+    VlcBuckets() {
+	m_dataSize = 0;
+	m_datap = NULL;
+	m_bucketsCovered = 0;
+	allocate(1024);
+    }
+    ~VlcBuckets() {
+	m_dataSize = 0;
+	free(m_datap); m_datap=NULL;
+    }
+
+    // ACCESSORS
+    static vluint64_t sufficient() { return 1; }
+    vluint64_t bucketsCovered() const { return m_bucketsCovered; }
+
+    // METHODS
+    void addData(vluint64_t point, vluint64_t hits) {
+	if (hits >= sufficient()) {
+	    //UINFO(9,"     addData "<<point<<" "<<hits<<" size="<<m_dataSize<<endl);
+	    if (point >= m_dataSize) allocate(point);
+	    m_datap[point/64] |= covBit(point);
+	    m_bucketsCovered++;
+	}
+    }
+    void clearHits(vluint64_t point) const {
+	if (point >= m_dataSize) {
+	    return;
+	} else {
+	    m_datap[point/64] &= ~covBit(point);
+	}
+    }
+    bool exists(vluint64_t point) const {
+	if (point >= m_dataSize) {
+	    return false;
+	} else {
+	    return (m_datap[point/64] & covBit(point)) ? 1:0;
+	}
+    }
+    vluint64_t hits(vluint64_t point) const {
+	if (point >= m_dataSize) {
+	    return 0;
+	} else {
+	    return (m_datap[point/64] & covBit(point)) ? 1:0;
+	}
+    }
+    vluint64_t popCount() const {
+	vluint64_t pop = 0;
+	for (vluint64_t i=0; i<m_dataSize; i++) {
+	    if (hits(i)) pop++;
+	}
+	return pop;
+    }
+    vluint64_t dataPopCount(const VlcBuckets& remaining) {
+	vluint64_t pop = 0;
+	for (vluint64_t i=0; i<m_dataSize; i++) {
+	    if (hits(i) && remaining.hits(i)) pop++;
+	}
+	return pop;
+    }
+    void orData(const VlcBuckets& ordata) {
+	for (vluint64_t i=0; i<m_dataSize; i++) {
+	    if (hits(i) && ordata.hits(i)) {
+		clearHits(i);
+	    }
+	}
+    }
+
+    void dump() const {
+	cout<<"#     ";
+	for (vluint64_t i=0; i<m_dataSize; i++) {
+	    if (hits(i)) cout<<","<<i;
+	}
+	cout<<endl;
+    }
+};
+
+
+//######################################################################
+
+#endif // guard
diff --git a/src/VlcMain.cpp b/src/VlcMain.cpp
new file mode 100644
index 0000000..3aaf6df
--- /dev/null
+++ b/src/VlcMain.cpp
@@ -0,0 +1,203 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: main()
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+// Cheat for speed and compile .cpp files into one object
+#define _V3ERROR_NO_GLOBAL_ 1
+#include "V3Error.cpp"
+#include "VlcTop.cpp"
+
+#include "VlcOptions.h"
+#include "VlcTop.h"
+
+#include <fstream>
+#include <algorithm>
+#include <unistd.h>
+
+//######################################################################
+// VlcOptions
+
+void VlcOptions::addReadFile(const string& filename) {
+    if (m_readFiles.find(filename) == m_readFiles.end()) {
+	m_readFiles.insert(filename);
+    }
+}
+
+string VlcOptions::version() {
+    string ver = DTVERSION;
+    ver += " rev "+cvtToStr(DTVERSION_rev);
+    return ver;
+}
+
+bool VlcOptions::onoff(const char* sw, const char* arg, bool& flag) {
+    // if sw==arg, then return true (found it), and flag=true
+    // if sw=="-no-arg", then return true (found it), and flag=false
+    // if sw=="-noarg", then return true (found it), and flag=false
+    // else return false
+    if (arg[0]!='-') v3fatalSrc("OnOff switches must have leading dash.\n");
+    if (0==strcmp(sw,arg)) { flag=true; return true; }
+    else if (0==strncmp(sw,"-no",3) && (0==strcmp(sw+3,arg+1))) { flag=false; return true; }
+    else if (0==strncmp(sw,"-no-",4) && (0==strcmp(sw+4,arg+1))) { flag=false; return true; }
+    return false;
+}
+
+void VlcOptions::parseOptsList(int argc, char** argv) {
+    // Parse parameters
+    // Note argc and argv DO NOT INCLUDE the filename in [0]!!!
+    // May be called recursively when there are -f files.
+#define shift { ++i; }
+    for (int i=0; i<argc; )  {
+	UINFO(9, " Option: "<<argv[i]<<endl);
+	if (argv[i][0]=='-') {
+	    const char *sw = argv[i];
+	    bool flag = true;
+	    // Allow gnu -- switches
+	    if (sw[0]=='-' && sw[1]=='-') ++sw;
+	    if (0) {}
+	    // Single switches
+	    else if ( onoff   (sw, "-annotate-all", flag/*ref*/) ) { m_annotateAll = flag; }
+	    else if ( onoff   (sw, "-rank", flag/*ref*/) ) { m_rank = flag; }
+	    else if ( onoff   (sw, "-unlink", flag/*ref*/) )	{ m_unlink = flag; }
+	    // Parameterized switches
+	    else if ( !strcmp (sw, "-annotate") && (i+1)<argc ) {
+		shift;
+		m_annotateOut = argv[i];
+	    }
+	    else if ( !strcmp (sw, "-debug") ) {
+		V3Error::debugDefault(3);
+	    }
+	    else if ( !strcmp (sw, "-debugi") && (i+1)<argc ) {
+		shift;
+		V3Error::debugDefault(atoi(argv[i]));
+	    }
+	    else if ( !strcmp (sw, "-V") ) {
+		showVersion(true);
+		exit(0);
+	    }
+	    else if ( !strcmp (sw, "-version") ) {
+		showVersion(false);
+		exit(0);
+	    }
+	    else if ( !strcmp (sw, "-write") && (i+1)<argc ) {
+		shift;
+		m_writeFile = argv[i];
+	    }
+	    else {
+		v3fatal ("Invalid option: "<<argv[i]);
+	    }
+	    shift;
+	} // - options
+	else if (1) {
+	    addReadFile(argv[i]);
+	    shift;
+	}
+	else {
+	    v3fatal ("Invalid argument: "<<argv[i]);
+	    shift;
+	}
+    }
+#undef shift
+}
+
+void VlcOptions::showVersion(bool verbose) {
+    cout <<version();
+    cout <<endl;
+    if (!verbose) return;
+
+    cout <<endl;
+    cout << "Copyright 2003-2014 by Wilson Snyder.  Verilator is free software; you can\n";
+    cout << "redistribute it and/or modify the Verilator internals under the terms of\n";
+    cout << "either the GNU Lesser General Public License Version 3 or the Perl Artistic\n";
+    cout << "License Version 2.0.\n";
+
+    cout <<endl;
+    cout << "See http://www.veripool.org/verilator for documentation\n";
+}
+
+//######################################################################
+// File searching
+// (TODO: Make a V3Os with these functions and share with Verilator)
+
+string VlcOptions::filenameNonDir (const string& filename) {
+    string::size_type pos;
+    if ((pos = filename.rfind("/")) != string::npos) {
+	return filename.substr(pos+1);
+    } else {
+	return filename;
+    }
+}
+
+//######################################################################
+
+int main(int argc, char** argv, char** env) {
+    // General initialization
+    ios::sync_with_stdio();
+
+    VlcTop top;
+
+    // Command option parsing
+    top.opt.parseOptsList(argc-1, argv+1);
+
+    if (top.opt.readFiles().empty()) {
+	top.opt.addReadFile("vlt_coverage.pl");
+    }
+
+    const VlStringSet& readFiles = top.opt.readFiles();
+    for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
+	string filename = *it;
+	top.readCoverage(filename);
+    }
+
+    if (debug() >= 9) {
+	top.tests().dump(true);
+	top.points().dump();
+    }
+
+    V3Error::abortIfWarnings();
+    if (top.opt.annotateOut() != "") {
+        top.annotate(top.opt.annotateOut());
+    }
+
+    if (top.opt.rank()) {
+	top.rank();
+	top.tests().dump(false);
+    }
+
+    if (top.opt.writeFile() != "") {
+	top.writeCoverage(top.opt.writeFile());
+	V3Error::abortIfWarnings();
+        if (top.opt.unlink()) {
+	    const VlStringSet& readFiles = top.opt.readFiles();
+	    for (VlStringSet::iterator it = readFiles.begin(); it != readFiles.end(); ++it) {
+		string filename = *it;
+		unlink(filename.c_str());
+	    }
+        }
+    }
+    
+    // Final writing shouldn't throw warnings, but...
+    V3Error::abortIfWarnings();
+
+    UINFO(1,"Done, Exiting...\n");
+}
+
+// Local Variables:
+// compile-command: "v4make bin/verilator_coverage --debugi 9 test_regress/t/t_vlcov_data_*.dat"
+// End:
+
diff --git a/src/VlcOptions.h b/src/VlcOptions.h
new file mode 100644
index 0000000..d644085
--- /dev/null
+++ b/src/VlcOptions.h
@@ -0,0 +1,87 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Command line options
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCOPTIONS_H_
+#define _VLCOPTIONS_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+#include <string>
+#include <vector>
+#include <map>
+#include <set>
+
+#include "config_rev.h"
+
+//######################################################################
+// V3Options - Command line options
+
+typedef vector<string> VlStringList;
+typedef set<string> VlStringSet;
+
+class VlcOptions {
+    // MEMBERS (general options)
+    string	m_annotateOut;	// main switch: --annotate I<output_directory>
+    bool	m_annotateAll;	// main switch: --annotate-all
+    int		m_annotateMin;	// main switch: --annotate-min I<count>
+    VlStringSet	m_readFiles;	// main switch: --read
+    bool	m_rank;		// main switch: --rank
+    bool	m_unlink;	// main switch: --unlink
+    string	m_writeFile;	// main switch: --write
+
+private:
+    // METHODS
+    void showVersion(bool verbose);
+    bool onoff(const char* sw, const char* arg, bool& flag);
+
+public:
+    // CREATORS
+    VlcOptions() {
+	m_annotateAll = false;
+	m_annotateMin = 10;
+	m_rank = false;
+	m_unlink = false;
+    }
+    ~VlcOptions() {}
+    void setDebugMode(int level);
+
+    // METHODS
+    void parseOptsList(int argc, char** argv);
+    void addReadFile(const string& filename);
+
+    // ACCESSORS (options)
+    const VlStringSet& readFiles() const { return m_readFiles; }
+    string annotateOut() const { return m_annotateOut; }
+    bool annotateAll() const { return m_annotateAll; }
+    int annotateMin() const { return m_annotateMin; }
+    bool rank() const { return m_rank; }
+    bool unlink() const { return m_unlink; }
+    string writeFile() const { return m_writeFile; }
+    
+    // METHODS (from main)
+    static string version();
+
+    // METHODS (file searching)
+    static string filenameNonDir(const string& filename);
+};
+
+//######################################################################
+
+#endif // guard
diff --git a/src/VlcPoint.h b/src/VlcPoint.h
new file mode 100644
index 0000000..a2aabb3
--- /dev/null
+++ b/src/VlcPoint.h
@@ -0,0 +1,152 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Coverage points
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCPOINT_H_
+#define _VLCPOINT_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+#include "verilated_cov_key.h"
+#include <map>
+#include <vector>
+#include <iomanip>
+
+//********************************************************************
+// VlcPoint - A coverage point (across all tests)
+
+class VlcPoint {
+private:
+    // MEMBERS
+    string		m_name;		//< Name of the point
+    vluint64_t		m_pointNum;	//< Point number
+    vluint64_t		m_testsCovering;//< Number tests with non-zero coverage of this point
+    vluint64_t		m_count;	//< Count of hits across all tests
+
+public:
+    // CONSTRUCTORS
+    VlcPoint(const string& name, int pointNum) {
+	m_name = name;
+	m_pointNum = pointNum;
+	m_testsCovering = 0;
+	m_count = 0;
+    }
+    ~VlcPoint() {}
+    // ACCESSORS
+    const string& name() const { return m_name; }
+    vluint64_t pointNum() const { return m_pointNum; }
+    vluint64_t testsCovering() const { return m_testsCovering; }
+    void countInc(vluint64_t inc) { m_count += inc; }
+    vluint64_t count() const { return m_count; }
+    void testsCoveringInc() { m_testsCovering++; }
+    // KEY ACCESSORS
+    string filename() const { return keyExtract(VL_CIK_FILENAME); }
+    string comment() const { return keyExtract(VL_CIK_COMMENT); }
+    string type() const { return keyExtract(VL_CIK_TYPE); }
+    string thresh() const { return keyExtract(VL_CIK_THRESH); }  // string as maybe ""
+    int lineno() const { return atoi(keyExtract(VL_CIK_LINENO).c_str()); }
+    int column() const { return atoi(keyExtract(VL_CIK_COLUMN).c_str()); }
+    // METHODS
+    string keyExtract(const char* shortKey) const {
+	// Hot function
+	size_t shortLen = strlen(shortKey);
+	const string namestr = name();
+	for (const char* cp = namestr.c_str(); *cp; ++cp) {
+	    if (*cp == '\001') {
+		if (0==strncmp(cp+1, shortKey, shortLen)
+		    && cp[shortLen+1] == '\002') {
+		    cp += shortLen+2;  // Skip \001+short+\002
+		    const char* ep = cp;
+		    while (*ep && *ep != '\001') ++ep;
+		    return string(cp, ep-cp);
+		}
+	    }
+	}
+	return "";
+    }
+    static void dumpHeader() {
+	cout<<"Points:\n";
+	cout<<"  Num,    TestsCover,    Count,  Name"<<endl;
+    }
+    void dump() const {
+	cout<<"  "<<setw(8)<<setfill('0')<<pointNum()
+	    <<",  "<<setw(7)<<setfill(' ')<<testsCovering()
+	    <<",  "<<setw(7)<<setfill(' ')<<count()
+	    <<",  \""<<name()<<"\""<<endl;
+    }
+};
+
+//********************************************************************
+// VlcPoints - Container of all points
+
+class VlcPoints {
+private:
+    // MEMBERS
+    typedef std::map<string,vluint64_t> NameMap;
+    NameMap		m_nameMap;	//< Name to point-number
+    vector<VlcPoint>	m_points;	//< List of all points
+    vluint64_t		m_numPoints;	//< Total unique points
+
+public:
+    // ITERATORS
+    typedef NameMap ByName;
+    typedef ByName::iterator iterator;
+    ByName::iterator begin() { return m_nameMap.begin(); }
+    ByName::iterator end() { return m_nameMap.end(); }
+
+public:
+    // CONSTRUCTORS
+    VlcPoints() {
+	m_numPoints = 0;
+    }
+    ~VlcPoints() {}
+
+    // METHODS
+    void dump() {
+	UINFO(2,"dumpPoints...\n");
+	VlcPoint::dumpHeader();
+	for (VlcPoints::ByName::iterator it=begin(); it!=end(); ++it) {
+	    const VlcPoint& point = pointNumber(it->second);
+	    point.dump();
+	}
+    }
+    VlcPoint& pointNumber(vluint64_t num) {
+	return m_points[num];
+    }
+    vluint64_t findAddPoint(const string& name, vluint64_t count) {
+	vluint64_t pointnum;
+	NameMap::iterator iter = m_nameMap.find(name);
+	if (iter != m_nameMap.end()) {
+	    pointnum = iter->second;
+	    m_points[pointnum].countInc(count);
+	}
+	else {
+	    pointnum = m_numPoints++;
+	    VlcPoint point (name, pointnum);
+	    point.countInc(count);
+	    m_points.push_back(point);
+	    m_nameMap.insert(make_pair(point.name(), point.pointNum()));
+	}
+	return pointnum;
+    }
+};
+
+//######################################################################
+
+#endif // guard
diff --git a/src/VlcSource.h b/src/VlcSource.h
new file mode 100644
index 0000000..fc7e344
--- /dev/null
+++ b/src/VlcSource.h
@@ -0,0 +1,145 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Source file to annotate with line coverage
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCSOURCE_H_
+#define _VLCSOURCE_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+#include <map>
+#include <vector>
+
+//********************************************************************
+// VlcColumnCount - count at specific source file, line and column
+
+class VlcSourceCount {
+private:
+    // MEMBERS
+    int		m_lineno;	///< Line number
+    int		m_column;	///< Column number
+    vluint64_t	m_count;	///< Count
+    bool	m_ok;		///< Coverage is above threshold
+
+public:
+    // CONSTRUCTORS
+    VlcSourceCount(int lineno, int column) {
+	m_lineno = lineno;
+	m_column = column;
+	m_count = 0;
+	m_ok = false;
+    }
+    ~VlcSourceCount() {}
+
+    // ACCESSORS
+    int lineno() const { return m_lineno; }
+    int column() const { return m_column; }
+    vluint64_t count() const { return m_count; }
+    bool ok() const { return m_ok; }
+
+    // METHODS
+    void incCount(vluint64_t count, bool ok) {
+	m_count += count;
+	if (ok) m_ok = true;
+    }
+};
+
+//********************************************************************
+// VlcSource - source file to annotate
+
+class VlcSource {
+public:
+    // TYPES
+    typedef map<int,VlcSourceCount> ColumnMap;	// Map of {column}
+    typedef map<int,ColumnMap> LinenoMap;	// Map of {lineno}{column}
+
+private:
+    // MEMBERS
+    string	m_name;		//< Name of the source file
+    bool	m_needed;	//< Need to annotate; has low coverage
+    LinenoMap	m_lines;	//< Map of each annotated line
+
+public:
+    // CONSTRUCTORS
+    VlcSource(const string& name) {
+	m_name = name;
+	m_needed = false;
+    }
+    ~VlcSource() {}
+
+    // ACCESSORS
+    const string& name() const { return m_name; }
+    void needed(bool flag) { m_needed = flag; }
+    bool needed() const { return m_needed; }
+    LinenoMap& lines() { return m_lines; }
+
+    // METHODS
+    void incCount(int lineno, int column, vluint64_t count, bool ok) {
+	LinenoMap::iterator lit = m_lines.find(lineno);
+	if (lit == m_lines.end()) {
+	    lit = m_lines.insert(make_pair(lineno,ColumnMap())).first;
+	}
+	ColumnMap& cmap = lit->second;
+	ColumnMap::iterator cit = cmap.find(column);
+	if (cit == cmap.end()) {
+	    cit = cmap.insert(make_pair(column,VlcSourceCount(lineno, column))).first;
+	}
+	VlcSourceCount& sc = cit->second;
+	sc.incCount(count,ok);
+    }
+};
+
+//********************************************************************
+// VlcSources - Container of all source files
+
+class VlcSources {
+public:
+    // TYPES
+    typedef map<string,VlcSource> NameMap;
+private:
+    // MEMBERS
+    NameMap	m_sources;	//< List of all sources
+
+public:
+    // ITERATORS
+    typedef NameMap::iterator iterator;
+    NameMap::iterator begin() { return m_sources.begin(); }
+    NameMap::iterator end() { return m_sources.end(); }
+
+public:
+    // CONSTRUCTORS
+    VlcSources() {}
+    ~VlcSources() {}
+
+    // METHODS
+    VlcSource& findNewSource(const string& name) {
+	NameMap::iterator iter = m_sources.find(name);
+	if (iter != m_sources.end()) {
+	    return iter->second;
+	}
+	else {
+	    iter = m_sources.insert(make_pair(name, VlcSource(name))).first;
+	    return iter->second;
+	}
+    }
+};
+
+//######################################################################
+
+#endif // Guard
diff --git a/src/VlcTest.h b/src/VlcTest.h
new file mode 100644
index 0000000..63675de
--- /dev/null
+++ b/src/VlcTest.h
@@ -0,0 +1,137 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Test/coverage file container
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCTEST_H_
+#define _VLCTEST_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+#include "VlcPoint.h"
+#include "VlcBucket.h"
+#include <map>
+#include <vector>
+
+//********************************************************************
+// VlcTest - a single testrun i.e. a file containing coverage data
+
+class VlcTest {
+private:
+    // MEMBERS
+    string	m_name;		//< Name of the test
+    double	m_computrons;	//< Runtime for the test
+    vluint64_t	m_testrun;	//< Test run number, for database use
+    vluint64_t	m_rank;		//< Execution rank suggestion
+    vluint64_t	m_rankPoints;	//< Ranked additional points
+    vluint64_t	m_user;		//< User data for algorithms (not persisted in .dat file)
+    VlcBuckets	m_buckets;	//< Coverage data for each coverage point
+
+public:
+    // CONSTRUCTORS
+    VlcTest(const string& name, vluint64_t testrun, double comp) {
+	m_name = name;
+	m_computrons = comp;
+	m_testrun = testrun;
+	m_rank = 0;
+	m_rankPoints = 0;
+	m_user = 0;
+    }
+    ~VlcTest() {}
+
+    // ACCESSORS
+    const string& name() const { return m_name; }
+    double computrons() const { return m_computrons; }
+    vluint64_t testrun() const { return m_testrun; }
+    VlcBuckets& buckets() { return m_buckets; }
+    vluint64_t bucketsCovered() const { return m_buckets.bucketsCovered(); }
+    vluint64_t rank() const { return m_rank; }
+    void rank(vluint64_t flag) { m_rank = flag; }
+    vluint64_t rankPoints() const { return m_rankPoints; }
+    void rankPoints(vluint64_t flag) { m_rankPoints = flag; }
+    vluint64_t user() const { return m_user; }
+    void user(vluint64_t flag) { m_user = flag; }
+
+    // METHODS
+    static void dumpHeader() {
+	cout<<"Tests:\n";
+	//cout<<"  Testrun, Computrons,";  // Currently not loaded
+	cout<<"  Covered,     Rank,  RankPts,  Filename"<<endl;
+    }
+    void dump(bool bucketsToo) {
+	if (testrun() || computrons()) {
+	    cout<<"  "<<setw(8)<<setfill('0')<<testrun()
+		<<",  "<<setw(7)<<setfill(' ')<<computrons()<<",";
+	}
+	cout<<"  "<<setw(7)<<setfill(' ')<<bucketsCovered()
+	    <<",  "<<setw(7)<<setfill(' ')<<rank()
+	    <<",  "<<setw(7)<<setfill(' ')<<rankPoints()
+	    <<",  \""<<name()<<"\""<<endl;
+	if (bucketsToo)	m_buckets.dump();
+    }
+};
+
+//********************************************************************
+// VlcTests - Container of all tests
+
+class VlcTests {
+public:
+    // TYPES
+    typedef vector<VlcTest*> ByName;
+private:
+    // MEMBERS
+    ByName	m_tests;	//< List of all tests
+
+public:
+    // ITERATORS
+    typedef ByName::iterator iterator;
+    ByName::iterator begin() { return m_tests.begin(); }
+    ByName::iterator end() { return m_tests.end(); }
+
+public:
+    // CONSTRUCTORS
+    VlcTests() {}
+    ~VlcTests() {
+	for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
+	    delete *it;  *it=NULL;
+	}
+    }
+
+    // METHODS
+    void dump(bool bucketsToo) {
+	UINFO(2,"dumpTests...\n");
+	VlcTest::dumpHeader();
+	for (VlcTests::ByName::iterator it=begin(); it!=end(); ++it) {
+	    (*it)->dump(bucketsToo);
+	}
+    }
+    VlcTest* newTest(const string& name, vluint64_t testrun, double comp) {
+	VlcTest* testp = new VlcTest(name, testrun, comp);
+	m_tests.push_back(testp);
+	return testp;
+    }
+    void clearUser() {
+	for (ByName::iterator it = m_tests.begin(); it != m_tests.end(); ++it) {
+	    (*it)->user(0);
+	}
+    }
+};
+
+//######################################################################
+
+#endif // Guard
diff --git a/src/VlcTop.cpp b/src/VlcTop.cpp
new file mode 100644
index 0000000..b71be0d
--- /dev/null
+++ b/src/VlcTop.cpp
@@ -0,0 +1,263 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: top implementation
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+// Cheat for speed and compile .cpp files into one object
+#include "V3Error.h"
+#include "VlcOptions.h"
+#include "VlcTop.h"
+
+#include <sys/stat.h>
+#include <fstream>
+#include <algorithm>
+
+//######################################################################
+
+void VlcTop::readCoverage(const string& filename, bool nonfatal) {
+    UINFO(2,"readCoverage "<<filename<<endl);
+
+    ifstream is (filename.c_str());
+    if (!is) {
+	if (!nonfatal) v3fatal("Can't read "<<filename);
+	return;
+    }
+
+    // Testrun and computrons argument unsupported as yet
+    VlcTest* testp = tests().newTest(filename, 0, 0);
+
+    while (!is.eof()) {
+	string line;
+	getline(is, line);
+	//UINFO(9," got "<<line<<endl);
+	if (line[0] == 'C') {
+	    string::size_type secspace=3;
+	    for (; secspace<line.length(); secspace++) {
+		if (line[secspace]=='\'' && line[secspace+1]==' ') break;
+	    }
+	    string point = line.substr(3,secspace-3);
+	    vluint64_t hits = atoll(line.c_str()+secspace+1);
+	    //UINFO(9,"   point '"<<point<<"'"<<" "<<hits<<endl);
+
+	    vluint64_t pointnum = points().findAddPoint(point, hits);
+	    if (pointnum) {} // Prevent unused
+	    if (opt.rank()) {  // Only if ranking - uses a lot of memory
+		if (hits >= VlcBuckets::sufficient()) {
+		    points().pointNumber(pointnum).testsCoveringInc();
+		    testp->buckets().addData(pointnum, hits);
+		}
+	    }
+	}
+    }
+}
+
+void VlcTop::writeCoverage(const string& filename) {
+    UINFO(2,"writeCoverage "<<filename<<endl);
+
+    ofstream os (filename.c_str());
+    if (!os) {
+	v3fatal("Can't write "<<filename);
+	return;
+    }
+
+    os << "# SystemC::Coverage-3" << endl;
+    for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
+	const VlcPoint& point = m_points.pointNumber(it->second);
+	os <<"C '"<<point.name()<<"' " << point.count()<<endl;
+    }
+}
+
+//********************************************************************
+
+struct CmpComputrons {
+    inline bool operator () (const VlcTest* lhsp, const VlcTest* rhsp) const {
+	if (lhsp->computrons() != rhsp->computrons()) {
+	    return lhsp->computrons() < rhsp->computrons();
+	}
+	return lhsp->bucketsCovered() > rhsp->bucketsCovered();
+    }
+};
+
+void VlcTop::rank() {
+    UINFO(2,"rank...\n");
+    vluint64_t nextrank=1;
+
+    // Sort by computrons, so fast tests get selected first
+    vector<VlcTest*> bytime;
+    for (VlcTests::ByName::iterator it=m_tests.begin(); it!=m_tests.end(); ++it) {
+	VlcTest* testp = *it;
+	if (testp->bucketsCovered()) {	 // else no points, so can't help us
+	    bytime.push_back(*it);
+	}
+    }
+    sort(bytime.begin(), bytime.end(), CmpComputrons()); // Sort the vector
+
+    VlcBuckets remaining;
+    for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
+	VlcPoint* pointp = &points().pointNumber(it->second);
+	// If any tests hit this point, then we'll need to cover it.
+	if (pointp->testsCovering()) { remaining.addData(pointp->pointNum(), 1); }
+    }
+
+    // Additional Greedy algorithm
+    // O(n^2) Ouch.  Probably the thing to do is randomize the order of data
+    // then hierarchically solve a small subset of tests, and take resulting
+    // solution and move up to larger subset of tests.  (Aka quick sort.)
+    while (1) {
+	if (debug()) { UINFO(9,"Left on iter"<<nextrank<<": "); remaining.dump(); }
+	VlcTest* bestTestp = NULL;
+	vluint64_t bestRemain = 0;
+	for (vector<VlcTest*>::iterator it=bytime.begin(); it!=bytime.end(); ++it) {
+	    VlcTest* testp = *it;
+	    if (!testp->rank()) {
+		vluint64_t remain = testp->buckets().dataPopCount(remaining);
+		if (remain > bestRemain) {
+		    bestTestp = testp;
+		    bestRemain = remain;
+		}
+	    }
+	}
+	if (VlcTest* testp = bestTestp) {
+	    testp->rank(nextrank++);
+	    testp->rankPoints(bestRemain);
+	    remaining.orData(bestTestp->buckets());
+	} else {
+	    break;   // No test covering more stuff found
+	}
+    }
+}
+
+//######################################################################
+
+void VlcTop::annotateCalc() {
+    // Calculate per-line information into filedata structure
+    for (VlcPoints::ByName::iterator it=m_points.begin(); it!=m_points.end(); ++it) {
+	const VlcPoint& point = m_points.pointNumber(it->second);
+	string filename = point.filename();
+	int lineno = point.lineno();
+	if (filename!="" && lineno!=0) {
+	    int column = point.column();
+	    VlcSource& source = sources().findNewSource(filename);
+	    string threshStr = point.thresh();
+	    unsigned thresh = (threshStr!="") ? atoi(threshStr.c_str()) : opt.annotateMin();
+	    bool ok = (point.count() >= thresh);
+	    UINFO(9, "AnnoCalc count "<<filename<<" "<<lineno<<" "<<point.count()<<endl);
+	    source.incCount(lineno, column, point.count(), ok);
+	}
+    }
+}
+
+void VlcTop::annotateCalcNeeded() {
+    // Compute which files are needed.  A file isn't needed if it has appropriate
+    // coverage in all categories
+    int totCases = 0;
+    int totOk = 0;
+    for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
+	VlcSource& source = sit->second;
+	//UINFO(1,"Source "<<source.name()<<endl);
+	if (opt.annotateAll()) source.needed(true);
+	VlcSource::LinenoMap& lines = source.lines();
+	for (VlcSource::LinenoMap::iterator lit=lines.begin(); lit!=lines.end(); ++lit) {
+	    VlcSource::ColumnMap& cmap = lit->second;
+	    for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
+		VlcSourceCount& col = cit->second;
+		//UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
+		++totCases;
+		if (col.ok()) {
+		    ++totOk;
+		} else {
+		    source.needed(true);
+		}
+	    }
+	}
+    }
+    float pct = totCases ? (100*totOk / totCases) : 0;
+    cout<<"Total coverage ("<<totOk<<"/"<<totCases<<") "
+	<<fixed<<setw(3)<<setprecision(2)<<pct<<"%"<<endl;
+    if (totOk != totCases) cout<<"See lines with '%00' in "<<opt.annotateOut()<<endl;
+}
+
+void VlcTop::annotateOutputFiles(const string& dirname) {
+    // Create if uncreated, ignore errors
+    mkdir(dirname.c_str(), 0777);
+    for (VlcSources::NameMap::iterator sit=m_sources.begin(); sit!=m_sources.end(); ++sit) {
+	VlcSource& source = sit->second;
+	if (!source.needed()) continue;
+	string filename = source.name();
+	string outfilename = dirname+"/"+VlcOptions::filenameNonDir(filename);
+
+	UINFO(1,"annotateOutputFile "<<filename<<" -> "<<outfilename<<endl);
+
+	ifstream is (filename.c_str());
+	if (!is) {
+	    v3error("Can't read "<<filename);
+	    return;
+	}
+	
+	ofstream os (outfilename.c_str());
+	if (!os) {
+	    v3fatal("Can't write "<<outfilename);
+	    return;
+	}
+
+	os << "\t// verilator_coverage annotation"<<endl;
+
+	int lineno = 0;
+	while (!is.eof()) {
+	    lineno++;
+	    string line;
+	    getline(is, line);
+
+	    bool first = true;
+
+	    VlcSource::LinenoMap& lines = source.lines();
+	    VlcSource::LinenoMap::iterator lit=lines.find(lineno);
+	    if (lit != lines.end()) {
+		VlcSource::ColumnMap& cmap = lit->second;
+		for (VlcSource::ColumnMap::iterator cit=cmap.begin(); cit!=cmap.end(); ++cit) {
+		    VlcSourceCount& col = cit->second;
+		    //UINFO(0,"Source "<<source.name()<<" lineno="<<col.lineno()<<" col="<<col.column()<<endl);
+		    os<<(col.ok()?" ":"%")
+		      <<setfill('0')<<setw(6)<<col.count()
+		      <<"\t"<<line<<endl;
+		    if (first) {
+			first = false;
+			// Multiple columns on same line; print line just once
+			string indent = "";
+			for (const char* cp=line.c_str(); isspace(*cp); ++cp) {
+			    indent += *cp;
+			}
+			line = indent + "verilator_coverage: (next point on previous line)\n";
+		    }
+		}
+	    }
+
+	    if (first) {
+		os<<"\t"<<line<<endl;
+	    }
+	}
+    }
+}
+
+void VlcTop::annotate(const string& dirname) {
+    // Calculate per-line information into filedata structure
+    annotateCalc();
+    annotateCalcNeeded();
+    annotateOutputFiles(dirname);
+}
+
diff --git a/src/VlcTop.h b/src/VlcTop.h
new file mode 100644
index 0000000..5c34c18
--- /dev/null
+++ b/src/VlcTop.h
@@ -0,0 +1,69 @@
+// -*- mode: C++; c-file-style: "cc-mode" -*-
+//*************************************************************************
+// DESCRIPTION: verilator_coverage: Top global container
+//
+// Code available from: http://www.veripool.org/verilator
+//
+//*************************************************************************
+//
+// Copyright 2003-2014 by Wilson Snyder.  This program is free software; you can
+// redistribute it and/or modify it under the terms of either the GNU
+// Lesser General Public License Version 3 or the Perl Artistic License
+// Version 2.0.
+//
+// Verilator is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+//*************************************************************************
+

+#ifndef _VLCTOP_H_
+#define _VLCTOP_H_ 1
+
+#include "config_build.h"
+#include "verilatedos.h"
+#include "VlcOptions.h"
+#include "VlcTest.h"
+#include "VlcPoint.h"
+#include "VlcSource.h"
+
+//######################################################################
+// VlcTop - Top level options container
+
+class VlcTop {
+public:
+    // PUBLIC MEMBERS
+    VlcOptions opt;		//< Runtime options
+private:
+    // MEMBERS
+    VlcTests	m_tests;	//< List of all tests (all coverage files)
+    VlcPoints	m_points;	//< List of all points
+    VlcSources	m_sources;	//< List of all source files to annotate
+
+    // METHODS
+    void annotateCalc();
+    void annotateCalcNeeded();
+    void annotateOutputFiles(const string& dirname);
+
+public:
+    // CONSTRUCTORS
+    VlcTop() {}
+    ~VlcTop() {}
+
+    // ACCESSORS
+    VlcTests& tests() { return m_tests; }
+    VlcPoints& points() { return m_points; }
+    VlcSources& sources() { return m_sources; }
+
+    // METHODS
+    void annotate(const string& dirname);
+    void readCoverage(const string& filename, bool nonfatal=false);
+    void writeCoverage(const string& filename);
+
+    void rank();
+};
+
+//######################################################################
+
+#endif // guard
diff --git a/src/astgen b/src/astgen
index 042f9ba..e0c7885 100755
--- a/src/astgen
+++ b/src/astgen
@@ -19,8 +19,8 @@ my @Opt_Cpt;
 my @Opt_I;
 Getopt::Long::config ("pass_through", "no_auto_abbrev");
 if (! GetOptions (
-	  "help"	=> \&report,
-	  "debug"	=> \&debug,
+	  "help"	=> \&usage,
+	  "debug"	=> sub { $Debug = 1; },
 	  "classes!"	=> \$opt_classes,
 	  "report!"	=> \$opt_report,
 	  "<>"		=> \&parameter,
@@ -54,10 +54,6 @@ sub usage {
     exit (1);
 }
 
-sub debug {
-    $Debug = 1;
-}
-
 sub parameter {
     my $param = shift;
     if ($param =~ /^-+I(\S+)/) {
diff --git a/src/config_build.h b/src/config_build.h
index b254886..3e3b8c9 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.866 2014-11-15"
+#define PACKAGE_STRING "Verilator 3.868 2014-12-20"
 
 #define DTVERSION	PACKAGE_STRING
 
diff --git a/src/config_rev.h b/src/config_rev.h
index 42c6ac1..af201f2 100644
--- a/src/config_rev.h
+++ b/src/config_rev.h
@@ -1 +1 @@
-static const char* DTVERSION_rev = "verilator_3_864-18-g55f0d4d";
+static const char* DTVERSION_rev = "verilator_3_866-36-g1a3378e";
diff --git a/src/verilog.l b/src/verilog.l
index f45b20b..d73342c 100644
--- a/src/verilog.l
+++ b/src/verilog.l
@@ -103,8 +103,6 @@ void V3ParseImp::verilatorCmtBad(const char* textp) {
 }
 
 // See V3Read.cpp
-//void V3ParseImp::stateExitPsl() { BEGIN VLG; }
-//void V3ParseImp::statePushVlg() { yy_push_state(VLG); }
 //void V3ParseImp::statePop() { yy_pop_state(); }
 
 //======================================================================
@@ -138,7 +136,7 @@ void yyerrorf(const char* format, ...) {
 
 %s V95 V01 V05 S05 S09 S12
 %s STRING ATTRMODE TABLE
-%s VA5 SAX PSL VLT
+%s VA5 SAX VLT
 %s SYSCHDR SYSCINT SYSCIMP SYSCIMPH SYSCCTOR SYSCDTOR
 %s IGNORE
 
@@ -179,7 +177,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 
   /************************************************************************/
   /* Verilog 1995 */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX>{
   {ws}			{ }	/* otherwise ignore white-space */
   {crnl}		{ NEXTLINE(); }		/* Count line numbers */
   /*     Extensions to Verilog set, some specified by PSL */
@@ -352,7 +350,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /* Verilog 2001 */
-<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V01,V05,VA5,S05,S09,S12,SAX>{
   /*     System Tasks */
   "$signed"		{ FL; return yD_SIGNED; }
   "$unsigned"		{ FL; return yD_UNSIGNED; }
@@ -383,13 +381,13 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /* Verilog 2005 */
-<V05,S05,S09,S12,SAX,PSL>{
+<V05,S05,S09,S12,SAX>{
   /*     Keywords */
   "uwire"		{ FL; return yWIRE; }
 }
 
   /* System Verilog 2005 */
-<S05,S09,S12,SAX,PSL>{
+<S05,S09,S12,SAX>{
   /*     System Tasks */
   "$bits"		{ FL; return yD_BITS; }
   "$clog2"		{ FL; return yD_CLOG2; }
@@ -414,18 +412,21 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "always_comb"		{ FL; return yALWAYS_COMB; }
   "always_ff"		{ FL; return yALWAYS_FF; }
   "always_latch"	{ FL; return yALWAYS_LATCH; }
+  "assert"		{ FL; return yASSERT; }
   "bind"		{ FL; return yBIND; }
   "bit"			{ FL; return yBIT; }
   "break"		{ FL; return yBREAK; }
   "byte"		{ FL; return yBYTE; }
   "chandle"		{ FL; return yCHANDLE; }
   "clocking"		{ FL; return yCLOCKING; }
+  "const"		{ FL; return yCONST__LEX; }
   "context"		{ FL; return yCONTEXT; }
   "continue"		{ FL; return yCONTINUE; }
+  "cover"		{ FL; return yCOVER; }
   "do"			{ FL; return yDO; }
   "endclocking"		{ FL; return yENDCLOCKING; }
-  "endpackage"		{ FL; return yENDPACKAGE; }
   "endinterface"	{ FL; return yENDINTERFACE; }
+  "endpackage"		{ FL; return yENDPACKAGE; }
   "endprogram"		{ FL; return yENDPROGRAM; }
   "endproperty"		{ FL; return yENDPROPERTY; }
   "enum"		{ FL; return yENUM; }
@@ -434,8 +435,8 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "iff"			{ FL; return yIFF; }
   "import"		{ FL; return yIMPORT; }
   "inside"		{ FL; return yINSIDE; }
-  "interface"		{ FL; return yINTERFACE; }
   "int"			{ FL; return yINT; }
+  "interface"		{ FL; return yINTERFACE; }
   "logic"		{ FL; return yLOGIC; }
   "longint"		{ FL; return yLONGINT; }
   "modport"		{ FL; return yMODPORT; }
@@ -443,6 +444,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "packed"		{ FL; return yPACKED; }
   "priority"		{ FL; return yPRIORITY; }
   "program"		{ FL; return yPROGRAM; }
+  "property"		{ FL; return yPROPERTY; }
   "pure"		{ FL; return yPURE; }
   "rand"		{ FL; return yRAND; }
   "randc"		{ FL; return yRANDC; }
@@ -454,6 +456,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "timeprecision"	{ FL; return yTIMEPRECISION; }
   "timeunit"		{ FL; return yTIMEUNIT; }
   "typedef"		{ FL; return yTYPEDEF; }
+  "union"		{ FL; return yUNION; }
   "unique"		{ FL; return yUNIQUE; }
   "var"			{ FL; return yVAR; }
   "void"		{ FL; return yVOID; }
@@ -461,6 +464,8 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   /* Note assert_strobe was in SystemVerilog 3.1, but removed for SystemVerilog 2005 */
   "$root"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "alias"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
+  "assume"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
+  "before"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "bins"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "binsof"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "class"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -492,6 +497,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "randomize"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "randsequence"	{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "ref"			{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
+  "sequence"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "shortreal"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "solve"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "super"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
@@ -503,25 +509,11 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "wait_order"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "wildcard"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
   "with"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
-}
-
-  /* SystemVerilog 2005 ONLY not PSL; different rules for PSL as specified below */
-<S05,S09,S12,SAX>{
-  /*     Keywords */
-  "assert"		{ FL; return yASSERT; }
-  "const"		{ FL; return yCONST__LEX; }
-  "cover"		{ FL; return yCOVER; }
-  "property"		{ FL; return yPROPERTY; }
-  "union"		{ FL; return yUNION; }
-  /*     Generic unsupported warnings */
-  "assume"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
-  "before"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
-  "sequence"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
-  "within"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented in non-PSL context: %s",yytext); }
+  "within"		{ yyerrorf("Unsupported: SystemVerilog 2005 reserved word not implemented: %s",yytext); }
 }
 
   /* SystemVerilog 2009 */
-<S09,S12,SAX,PSL>{
+<S09,S12,SAX>{
   /*     Keywords */
   "global"	 	{ FL; return yGLOBAL__LEX; }
   "unique0"	 	{ FL; return yUNIQUE0; }
@@ -550,7 +542,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /* System Verilog 2012 */
-<S12,SAX,PSL>{
+<S12,SAX>{
   /*     Keywords */
   "implements"	 	{ yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
   "interconnect" 	{ yyerrorf("Unsupported: SystemVerilog 2012 reserved word not implemented: %s",yytext); }
@@ -559,7 +551,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /* Default PLI rule */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX>{
   "$"[a-zA-Z_$][a-zA-Z0-9_$]*	{ string str (yytext,yyleng);
 				  yylval.strp = PARSEP->newString(AstNode::encodeName(str));
 				  // Lookup unencoded name including the $, to avoid hitting normal signals
@@ -663,99 +655,10 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /************************************************************************/
-  /* PSL */
-
-  /*Entry into PSL; mode change */
-<V95,V01,V05,VA5,S05,S09,S12,SAX>{
-  "psl"			{ yy_push_state(PSL); FL; return yPSL; }
-}
-
-<PSL>{
-  /*     Special things */
-  "psl"			{ ; }	// 'psl' may occur in middle of statement, so easier just to suppress
-  /*     Keywords */
-  "assert"		{ FL; return yPSL_ASSERT; }
-  "assume"		{ FL; return yPSL_ASSERT; } //==assert
-  "before_!"		{ yyerrorf("Illegal syntax, use before!_ instead of %s",yytext); }
-  "clock"		{ FL; return yPSL_CLOCK; }
-  "countones"		{ FL; return yD_COUNTONES; }
-  "cover"		{ FL; return yPSL_COVER; }
-  "isunknown"		{ FL; return yD_ISUNKNOWN; }
-  "onehot"		{ FL; return yD_ONEHOT; }
-  "onehot0"		{ FL; return yD_ONEHOT0; }
-  "until_!"		{ yyerrorf("Illegal syntax, use until!_ instead of %s",yytext); }
-  "report"		{ FL; return yPSL_REPORT; }
-  "true"		{ FL; return yTRUE; }
-  /*     Generic unsupported warnings */
-  /*"A"			{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"AF"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"AG"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"AX"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"E"			{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"EF"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"EG"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"EX"		{ yyerrorf("Unsupported: PSL branching reserved word not implemented: %s",yytext); } */
-  /*"F"			{ FL; return yEVENTUALLYB; } */
-  /*"G"			{ FL; return yALWAYS; } */
-  /*"U"			{ FL; return yUNTILB; } */
-  /*"W"			{ FL; return yUNTIL; } */
-  /*"X"			{ FL; return yNEXT; } */
-  /*"X!"		{ FL; return yNEXTB; } */
-  /*"restrict"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
-  /*"strong"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
-  /*"until"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } S09 instead */
-  "%for"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "%if"			{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "abort"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "assume_guarantee"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "before"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "before!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "before!_"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "before_"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "boolean"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "const"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "endpoint"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "eventually!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "fairness"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "fell"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "forall"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "in"			{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "inf"			{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "inherit"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "never"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_a"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_a!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_e"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_e!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event_a"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event_a!"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event_e"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "next_event_e!"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "prev"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "property"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "restrict_guarantee"	{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "rose"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "sequence"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "stable"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "union"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "until!"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "until!_"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "until_"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "vmode"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "vprop"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); } //Unsup in other tools
-  "vunit"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-  "within"		{ yyerrorf("Unsupported: PSL reserved word not implemented: %s",yytext); }
-}
-
-  /************************************************************************/
   /* Meta comments */
 
   /* Converted from //{cmt}verilator ...{cmt} by preprocessor */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX>{
   "/*verilator"{ws}*"*/"		{}	/* Ignore empty comments, may be `endif // verilator */
   "/*verilator clock_enable*/"		{ FL; return yVL_CLOCK_ENABLE; }
   "/*verilator coverage_block_off*/"	{ FL; return yVL_COVERAGE_BLOCK_OFF; }
@@ -793,8 +696,6 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 <V95,V01,V05,VA5,S05,S09,S12,SAX>{
   "{"			{ FL; return yytext[0]; }
   "}"			{ FL; return yytext[0]; }
-}
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
   "!"			{ FL; return yytext[0]; }
   "#"			{ FL; return yytext[0]; }
   "$"			{ FL; return yytext[0]; }
@@ -826,7 +727,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   /* Operators and multi-character symbols */
 
   /* Verilog 1995 Operators */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX>{
   "&&"			{ FL; return yP_ANDAND; }
   "||"			{ FL; return yP_OROR; }
   "<="			{ FL; return yP_LTE; }
@@ -848,7 +749,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
 }
 
   /* Verilog 2001 Operators */
-<V01,V05,VA5,S05,S09,S12,SAX,PSL>{
+<V01,V05,VA5,S05,S09,S12,SAX>{
   "<<<"			{ FL; return yP_SLEFT; }
   ">>>"			{ FL; return yP_SSRIGHT; }
   "**"			{ FL; return yP_POW; }
@@ -891,23 +792,8 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "["{ws}*"->"		{ FL; return yP_BRAMINUSGT; }
 }
 
-  /* PSL Operators */
-<PSL>{
-  "{"			{ FL; return yPSL_BRA; }	// Avoid parser hitting concatenate.
-  "}"			{ FL; return yPSL_KET; }	// Avoid parser hitting concatenate.
-  "<->"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } //Unsup in other tools
-  "[*"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_STAR
-  "[*]"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_STAR_KET
-  "[+]"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_PLUS_KET
-  "[->"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_MINUS_GT
-  "[->]"		{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_MINUS_GT_KET
-  "[="			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_BRA_EQ
-  "|->"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_ORMINUSGT
-  "|=>"			{ yyerrorf("Unsupported: PSL operator not implemented: %s",yytext); } // yP_OREQGT
-}
-
   /* Identifiers and numbers */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT>{
   {escid}		{ FL; yylval.strp = PARSEP->newString
 	  			(AstNode::encodeName(string(yytext+1))); // +1 to skip the backslash
 			  return yaID__LEX;
@@ -997,7 +883,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   /* Preprocessor */
   /* Common for all SYSC header states */
   /* OPTIMIZE: we return one per line, make it one for the entire block */
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT,SYSCHDR,SYSCINT,SYSCIMP,SYSCIMPH,SYSCCTOR,SYSCDTOR,IGNORE>{
   "`accelerate"				{ } // Verilog-XL compatibility
   "`autoexpand_vectornets"		{ } // Verilog-XL compatibility
   "`celldefine"				{ PARSEP->inCellDefine(true); }
@@ -1026,7 +912,6 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   "`portcoerce"				{ }
   "`pragma"{ws}+[^\n\r]*		{ } // Verilog 2005
   "`protect"				{ }
-  "`psl"				{ if (PARSEP->optPsl()) { BEGIN PSL; } else { BEGIN IGNORE; } }
   "`remove_gatenames"			{ } // Verilog-XL compatibility
   "`remove_netnames"			{ } // Verilog-XL compatibility
   "`resetall"				{ PARSEP->fileline()->warnOn(V3ErrorCode::I_DEF_NETTYPE_WIRE,true); } // Rest handled by preproc
@@ -1073,7 +958,7 @@ vnum	{vnum1}|{vnum2}|{vnum3}|{vnum4}|{vnum5}
   /************************************************************************/
   /* Default rules - leave last */
 
-<V95,V01,V05,VA5,S05,S09,S12,SAX,PSL,VLT>{
+<V95,V01,V05,VA5,S05,S09,S12,SAX,VLT>{
   "`"[a-zA-Z_0-9]+	{ FL; yyerrorf("Define or directive not defined: %s",yytext); }
   "//"[^\n]*		{ }  /* throw away single line comments */
   .			{ FL; return yytext[0]; }	/* return single char ops. */
@@ -1087,15 +972,14 @@ int V3ParseImp::stateVerilogRecent() { return STATE_VERILOG_RECENT; }
 double V3ParseImp::parseDouble(const char* textp, size_t length) {
     char* strgp = new char[length+1];
     char* dp=strgp;
-    for (const char* sp=textp; sp<(textp+length);) {
-	if (*sp != '_') *dp++ = *sp++;
-	else sp++;
+    for (const char* sp=textp; sp<(textp+length); ++sp) {
+	if (*sp != '_') *dp++ = *sp;
     }
     *dp++ = '\0';
     char* endp = strgp;
     double d = strtod(strgp, &endp);
     size_t parsed_len = endp-strgp;
-    if (parsed_len != length) { yyerrorf("Syntax error parsing real: %s",strgp); }
+    if (parsed_len != strlen(strgp)) { yyerrorf("Syntax error parsing real: %s",strgp); }
     delete strgp;
     return d;
 }
diff --git a/src/verilog.y b/src/verilog.y
index 4cdeb17..d77a53d 100644
--- a/src/verilog.y
+++ b/src/verilog.y
@@ -488,12 +488,6 @@ class AstSenTree;
 %token<fl>		yD_WARNING	"$warning"
 %token<fl>		yD_WRITE	"$write"
 
-%token<fl>		yPSL		"psl"
-%token<fl>		yPSL_ASSERT	"PSL assert"
-%token<fl>		yPSL_CLOCK	"PSL clock"
-%token<fl>		yPSL_COVER	"PSL cover"
-%token<fl>		yPSL_REPORT	"PSL report"
-
 %token<fl>		yVL_CLOCK		"/*verilator sc_clock*/"
 %token<fl>		yVL_CLOCK_ENABLE	"/*verilator clock_enable*/"
 %token<fl>		yVL_COVERAGE_BLOCK_OFF	"/*verilator coverage_block_off*/"
@@ -566,8 +560,6 @@ class AstSenTree;
 %token<fl>		yP_SRIGHTEQ	">>="
 %token<fl>		yP_SSRIGHTEQ	">>>="
 
-%token<fl>		yPSL_BRA	"{"
-%token<fl>		yPSL_KET	"}"
 %token<fl>	 	yP_LOGIFF
 
 // [* is not a operator, as "[ * ]" is legal
@@ -578,7 +570,6 @@ class AstSenTree;
 // PSL op precedence
 %right	 	yP_MINUSGT  yP_LOGIFF
 %right		yP_ORMINUSGT  yP_OREQGT
-%left<fl>	prPSLCLK
 
 // Verilog op precedence
 %right		'?' ':'
@@ -638,20 +629,6 @@ class AstSenTree;
 
 %%
 //**********************************************************************
-// Feedback to the Lexer
-// Note we read a parenthesis ahead, so this may not change the lexer at the right point.
-
-stateExitPsl:			// For PSL lexing, return from PSL state
-		/* empty */			 	{ PARSEP->stateExitPsl(); }
-	;
-statePushVlg:			// For PSL lexing, escape current state into Verilog state
-		/* empty */			 	{ PARSEP->statePushVlg(); }
-	;
-statePop:			// Return to previous lexing state
-		/* empty */			 	{ PARSEP->statePop(); }
-	;
-
-//**********************************************************************
 // Files
 
 source_text:			// ==IEEE: source_text
@@ -994,7 +971,8 @@ interface_itemList<nodep>:
 interface_item<nodep>:		// IEEE: interface_item + non_port_interface_item
 		port_declaration ';'			{ $$ = $1; }
 	//			// IEEE: non_port_interface_item
-	//UNSUP	generate_region				{ $$ = $1; }
+	//			// IEEE: generate_region
+	|	interface_generate_region		{ $$ = $1; }
 	|	interface_or_generate_item		{ $$ = $1; }
 	//UNSUP	program_declaration			{ $$ = $1; }
 	//UNSUP	interface_declaration			{ $$ = $1; }
@@ -1003,6 +981,11 @@ interface_item<nodep>:		// IEEE: interface_item + non_port_interface_item
 	|	module_common_item			{ $$ = $1; }
 	;
 
+interface_generate_region<nodep>:		// ==IEEE: generate_region
+		yGENERATE interface_itemList yENDGENERATE	{ $$ = new AstGenerate($1, $2); }
+	|	yGENERATE yENDGENERATE			{ $$ = NULL; }
+	;
+
 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
@@ -1698,8 +1681,6 @@ module_common_item<nodep>:	// ==IEEE: module_common_item
 	|	yALWAYS_LATCH event_controlE stmtBlock	{ $$ = new AstAlways($1,VAlwaysKwd::ALWAYS_LATCH, $2,$3); }
 	|	loop_generate_construct			{ $$ = $1; }
 	|	conditional_generate_construct		{ $$ = $1; }
-	//			// Verilator only
-	|	pslStmt 				{ $$ = $1; }
 	//
 	|	error ';'				{ $$ = NULL; }
 	;
@@ -2987,7 +2968,7 @@ expr<nodep>:			// IEEE: part of expression/constant_expression/primary
 	|	~noPar__IGNORE~'(' expr ')'		{ $$ = $2; }
 	//UNSUP	~noPar__IGNORE~'(' expr ':' expr ':' expr ')'	{ $$ = $4; }
 	//			// PSL rule
-	|	'_' '(' statePushVlg expr statePop ')'	{ $$ = $4; }	// Arbitrary Verilog inside PSL
+	|	'_' '(' expr ')'			{ $$ = $3; }	// Arbitrary Verilog inside PSL
 	//
 	//			// IEEE: cast/constant_cast
 	|	casting_type yP_TICK '(' expr ')'	{ $$ = new AstCast($2,$4,$1); }
@@ -3087,11 +3068,6 @@ fexprScope<nodep>:		// exprScope, For use as first part of statement (disambigua
 		BISONPRE_COPY(exprScope,{s/~l~/f/g})	// {copied}
 	;
 
-// Psl excludes {}'s by lexer converting to different token
-exprPsl<nodep>:
-		expr					{ $$ = $1; }
-	;
-
 // PLI calls exclude "" as integers, they're strings
 // For $c("foo","bar") we want "bar" as a string, not a Verilog integer.
 exprStrText<nodep>:
@@ -3514,7 +3490,7 @@ str<strp>:			// yaSTRING but with \{escapes} need decoded
 	;
 
 strAsInt<nodep>:
-		yaSTRING				{ $$ = new AstConst($<fl>1,V3Number(V3Number::VerilogString(),$<fl>1,GRAMMARP->deQuote($<fl>1,*$1)));}
+		yaSTRING				{ $$ = new AstConst($<fl>1,V3Number(V3Number::VerilogStringLiteral(),$<fl>1,GRAMMARP->deQuote($<fl>1,*$1)));}
 	;
 
 strAsIntIgnore<nodep>:		// strAsInt, but never matches for when expr shouldn't parse strings
@@ -3622,56 +3598,6 @@ package_scopeIdFollows<packagep>:	// IEEE: package_scope
 	//UNSUP	/*cont*/	yP_COLONCOLON	{ UNSUP }
 	;
 
-//************************************************
-// PSL Statements
-
-pslStmt<nodep>:
-		yPSL pslDir  stateExitPsl		{ $$ = $2; }
-	|	yPSL pslDecl stateExitPsl 		{ $$ = $2; }
-	;
-
-pslDir<nodep>:
-		id ':' pslDirOne			{ $$ = $3; }
-	|	pslDirOne		       		{ $$ = $1; }
-	;
-
-pslDirOne<nodep>:
-		yPSL_ASSERT pslProp ';'				{ $$ = new AstPslAssert($1,$2); }
-	|	yPSL_ASSERT pslProp yPSL_REPORT yaSTRING ';'	{ $$ = new AstPslAssert($1,$2,*$4); }
-	|	yPSL_COVER  pslProp ';'				{ $$ = new AstPslCover($1,$2,NULL); }
-	|	yPSL_COVER  pslProp yPSL_REPORT yaSTRING ';'	{ $$ = new AstPslCover($1,$2,NULL,*$4); }
-	;
-
-pslDecl<nodep>:
-		yDEFAULT yPSL_CLOCK '=' senitemEdge ';'		{ $$ = new AstPslDefClock($3, $4); }
-	|	yDEFAULT yPSL_CLOCK '=' '(' senitemEdge ')' ';'	{ $$ = new AstPslDefClock($3, $5); }
-	;
-
-//************************************************
-// PSL Properties, Sequences and SEREs
-// Don't use '{' or '}'; in PSL they're yPSL_BRA and yPSL_KET to avoid expr concatenates
-
-pslProp<nodep>:
-		pslSequence				{ $$ = $1; }
-	|	pslSequence '@' %prec prPSLCLK '(' senitemEdge ')' { $$ = new AstPslClocked($2,$4,NULL,$1); }  // or pslSequence @ ...?
-	;
-
-pslSequence<nodep>:
-		yPSL_BRA pslSere yPSL_KET		{ $$ = $2; }
-	;
-
-pslSere<nodep>:
-		pslExpr					{ $$ = $1; }
-	|	pslSequence				{ $$ = $1; }  // Sequence containing sequence
-	;
-
-// Undocumented PSL rule is that {} is always a SERE; concatenation is not allowed.
-// This can be bypassed with the _(...) embedding of any arbitrary expression.
-pslExpr<nodep>:
-		exprPsl					{ $$ = new AstPslBool($1->fileline(), $1); }
-	|	yTRUE					{ $$ = new AstPslBool($1, new AstConst($1, AstConst::LogicTrue())); }
-	;
-
 //**********************************************************************
 // VLT Files
 
@@ -3815,7 +3741,7 @@ AstVar* V3ParseGrammar::createVariable(FileLine* fileline, string name, AstRange
 
 string V3ParseGrammar::deQuote(FileLine* fileline, string text) {
     // Fix up the quoted strings the user put in, for example "\"" becomes "
-    // Reverse is AstNode::quoteName(...)
+    // Reverse is V3Number::quoteNameControls(...)
     bool quoted = false;
     string newtext;
     unsigned char octal_val = 0;
diff --git a/src/vlcovgen b/src/vlcovgen
new file mode 100755
index 0000000..533505f
--- /dev/null
+++ b/src/vlcovgen
@@ -0,0 +1,173 @@
+#!/usr/bin/perl -w
+# See copyright, etc in below POD section.
+######################################################################
+
+#require 5.006_001;
+use Getopt::Long;
+use IO::File;
+use Pod::Usage;
+use strict;
+use vars qw ($Debug);
+
+our @Items;
+
+#======================================================================
+# main
+
+$Debug = 0;
+my $Opt_Srcdir = ".";
+Getopt::Long::config ("pass_through", "no_auto_abbrev");
+if (! GetOptions (
+	  "help"	=> \&usage,
+	  "debug"	=> sub { $Debug = 1; },
+	  "srcdir=s"	=> \$Opt_Srcdir,
+	  "<>"		=> sub { die "%Error: Unknown parameter: $_[0],"; },
+    )) {
+    usage();
+}
+
+read_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
+lint();
+write_keys("$Opt_Srcdir/../include/verilated_cov_key.h");
+
+#----------------------------------------------------------------------
+
+sub usage {
+    pod2usage(-verbose=>2, -exitval=>2, -output=>\*STDOUT);
+    exit (1);
+}
+
+#######################################################################
+
+sub read_keys {
+    my $filename = shift;
+
+    my $fh = IO::File->new("<$filename") or die "%Error: $! $filename,";
+    while (defined (my $line = $fh->getline())) {
+	$line =~ s/\/\/.*$//;
+	next if $line =~ /^\s*$/;
+	if ($line =~ /^\s*VLCOVGEN_ITEM/) {
+	    $line =~ /^\s*VLCOVGEN_ITEM *\( *"([^"]+)" *\)/
+		or die "%Error: $filename:$.: Misformed VLCOVGEN_ITEM line,";
+	    my @data;
+	    my $code = "\@data = ($1);";
+	    eval $code;
+	    die "%Error: $filename:$.: Parsing '$code': $@," if $@;
+	    push @Items, {@data};
+	}
+    }
+}
+
+#######################################################################
+
+sub lint {
+    my %shorts;
+    my $ok = 1;
+    foreach my $itemref (@Items) {
+	if ($shorts{$itemref->{short}}) {
+	    warn "%Error: Duplicate short code: $itemref->{short},";
+	    $ok = 0;
+	}
+	$shorts{$itemref->{short}} = 1;
+    }
+    return $ok;
+}
+
+sub write_keys {
+    my $filename = shift;
+
+    my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
+
+    my @in;
+    my @out;
+    my $deleting;
+    while (defined(my $line = $fh->getline)) {
+	push @in, $line;
+	if ($line =~ /VLCOVGEN_CIK_AUTO_EDIT_BEGIN/) {
+	    $deleting = 1;
+	    push @out, $line;
+	    foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
+		push @out, sprintf("#define VL_CIK_%s \"%s\"\n",
+				   uc $keyref->{name}, $keyref->{short});
+	    }
+	}
+	elsif ($line =~ /VLCOVGEN_SHORT_AUTO_EDIT_BEGIN/) {
+	    $deleting = 1;
+	    push @out, $line;
+	    foreach my $keyref (sort {$a->{name} cmp $b->{name}} @Items) {
+		push @out, sprintf("\tif (key == \"%s\") return VL_CIK_%s;\n",
+				   $keyref->{name}, uc $keyref->{name});
+	    }
+	}
+	elsif ($line =~ /VLCOVGEN_.*AUTO_EDIT_END/) {
+	    $deleting = 0;
+	    push @out, $line;
+	}
+	elsif ($deleting) {
+	}
+	else {
+	    push @out, $line;
+	}
+    }
+    $fh->close;
+
+    my $ok = join("", @out) eq join("", @in);
+    if (!$ok) {
+	my $fh = IO::File->new(">$filename") or die "%Error: $! writing $filename\n";
+	$fh->print(join "", @out);
+	$fh->close;
+    }
+}
+
+
+#######################################################################
+__END__
+
+=pod
+
+=head1 NAME
+
+vlcovgen - Generate verilated_cov headers to reduce C++ code duplication
+
+=head1 SYNOPSIS
+
+  (called from make rules)
+  vlcovgen
+
+=head1 DESCRIPTION
+
+Generates several files for Verilator compilations.
+
+=head1 ARGUMENTS
+
+=over 4
+
+=item --help
+
+Displays this message and program version and exits.
+
+=back
+
+=head1 DISTRIBUTION
+
+Copyright 2002-2014 by Wilson Snyder.  Verilator 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.
+
+This program is distributed in the hope that it will be useful, but WITHOUT
+ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+more details.
+
+=head1 AUTHORS
+
+Wilson Snyder <wsnyder at wsnyder.org>
+
+=head1 SEE ALSO
+
+=cut
+
+######################################################################
+### Local Variables:
+### compile-command: "./vlcovgen --srcdir ."
+### End:
diff --git a/test_regress/Makefile_obj b/test_regress/Makefile_obj
index 0a487eb..2b68424 100644
--- a/test_regress/Makefile_obj
+++ b/test_regress/Makefile_obj
@@ -52,7 +52,7 @@ endif
 
 #Our own compile rules; Faster compile, all in one file
 $(VM_PREFIX)__ALLboth.cpp: $(VK_CLASSES_CPP) $(VK_SUPPORT_CPP)
-	$(SP_INCLUDER) $^ > $@
+	$(VERILATOR_INCLUDER) -DVL_INLINE_OPT=inline $^ > $@
 
 $(VM_PREFIX)__ALLboth.o: $(VM_PREFIX)__ALLboth.cpp
 	$(OBJCACHE) $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(OPT_FAST) -c -o $@ $<
diff --git a/test_regress/driver.pl b/test_regress/driver.pl
index abee28c..d13e33b 100755
--- a/test_regress/driver.pl
+++ b/test_regress/driver.pl
@@ -115,9 +115,15 @@ if ($#opt_tests<0) {
     foreach my $dir (@Test_Dirs) {
 	my @stats = stat($dir);  # Uniquify by inode, so different paths to same place get combined
 	next if !$stats[1] || $uniq{$stats[1]}++;
-	push @opt_tests, glob ("${dir}/t_*.pl");
+	push @opt_tests, sort(glob ("${dir}/t_*.pl"));
     }
 }
+if ($#opt_tests>=2 && $opt_jobs>=2) {
+    # Without this tests such as t_debug_sigsegv_bt_bad.pl will occasionally
+    # block on input and cause a SIGSTOP, then a "fg" was needed to resume testing.
+    print STDERR "== Many jobs; redirecting STDIN\n";
+    open(STDIN,  "+>/dev/null");
+}
 
 mkdir "obj_dir";
 
@@ -388,7 +394,7 @@ sub new {
     $self->{stats} ||= "$self->{obj_dir}/V".$self->{name}."__stats.txt";
     $self->{status_filename} ||= "$self->{obj_dir}/V".$self->{name}.".status";
     $self->{run_log_filename} ||= "$self->{obj_dir}/vlt_sim.log";
-    $self->{coverage_filename} ||= "$self->{obj_dir}/vlt_coverage.pl";
+    $self->{coverage_filename} ||= "$self->{obj_dir}/coverage.dat";
     $self->{vcd_filename}  ||= "$self->{obj_dir}/sim.vcd";
     $self->{main_filename} ||= "$self->{obj_dir}/$self->{VM_PREFIX}__main.cpp";
     ($self->{top_filename} = $self->{pl_filename}) =~ s/\.pl$//;
@@ -633,10 +639,6 @@ sub compile {
 	    $self->skip("Test requires SystemC; ignore error since not installed\n");
 	    return 1;
 	}
-	elsif ($self->{coverage} && !$Have_System_Perl) {
-	    $self->skip("Test requires SystemPerl; ignore error since not installed\n");
-	    return 1;
-	}
 
 	if (!$param{fails} && $param{verilator_make_gcc}
 	    && $param{make_main}) {
@@ -1143,7 +1145,7 @@ sub _make_main {
 
     if ($self->{coverage}) {
 	$fh->print("#if VM_COVERAGE\n");
-	$fh->print("    SpCoverage::write(\"",$self->{coverage_filename},"\");\n");
+	$fh->print("    VerilatedCov::write(\"",$self->{coverage_filename},"\");\n");
 	$fh->print("#endif //VM_COVERAGE\n");
     }
     if ($self->{trace}) {
diff --git a/test_regress/t/t_assert_basic_cover.pl b/test_regress/t/t_assert_basic_cover.pl
index e10bc2e..a14ea16 100755
--- a/test_regress/t/t_assert_basic_cover.pl
+++ b/test_regress/t/t_assert_basic_cover.pl
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 top_filename("t/t_assert_basic.v");
 
 compile (
-	 verilator_flags2 => ['--assert --sp --coverage-user'],
+	 verilator_flags2 => ['--assert --cc --coverage-user'],
 	 );
 
 execute (
diff --git a/test_regress/t/t_assert_cover.pl b/test_regress/t/t_assert_cover.pl
index f20a45b..9b33acb 100755
--- a/test_regress/t/t_assert_cover.pl
+++ b/test_regress/t/t_assert_cover.pl
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 top_filename("t/t_assert_cover.v");
 
 compile (
-	 verilator_flags2 => ['--assert --sp --coverage-user'],
+	 verilator_flags2 => ['--assert --cc --coverage-user'],
 	 nc_flags2 => ["+nccovoverwrite +nccoverage+all +nccovtest+$Self->{name}"]
 	 );
 
diff --git a/test_regress/t/t_bitsel_wire_array_bad.pl b/test_regress/t/t_bitsel_wire_array_bad.pl
index b2b725f..3a68ce0 100755
--- a/test_regress/t/t_bitsel_wire_array_bad.pl
+++ b/test_regress/t/t_bitsel_wire_array_bad.pl
@@ -10,13 +10,12 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 # Comple time only test
 
 compile (
-	 verilator_flags2 => ["--lint-only"],
-	 fails=>1,
-#	 expect=>
-# TBD better error message, bug509
-#'.*
-#%Error: Exiting due to.*',
-	 );
+    verilator_flags2 => ["--lint-only"],
+    fails=>1,
+    expect=>
+'.*%Error: t/t_bitsel_wire_array_bad.v:\d+: Illegal assignment of constant to unpacked array
+%Error: Exiting due to.*',
+    );
 
 ok(1);
 1;
diff --git a/test_regress/t/t_cover_line.out b/test_regress/t/t_cover_line.out
new file mode 100644
index 0000000..c6840d2
--- /dev/null
+++ b/test_regress/t/t_cover_line.out
@@ -0,0 +1,170 @@
+	// verilator_coverage annotation
+	// DESCRIPTION: Verilator: Verilog Test module
+	//
+	// This file ONLY is placed into the Public Domain, for any use,
+	// without warranty, 2008 by Wilson Snyder.
+	
+	module t (/*AUTOARG*/
+	   // Inputs
+	   clk
+	   );
+	
+	   input clk;
+	
+	   reg 	 toggle; initial toggle=0;
+	
+	   integer cyc; initial cyc=1;
+	   wire [7:0] cyc_copy = cyc[7:0];
+	
+	   alpha a1 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	   alpha a2 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	   beta  b1 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	   beta  b2 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	   tsk   t1 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	   off   o1 (/*AUTOINST*/
+		     // Inputs
+		     .clk			(clk),
+		     .toggle			(toggle));
+	
+	   always @ (posedge clk) begin
+ 000010	      if (cyc!=0) begin
+		 cyc <= cyc + 1;
+		 toggle <= '0;
+%000001		 if (cyc==3) begin
+		    toggle <= '1;
+		 end
+%000001		 else if (cyc==5) begin
+	`ifdef VERILATOR
+		    $c("call_task();");
+	`else
+		    call_task();
+	`endif
+		 end
+%000001		 else if (cyc==10) begin
+		    $write("*-* All Finished *-*\n");
+		    $finish;
+		 end
+	      end
+	   end
+	
+	   task call_task;
+	      /* verilator public */
+	      t1.center_task(1'b1);
+	   endtask
+	
+	endmodule
+	
+	module alpha (/*AUTOARG*/
+	   // Inputs
+	   clk, toggle
+	   );
+	   input clk;
+	   input toggle;
+	   always @ (posedge clk) begin
+%000002	      if (toggle) begin
+		 // CHECK_COVER(-1,"top.v.a*",2)
+		 // t.a1 and t.a2 collapse to a count of 2
+	      end
+	      if (toggle) begin
+		 // CHECK_COVER_MISSING(-1)
+		 // This doesn't even get added
+		 // verilator coverage_block_off
+		 $write("");
+	      end
+	   end
+	endmodule
+	
+	module beta (/*AUTOARG*/
+	   // Inputs
+	   clk, toggle
+	   );
+	   input clk;
+	   input toggle;
+	
+	   /* verilator public_module */
+	
+	   always @ (posedge clk) begin
+%000000	      if (0) begin
+		 // CHECK_COVER(-1,"top.v.b*",0)
+		 // Make sure that we don't optimize away zero buckets
+	      end
+%000002	      if (toggle) begin
+		 // CHECK_COVER(-1,"top.v.b*",2)
+		 // t.b1 and t.b2 collapse to a count of 2
+	      end
+	      if (toggle) begin
+		 // CHECK_COVER_MISSING(-1)
+		 // This doesn't
+		 // verilator coverage_block_off
+		 $write("");
+	      end
+	   end
+	endmodule
+	
+	module tsk (/*AUTOARG*/
+	   // Inputs
+	   clk, toggle
+	   );
+	   input clk;
+	   input toggle;
+	
+	   /* verilator public_module */
+	
+	   always @ (posedge clk) begin
+	      center_task(1'b0);
+	   end
+	
+	   task center_task;
+	      input external;
+	      begin
+%000001		 if (toggle) begin
+		    // CHECK_COVER(-1,"top.v.t1",1)
+		 end
+%000001		 if (external) begin
+		    // CHECK_COVER(-1,"top.v.t1",1)
+		    $write("[%0t] Got external pulse\n", $time);
+		 end
+	      end
+	   endtask
+	
+	endmodule
+	
+	module off (/*AUTOARG*/
+	   // Inputs
+	   clk, toggle
+	   );
+	   input clk;
+	   input toggle;
+	
+	   // verilator coverage_off
+	   always @ (posedge clk) begin
+	      if (toggle) begin
+		 // CHECK_COVER_MISSING(-1)
+		 // because under coverage_module_off
+	      end
+	   end
+	   // verilator coverage_on
+	   always @ (posedge clk) begin
+%000001	      if (toggle) begin
+		 // CHECK_COVER(-1,"top.v.o1",1)
+		 // because under coverage_module_off
+	      end
+	   end
+	
+	endmodule
+	
diff --git a/test_regress/t/t_cover_line_cc.pl b/test_regress/t/t_cover_line_cc.pl
index 0b803dd..af024c4 100755
--- a/test_regress/t/t_cover_line_cc.pl
+++ b/test_regress/t/t_cover_line_cc.pl
@@ -20,5 +20,12 @@ execute (
 # Read the input .v file and do any CHECK_COVER requests
 inline_checks();
 
-ok(1);
+$Self->_run(cmd=>["../bin/verilator_coverage",
+		  "--annotate", "$Self->{obj_dir}/annotated",
+		  "$Self->{obj_dir}/coverage.dat",
+	    ],
+    );
+
+ok(files_identical("$Self->{obj_dir}/annotated/t_cover_line.v", "t/t_cover_line.out"));
+
 1;
diff --git a/test_regress/t/t_cover_line_sp.pl b/test_regress/t/t_cover_line_sp.pl
deleted file mode 100755
index 05afc6b..0000000
--- a/test_regress/t/t_cover_line_sp.pl
+++ /dev/null
@@ -1,24 +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.
-
-top_filename("t/t_cover_line.v");
-
-compile (
-	 verilator_flags2 => ['--sp --coverage-line'],
-	 );
-
-execute (
-	 check_finished=>1,
-	 );
-
-# Read the input .v file and do any CHECK_COVER requests
-inline_checks();
-
-ok(1);
-1;
diff --git a/test_regress/t/t_cover_sva_notflat.pl b/test_regress/t/t_cover_sva_notflat.pl
index 5d55d60..9ee0511 100755
--- a/test_regress/t/t_cover_sva_notflat.pl
+++ b/test_regress/t/t_cover_sva_notflat.pl
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 # Version 2.0.
 
 compile (
-	 verilator_flags2 => ['--assert --sp --coverage-user'],
+	 verilator_flags2 => ['--assert --cc --coverage-user'],
 	 );
 
 execute (
diff --git a/test_regress/t/t_cover_toggle.pl b/test_regress/t/t_cover_toggle.pl
index 9b68058..2747130 100755
--- a/test_regress/t/t_cover_toggle.pl
+++ b/test_regress/t/t_cover_toggle.pl
@@ -8,7 +8,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 # Version 2.0.
 
 compile (
-	 verilator_flags2 => ['--sp --coverage-toggle --stats'],
+	 verilator_flags2 => ['--cc --coverage-toggle --stats'],
 	 );
 
 execute (
diff --git a/test_regress/t/t_dist_spdiff.pl b/test_regress/t/t_dist_spdiff.pl
deleted file mode 100755
index ffbae66..0000000
--- a/test_regress/t/t_dist_spdiff.pl
+++ /dev/null
@@ -1,23 +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 2010 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.
-
-my $root = "..";
-if (!-r "$root/.git") {
-    $Self->skip("Not in a git repository");
-} else {
-    my $cmd = "cd $root && nodist/spdiff . $ENV{SYSTEMPERL}";
-    my $grep = `$cmd`;
-    print "$grep\n";
-    if ($grep ne "") {
-	$Self->error("Include mismatches SystemPerl src\n");
-    }
-}
-
-ok(1);
-1;
diff --git a/test_regress/t/t_sv_enum_type_methods.pl b/test_regress/t/t_enum_name2.pl
similarity index 83%
copy from test_regress/t/t_sv_enum_type_methods.pl
copy to test_regress/t/t_enum_name2.pl
index fda118f..f912897 100755
--- a/test_regress/t/t_sv_enum_type_methods.pl
+++ b/test_regress/t/t_enum_name2.pl
@@ -7,9 +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.
 
-# Not yet working on Verilator
-$Self->{vlt} and $Self->unsupported("Verilator unsupported");
-
 compile (
     );
 
diff --git a/test_regress/t/t_enum_name2.v b/test_regress/t/t_enum_name2.v
new file mode 100644
index 0000000..6e420bd
--- /dev/null
+++ b/test_regress/t/t_enum_name2.v
@@ -0,0 +1,31 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Jonathon Donaldson.
+
+package our_pkg;
+   typedef enum logic [8-1:0] {
+			       ADC_IN2IN = 8'h99,
+			       ADC_IMMED = 8'h88,
+			       ADC_INDIR = 8'h86,
+			       ADC_INIDX = 8'h97
+			       } T_Opcode;
+endpackage : our_pkg
+
+module t ();
+   our our ();
+endmodule
+
+module our
+  import our_pkg::*;
+   ();
+
+   T_Opcode IR = ADC_IN2IN;
+
+   initial begin
+      $write ("%s (%t)\n", IR.name, $realtime);
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+
+endmodule
diff --git a/test_regress/t/t_enum_type_methods.v b/test_regress/t/t_enum_type_methods.v
index b05af53..ea2ffae 100644
--- a/test_regress/t/t_enum_type_methods.v
+++ b/test_regress/t/t_enum_type_methods.v
@@ -1,48 +1,10 @@
-// DESCRIPTION: Verilator: System Verilog test of enumerated type methods
+// DESCRIPTION: Verilator: Verilog Test module
 //
-// This code instantiates a module that uses a localparam with an enumerated
-// type.
-//
-// This file ONLY is placed into the Public Domain, for any use, without
-// warranty.
-
-// Contributed 2012 by M W Lund, Atmel Corporation and Jeremy Bennett, Embecosm.
-
-
-// **** Pin Identifiers ****
-typedef enum int
-{
- PINID_A0 = 32'd0,                    // MUST BE ZERO!
- // - Standard Ports -
-           PINID_A1, PINID_A2, PINID_A3, PINID_A4, PINID_A5, PINID_A6, PINID_A7,
- PINID_B0, PINID_B1, PINID_B2, PINID_B3, PINID_B4, PINID_B5, PINID_B6, PINID_B7,
- PINID_C0, PINID_C1, PINID_C2, PINID_C3, PINID_C4, PINID_C5, PINID_C6, PINID_C7,
- PINID_D0, PINID_D1, PINID_D2, PINID_D3, PINID_D4, PINID_D5, PINID_D6, PINID_D7,
- PINID_E0, PINID_E1, PINID_E2, PINID_E3, PINID_E4, PINID_E5, PINID_E6, PINID_E7,
- PINID_F0, PINID_F1, PINID_F2, PINID_F3, PINID_F4, PINID_F5, PINID_F6, PINID_F7,
- PINID_G0, PINID_G1, PINID_G2, PINID_G3, PINID_G4, PINID_G5, PINID_G6, PINID_G7,
- PINID_H0, PINID_H1, PINID_H2, PINID_H3, PINID_H4, PINID_H5, PINID_H6, PINID_H7,
-// PINID_I0, PINID_I1, PINID_I2, PINID_I3, PINID_I4, PINID_I5, PINID_I6, PINID_I7,-> DO NOT USE!!!! I == 1
- PINID_J0, PINID_J1, PINID_J2, PINID_J3, PINID_J4, PINID_J5, PINID_J6, PINID_J7,
- PINID_K0, PINID_K1, PINID_K2, PINID_K3, PINID_K4, PINID_K5, PINID_K6, PINID_K7,
- PINID_L0, PINID_L1, PINID_L2, PINID_L3, PINID_L4, PINID_L5, PINID_L6, PINID_L7,
- PINID_M0, PINID_M1, PINID_M2, PINID_M3, PINID_M4, PINID_M5, PINID_M6, PINID_M7,
- PINID_N0, PINID_N1, PINID_N2, PINID_N3, PINID_N4, PINID_N5, PINID_N6, PINID_N7,
-// PINID_O0, PINID_O1, PINID_O2, PINID_O3, PINID_O4, PINID_O5, PINID_O6, PINID_O7,-> DO NOT USE!!!! O == 0
- PINID_P0, PINID_P1, PINID_P2, PINID_P3, PINID_P4, PINID_P5, PINID_P6, PINID_P7,
- PINID_Q0, PINID_Q1, PINID_Q2, PINID_Q3, PINID_Q4, PINID_Q5, PINID_Q6, PINID_Q7,
- PINID_R0, PINID_R1, PINID_R2, PINID_R3, PINID_R4, PINID_R5, PINID_R6, PINID_R7,
- // - AUX Port (Custom) -
- PINID_X0, PINID_X1, PINID_X2, PINID_X3, PINID_X4, PINID_X5, PINID_X6, PINID_X7,
- // - PDI Port -
- PINID_D2W_DAT, PINID_D2W_CLK,
- // - Power Pins -
- PINID_VDD0, PINID_VDD1, PINID_VDD2, PINID_VDD3,
- PINID_GND0, PINID_GND1, PINID_GND2, PINID_GND3,
- // - Maximum number of pins -
- PINID_MAX
- } t_pinid;
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Wilson Snyder.
 
+`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d:  got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
+`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d:  got='%s' exp='%s'\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
 
 module t (/*AUTOARG*/
    // Inputs
@@ -50,26 +12,85 @@ module t (/*AUTOARG*/
    );
    input clk;
 
-   wire  a = clk;
-   wire  b = 1'b0;
-   reg   c;
-   
-   simple_test_1 simple_test_1_i (/*AUTOINST*/
-				  // Outputs
-				  .c			(c),
-				  // Inputs
-				  .a			(a),
-				  .b			(b));
+   typedef enum {
+		 E01 = 1,
+		 E03 = 3,
+		 E04 = 4
+		 } my_t;
+
+   integer 	cyc=0;
+   my_t e;
 
-   // This is a compile time only test. Immediately finish
-   always @(posedge clk) begin
-      $write("*-* All Finished *-*\n");
-      $finish;
+   int arrayfits [e.num];  // Check can use as constant
+
+   string all;
+
+   // Check constification
+   initial begin
+      e = E03;
+      `checkh(e.first, E01);
+      `checkh(e.last, E04);
+      `checkh(e.last(), E04);
+      `checkh(e.next, E04); 
+      `checkh(e.next(), E04); 
+      `checkh(e.next(1), E04); 
+      //Unsup: `checkh(e.next(2), E01); 
+      `checkh(e.prev, E01); 
+      `checkh(e.prev(1), E01); 
+      //Unsup: `checkh(e.prev(2), E04); 
+      `checkh(e.num, 3);
+      `checks(e.name, "E03");
+      //
+      all = "";
+      for (my_t e = e.first; e != e.last; e = e.next) begin
+	 all = {all, e.name};
+      end
+      e = e.last;
+      all = {all, e.name};
+      `checks(all, "E01E03E04");
    end
 
-endmodule
+   // Check runtime
+   always @ (posedge clk) begin
+      cyc <= cyc + 1;
+      if (cyc==0) begin
+	 // Setup
+	 e <= E01;
+      end
+      else if (cyc==1) begin
+	 `checks(e.name, "E01");
+	 `checkh(e.next, E03); 
+	 `checkh(e.next(1), E03); 
+	 //Unsup: `checkh(e.next(2), E04); 
+	 `checkh(e.prev, E04); 
+	 `checkh(e.prev(1), E04); 
+	 //Unsup: `checkh(e.prev(2), E03); 
+	 e <= E03;
+      end
+      else if (cyc==2) begin
+	 `checks(e.name, "E03");
+	 `checkh(e.next, E04); 
+	 `checkh(e.next(1), E04); 
+	 //Unsup: `checkh(e.next(2), E01); 
+	 `checkh(e.prev, E01); 
+	 `checkh(e.prev(1), E01); 
+	 //Unsup: `checkh(e.prev(2), E04); 
+	 e <= E04;
+      end
+      else if (cyc==3) begin
+	 `checks(e.name, "E04");
+	 `checkh(e.next, E01); 
+	 `checkh(e.next(1), E01); 
+	 //Unsup: `checkh(e.next(2), E03); 
+	 `checkh(e.prev, E03); 
+	 `checkh(e.prev(1), E03); 
+	 //Unsup: `checkh(e.prev(2), E01); 
+	 e <= E01;
+      end
+      else if (cyc==99) begin
+	 $write("*-* All Finished *-*\n");
+	 $finish;
+      end
+   end
 
-// **** Simple use of parameters for sizing an array ****
-module simple_test_1 (input a, b, output c);
-   int myarray1 [PINID_MAX];
 endmodule
diff --git a/test_regress/t/t_sv_enum_type_methods.pl b/test_regress/t/t_enum_type_pins.pl
similarity index 100%
copy from test_regress/t/t_sv_enum_type_methods.pl
copy to test_regress/t/t_enum_type_pins.pl
diff --git a/test_regress/t/t_sv_enum_type_methods.v b/test_regress/t/t_enum_type_pins.v
similarity index 100%
rename from test_regress/t/t_sv_enum_type_methods.v
rename to test_regress/t/t_enum_type_pins.v
diff --git a/test_regress/t/t_sv_enum_type_methods.pl b/test_regress/t/t_flag_stats.pl
similarity index 70%
copy from test_regress/t/t_sv_enum_type_methods.pl
copy to test_regress/t/t_flag_stats.pl
index fda118f..c79b43f 100755
--- a/test_regress/t/t_sv_enum_type_methods.pl
+++ b/test_regress/t/t_flag_stats.pl
@@ -2,15 +2,15 @@
 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
+# Copyright 2008 by Wilson Snyder. This program is free software; you can
 # redistribute it and/or modify it under the terms of either the GNU
 # Lesser General Public License Version 3 or the Perl Artistic License
 # Version 2.0.
 
-# Not yet working on Verilator
-$Self->{vlt} and $Self->unsupported("Verilator unsupported");
+$Self->{vlt} or $Self->skip("Verilator only test");
 
 compile (
+    verilator_flags2 => ["--stats --stats-vars"],
     );
 
 execute (
diff --git a/test_regress/t/t_flag_stats.v b/test_regress/t/t_flag_stats.v
new file mode 100644
index 0000000..2bd129e
--- /dev/null
+++ b/test_regress/t/t_flag_stats.v
@@ -0,0 +1,13 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Wilson Snyder.
+
+module t (b);
+   output reg [31:0] b;
+   initial begin
+      b = 22;
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+endmodule
diff --git a/test_regress/t/t_flag_werror_bad2.pl b/test_regress/t/t_flag_werror_bad2.pl
index 41c91e2..c6786b5 100755
--- a/test_regress/t/t_flag_werror_bad2.pl
+++ b/test_regress/t/t_flag_werror_bad2.pl
@@ -12,7 +12,7 @@ top_filename("t/t_flag_werror.v");
 compile (
 	 v_flags2 => ["--lint-only"],
 	 fails=>$Self->{v3},
-	 verilator_flags=> [qw(-sp -Werror-WIDTH)],
+	 verilator_flags=> [qw(-cc -Werror-WIDTH)],
 	 expect=>
 q{%Error-WIDTH: t/t_flag_werror.v:\d+: Operator ASSIGNW expects 4 bits on the Assign RHS, but Assign RHS.s CONST '6'h2e' generates 6 bits.
 %Error: Exiting due to},
diff --git a/test_regress/t/t_help.pl b/test_regress/t/t_help.pl
index ba73b76..5324df1 100755
--- a/test_regress/t/t_help.pl
+++ b/test_regress/t/t_help.pl
@@ -9,14 +9,20 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 $Self->{vlt} or $Self->skip("Verilator only test");
 
-$Self->_run(fails=>1,
-		 cmd=>["perl","../bin/verilator",
-		       "--help"],
-		 logfile=>"$Self->{obj_dir}/t_help.log",
-		 tee=>0,
-	    );
-
-file_grep ("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i);
+foreach my $prog (
+    "../bin/verilator",
+    "../bin/verilator_coverage",
+    "../bin/verilator_difftree",
+    "../bin/verilator_profcfunc",
+    ) {
+    $Self->_run(fails=>1,
+		cmd=>["perl",$prog,
+		      "--help"],
+		logfile=>"$Self->{obj_dir}/t_help.log",
+		tee=>0,
+	);
+    file_grep ("$Self->{obj_dir}/t_help.log", qr/DISTRIBUTION/i);
+}
 
 ok(1);
 1;
diff --git a/test_regress/t/t_inst_overwide.pl b/test_regress/t/t_inst_overwide.pl
index d5af537..2d0bd83 100755
--- a/test_regress/t/t_inst_overwide.pl
+++ b/test_regress/t/t_inst_overwide.pl
@@ -9,7 +9,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 compile (
 	 make_top_shell=>0,
-	 verilator_flags2 => [qw(-sp -Wno-WIDTH)],
+	 verilator_flags2 => [qw(-sc -Wno-WIDTH)],
 	 verilator_make_gcc=>0,
 	 );
 
diff --git a/test_regress/t/t_inst_overwide_bad.pl b/test_regress/t/t_inst_overwide_bad.pl
index 4a2e845..6e0b9ae 100755
--- a/test_regress/t/t_inst_overwide_bad.pl
+++ b/test_regress/t/t_inst_overwide_bad.pl
@@ -12,7 +12,7 @@ top_filename("t/t_inst_overwide.v");
 compile (
 	 v_flags2 => ["--lint-only"],
 	 make_top_shell=>0,
-	 verilator_flags=> [qw(-sp)],
+	 verilator_flags=> [qw(-cc)],
 	 verilator_make_gcc=>0,
 	 fails=>$Self->{v3},
 	 expect=>
diff --git a/test_regress/t/t_psl_basic_off.pl b/test_regress/t/t_interface_gen4.pl
similarity index 83%
rename from test_regress/t/t_psl_basic_off.pl
rename to test_regress/t/t_interface_gen4.pl
index ba70562..1118f2e 100755
--- a/test_regress/t/t_psl_basic_off.pl
+++ b/test_regress/t/t_interface_gen4.pl
@@ -7,15 +7,12 @@ 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.
 
-top_filename("t/t_psl_basic.v");
-
 compile (
-	 v_flags2 => [],
-	 );
+    );
 
 execute (
-	 check_finished=>1,
-	 );
+    check_finished=>1,
+    );
 
 ok(1);
 1;
diff --git a/test_regress/t/t_interface_gen4.v b/test_regress/t/t_interface_gen4.v
new file mode 100644
index 0000000..7678ac0
--- /dev/null
+++ b/test_regress/t/t_interface_gen4.v
@@ -0,0 +1,58 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2013 by Wilson Snyder.
+
+// bug789 generates
+
+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.i != 4) $stop;
+	 if (itopb.i != 5) $stop;
+	 $write("*-* All Finished *-*\n");
+	 $finish;
+      end
+   end
+endmodule
+
+module sub
+  #(parameter MODE = 0)
+   (
+    ifc isub,
+    input integer i_value
+   );
+
+   // Commercial unsupported Xmrs into scopes within interfaces
+   generate
+      always_comb isub.i = i_value;
+   endgenerate
+endmodule
+
+interface ifc;
+   parameter MODE = 0;
+   // Commercial unsupported Xmrs into scopes within interfaces
+   generate
+      integer 	  i;
+   endgenerate
+endinterface
diff --git a/test_regress/t/t_math_real.v b/test_regress/t/t_math_real.v
index dcb19a0..a72054b 100644
--- a/test_regress/t/t_math_real.v
+++ b/test_regress/t/t_math_real.v
@@ -24,6 +24,7 @@ module t (/*AUTOARG*/
    sub_cast_bug374 sub (.cyc5(cyc[4:0]), .*);
 
    initial begin
+      if (1_00_0.0_1 != 1000.01) $stop;
       // rtoi truncates
       if ($rtoi(36.7) != 36) $stop;
       if ($rtoi(36.5) != 36) $stop;
diff --git a/test_regress/t/t_mem_multidim_trace.pl b/test_regress/t/t_mem_multidim_trace.pl
index 05a9968..b8a0427 100755
--- a/test_regress/t/t_mem_multidim_trace.pl
+++ b/test_regress/t/t_mem_multidim_trace.pl
@@ -10,7 +10,7 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 top_filename("t/t_mem_multidim.v");
 
 compile (
-	 verilator_flags2 => ['--sp --trace'],
+	 verilator_flags2 => ['--cc --trace'],
 	 );
 
 execute (
diff --git a/test_regress/t/t_preproc_psl.v b/test_regress/t/t_preproc_psl.v
deleted file mode 100644
index c65b796..0000000
--- a/test_regress/t/t_preproc_psl.v
+++ /dev/null
@@ -1,72 +0,0 @@
-// DESCRIPTION: Verilator: Verilog Test module
-//
-//
-// This file ONLY is placed into the Public Domain, for any use,
-// without warranty, 2005 by Wilson Snyder.
-
-// verilator metacomment preserved
-/**/
-/*verilator metacomment also_preserved*/
-
-Hello in t_preproc_psl.v
-   // Psl capitalized not relevant
-   // Double commented ignored // psl not ok
-   // You can't have multiple statements on one // psl line.
-   // Inline /*cmt*/ comments not allowed inside psl comments
-
-   // psl default clock = (posedge clk);
-   // psl fails1: cover {cyc==10};
-   // psl assert always cyc!=10;
-   // psl assert always cyc==3 -> mask==8'h2;
-   // psl failsx: cover {cyc==3 && mask==8'h1};
-   /* psl fails2:
-        cover {
-	    cyc==3 && mask==8'h9};
-        // Ignore this comment-in-between-statements  (however not legal inside a statement)
-	fails3: always assert {
-	    cyc==3 && mask==8'h10 };
-    */
- `__LINE__
-
-   // Note the PSL statement can be on a unique line
-   // There can also be multiple "psl" keywords per line.
-   /*
-   psl
-      fails_ml:
-        assert always
-  	    cyc==3 -> mask==8'h21;
-    psl
-      fails_mlalso:  assert always cyc==3 -> mask==8'h21;
-    */
- `__LINE__
-
-   // psl assert never (cyc==1 && reset_l);
-
-   // psl fails3: assert always
-   //	    cyc==3 -> mask==8'h21;
-   //	syntax_error, not_part_of_above_stmt;
-
-// We need to count { and ( when looking for ; that terminate a PSL expression
-   // psl assert always
-   //       {[*]; cyc==3;
-   //        cyc==4; cyc==6};
-   //	syntax_error, not_part_of_above_stmt;
-
-// However /**/ pairs can't be split as above.
-
-`ifdef NEVER
-   // psl ifdefs have precedence;
-`endif
-
-// Macros are expanded...
-`define define_sig cyc
-   // psl assert always `define_sig!=10;
-
-`ifdef verilator
-  `psl
-psl assert always sig!=90;
-  `verilog
-`endif
-
-// Did we end up right?
-`__LINE__
diff --git a/test_regress/t/t_preproc_psl_off.out b/test_regress/t/t_preproc_psl_off.out
deleted file mode 100644
index fecd977..0000000
--- a/test_regress/t/t_preproc_psl_off.out
+++ /dev/null
@@ -1,99 +0,0 @@
-`line 1 "t/t_preproc_psl.v" 1
- 
-
-
-`line 4 "t/t_preproc_psl.v" 0
- 
- 
-
-`line 7 "t/t_preproc_psl.v" 0
-/*verilator metacomment preserved*/ 
- 
-/*verilator metacomment also_preserved*/ 
-
-`line 11 "t/t_preproc_psl.v" 0
-Hello in t_preproc_psl.v
-    
-    
-    
-    
-
-`line 17 "t/t_preproc_psl.v" 0
-    
-    
-    
-    
-    
-   
-
-`line 28 "t/t_preproc_psl.v" 0
-
-`line 28 "t/t_preproc_psl.v" 0
-
-`line 28 "t/t_preproc_psl.v" 0
-
-`line 28 "t/t_preproc_psl.v" 0
-
-`line 28 "t/t_preproc_psl.v" 0
- 
- 29
-
-`line 31 "t/t_preproc_psl.v" 0
-    
-    
-   
-
-`line 40 "t/t_preproc_psl.v" 0
-
-`line 40 "t/t_preproc_psl.v" 0
-
-`line 40 "t/t_preproc_psl.v" 0
-
-`line 40 "t/t_preproc_psl.v" 0
-
-`line 40 "t/t_preproc_psl.v" 0
-
-`line 40 "t/t_preproc_psl.v" 0
- 
- 41
-
-`line 43 "t/t_preproc_psl.v" 0
-    
-
-`line 45 "t/t_preproc_psl.v" 0
-    
-    
-    
-
-`line 49 "t/t_preproc_psl.v" 0
- 
-    
-    
-    
-    
-
-`line 55 "t/t_preproc_psl.v" 0
- 
-
-`line 57 "t/t_preproc_psl.v" 0
- 
-   
-
-
-`line 61 "t/t_preproc_psl.v" 0
- 
- 
-    
-
-`line 65 "t/t_preproc_psl.v" 0
- 
-  `psl
-psl assert always sig!=90;
-  `verilog
-
-
-`line 71 "t/t_preproc_psl.v" 0
- 
-72
-
-`line 74 "t/t_preproc_psl.v" 2
diff --git a/test_regress/t/t_preproc_psl_on.out b/test_regress/t/t_preproc_psl_on.out
deleted file mode 100644
index bf4bb1e..0000000
--- a/test_regress/t/t_preproc_psl_on.out
+++ /dev/null
@@ -1,88 +0,0 @@
-`line 1 "t/t_preproc_psl.v" 1
- 
-
-
-`line 4 "t/t_preproc_psl.v" 0
- 
- 
-
-`line 7 "t/t_preproc_psl.v" 0
-/*verilator metacomment preserved*/ 
- 
-/*verilator metacomment also_preserved*/ 
-
-`line 11 "t/t_preproc_psl.v" 0
-Hello in t_preproc_psl.v
-    
-    
-    
-    
-
-`line 17 "t/t_preproc_psl.v" 0
-    psl  default clock = (posedge clk);
-    psl  fails1: cover {cyc==10};
-    psl  assert always cyc!=10;
-    psl  assert always cyc==3 -> mask==8'h2;
-    psl  failsx: cover {cyc==3 && mask==8'h1};
-     psl  fails2:
-        cover {
-	    cyc==3 && mask==8'h9};
-         
-	fails3: always assert {
-	    cyc==3 && mask==8'h10 };
-     
- 29
-
-`line 31 "t/t_preproc_psl.v" 0
-    
-    
-   
-  psl 
-      fails_ml:
-        assert always
-  	    cyc==3 -> mask==8'h21;
-    psl
-      fails_mlalso:  assert always cyc==3 -> mask==8'h21;
-     
- 41
-
-`line 43 "t/t_preproc_psl.v" 0
-    psl  assert never (cyc==1 && reset_l);
-
-`line 45 "t/t_preproc_psl.v" 0
-    psl  fails3: assert always
-    psl 	    cyc==3 -> mask==8'h21;
-    
-
-`line 49 "t/t_preproc_psl.v" 0
- 
-    psl  assert always
-    psl        {[*]; cyc==3;
-    psl         cyc==4; cyc==6};
-    
-
-`line 55 "t/t_preproc_psl.v" 0
- 
-
-`line 57 "t/t_preproc_psl.v" 0
- 
-      
-
-
-`line 61 "t/t_preproc_psl.v" 0
- 
- 
-    psl  assert always cyc!=10;
-
-`line 65 "t/t_preproc_psl.v" 0
- 
-  `psl
-psl assert always sig!=90;
-  `verilog
-
-
-`line 71 "t/t_preproc_psl.v" 0
- 
-72
-
-`line 74 "t/t_preproc_psl.v" 2
diff --git a/test_regress/t/t_psl_basic.v b/test_regress/t/t_psl_basic.v
deleted file mode 100644
index 8fe62c1..0000000
--- a/test_regress/t/t_psl_basic.v
+++ /dev/null
@@ -1,54 +0,0 @@
-// DESCRIPTION: Verilator: Verilog Test module
-//
-// This file ONLY is placed into the Public Domain, for any use,
-// without warranty, 2005 by Wilson Snyder.
-
-module t (/*AUTOARG*/
-   // Inputs
-   clk
-   );
-
-   input clk;
-
-   reg 	 toggle;
-
-   integer cyc; initial cyc=1;
-   wire [7:0] cyc_copy = cyc[7:0];
-
-   // psl cover  {cyc==3 || cyc==4} @ (posedge clk);
-   // psl assert {cyc<100} @ (posedge clk) report "AssertionFalse1";
-`ifdef FAILING_ASSERTIONS
-   // psl assert {toggle} @ (posedge clk) report "AssertionShouldFail";
-`endif
-
-   // psl default clock = negedge clk;
-//FIX   // psl assert always {cyc<99};
-   // psl cover {cyc==9} report "DefaultClock,expect=1";
-
-   // psl assert {(cyc==5)->toggle};
-   // psl cover  {(cyc==5)->toggle} report "ToggleLogIf,expect=1";
-`ifdef NOT_SUP
-   // psl assert {toggle<->cyc[0]};
-   // psl cover  {toggle<->cyc[0]} report "CycsLogIff,expect=10";
-`endif
-   
-   // Test {{..}} == Sequence of sequence...
-   // psl assert {{true}};
-
-   always @ (negedge clk) begin
-      //if (!(cyc==5) || toggle) $write("%d: %s\n", cyc, "ToggleLogIf,expect=1");
-      //if (toggle&&cyc[0] || ~toggle&&~cyc[0]) $write("%d: %s\n", cyc, "CycsLogIff,expect=10");
-   end
-
-   always @ (posedge clk) begin
-      if (cyc!=0) begin
-	 cyc <= cyc + 1;
-	 toggle <= !cyc[0];
-	 if (cyc==10) begin
-	    $write("*-* All Finished *-*\n");
-	    $finish;
-	 end
-      end
-   end
-
-endmodule
diff --git a/test_regress/t/t_psl_basic_cover.pl b/test_regress/t/t_psl_basic_cover.pl
deleted file mode 100755
index 700c381..0000000
--- a/test_regress/t/t_psl_basic_cover.pl
+++ /dev/null
@@ -1,26 +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.
-
-top_filename("t/t_psl_basic.v");
-
-compile (
-	 verilator_flags2 => ['--psl-deprecated --sp --coverage-user'],
-	 );
-
-execute (
-	 check_finished=>1,
-	 );
-
-# Allow old Perl format dump, or new binary dump
-file_grep ($Self->{coverage_filename}, qr/(,o=>'cover'.*,c=>2\)|o.cover.* 2\n)/);
-file_grep ($Self->{coverage_filename}, qr/(DefaultClock.*,c=>1\)|DefaultClock.* 1\n)/);
-file_grep ($Self->{coverage_filename}, qr/(ToggleLogIf.*,c=>9\)|ToggleLogIf.* 9\n)/);
-
-ok(1);
-1;
diff --git a/test_regress/t/t_savable.v b/test_regress/t/t_savable.v
index 4df08d2..a98c687 100644
--- a/test_regress/t/t_savable.v
+++ b/test_regress/t/t_savable.v
@@ -73,6 +73,7 @@ module sub (/*AUTOARG*/
 	 if (vec[2][1] !== 32'h0201) $stop;
 	 if (vec[2][2] !== 32'h0202) $stop;
 	 if (r != 1.234) $stop;
+	 $display("%s",s); 
 	 $write("*-* All Finished *-*\n");
 	 $finish;
       end
diff --git a/test_regress/t/t_sv_enum_type_methods.pl b/test_regress/t/t_string.pl
similarity index 83%
copy from test_regress/t/t_sv_enum_type_methods.pl
copy to test_regress/t/t_string.pl
index fda118f..f912897 100755
--- a/test_regress/t/t_sv_enum_type_methods.pl
+++ b/test_regress/t/t_string.pl
@@ -7,9 +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.
 
-# Not yet working on Verilator
-$Self->{vlt} and $Self->unsupported("Verilator unsupported");
-
 compile (
     );
 
diff --git a/test_regress/t/t_string.v b/test_regress/t/t_string.v
new file mode 100644
index 0000000..3310728
--- /dev/null
+++ b/test_regress/t/t_string.v
@@ -0,0 +1,91 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Wilson Snyder.
+
+`define checkh(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d:  got='h%x exp='h%x\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
+`define checks(gotv,expv) do if ((gotv) !== (expv)) begin $write("%%Error: %s:%0d:  got=\"%s\" exp=\"%s\"\n", `__FILE__,`__LINE__, (gotv), (expv)); $stop; end while(0);
+
+module t (/*AUTOARG*/
+   // Inputs
+   clk
+   );
+   input clk;
+
+   integer 	cyc=0;
+
+   reg [4*8:1] 	vstr;
+   const string s = "a";  // Check static assignment
+   string 	s2;
+   string 	s3;
+   reg		eq;
+
+   // Operators == != < <= > >=  {a,b}  {a{b}}  a[b]
+   // a.len, a.putc, a.getc, a.toupper, a.tolower, a.compare, a.icompare, a.substr
+   // a.atoi, a.atohex, a.atooct, a.atobin, a.atoreal,
+   // a.itoa, a.hextoa, a.octoa, a.bintoa, a.realtoa
+
+   initial begin
+      $sformat(vstr, "s=%s", s);
+      `checks(vstr, "s=a");
+      `checks(s, "a");
+      `checks({s,s,s}, "aaa");
+      `checks({4{s}}, "aaaa");
+      // Constification
+      `checkh(s == "a", 1'b1);
+      `checkh(s == "b", 1'b0);
+      `checkh(s != "a", 1'b0);
+      `checkh(s != "b", 1'b1);
+      `checkh(s >  " ", 1'b1);
+      `checkh(s >  "a", 1'b0);
+      `checkh(s >= "a", 1'b1);
+      `checkh(s >= "b", 1'b0);
+      `checkh(s <  "a", 1'b0);
+      `checkh(s <  "b", 1'b1);
+      `checkh(s <= " ", 1'b0);
+      `checkh(s <= "a", 1'b1);
+   end
+
+   // Test loop
+   always @ (posedge clk) begin
+      cyc <= cyc + 1;
+      if (cyc==0) begin
+	 // Setup
+	 s2 = "c0";
+      end
+      else if (cyc==1) begin
+	 $sformat(vstr, "s2%s", s2);
+	 `checks(vstr, "s2c0");
+      end
+      else if (cyc==2) begin
+	 s3 = s2;
+	 $sformat(vstr, "s2%s", s3);
+	 `checks(vstr, "s2c0");
+      end
+      else if (cyc==3) begin
+	 s2 = "a";
+	 s3 = "b";
+      end
+      else if (cyc==4) begin
+	 `checks({s2,s3}, "ab");
+	 `checks({3{s3}}, "bbb");
+	 `checkh(s == "a", 1'b1);
+	 `checkh(s == "b", 1'b0);
+	 `checkh(s != "a", 1'b0);
+	 `checkh(s != "b", 1'b1);
+	 `checkh(s >  " ", 1'b1);
+	 `checkh(s >  "a", 1'b0);
+	 `checkh(s >= "a", 1'b1);
+	 `checkh(s >= "b", 1'b0);
+	 `checkh(s <  "a", 1'b0);
+	 `checkh(s <  "b", 1'b1);
+	 `checkh(s <= " ", 1'b0);
+	 `checkh(s <= "a", 1'b1);
+      end
+      else if (cyc==99) begin
+	 $write("*-* All Finished *-*\n");
+	 $finish;
+      end
+   end
+
+endmodule
diff --git a/test_regress/t/t_sys_sformat.v b/test_regress/t/t_sys_sformat.v
index e2ce550..fbda9b9 100644
--- a/test_regress/t/t_sys_sformat.v
+++ b/test_regress/t/t_sys_sformat.v
@@ -13,6 +13,7 @@ module t;
    reg [63:0] q;
    reg [16*8:1] wide;
 
+   reg [8:1] 	char;
    reg [48*8:1] str;
    reg [48*8:1] str2;
 
@@ -48,6 +49,9 @@ module t;
       if (str2 !== "mod=top.t") $stop;
 `endif
 
+      $sformat(char,"%s","c");
+      if (char != "c") $stop;
+
       $write("*-* All Finished *-*\n");
       $finish;
    end
diff --git a/test_regress/t/t_trace_ena_sp.pl b/test_regress/t/t_trace_ena_sp.pl
deleted file mode 100755
index 3ff0118..0000000
--- a/test_regress/t/t_trace_ena_sp.pl
+++ /dev/null
@@ -1,26 +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.
-
-top_filename("t/t_trace_ena.v");
-
-compile (
-	 verilator_flags2 => ['-trace -sp'],
-	 );
-
-execute (
-	 check_finished=>1,
-	 );
-
-if ($Self->{vlt}) {
-    # Note more checks in _cc.pl
-    file_grep     ("$Self->{obj_dir}/simx.vcd", qr/\$enddefinitions/x);
-}
-
-ok(1);
-1;
diff --git a/test_regress/t/t_trace_off_sp.pl b/test_regress/t/t_trace_off_sp.pl
deleted file mode 100755
index 91b03c8..0000000
--- a/test_regress/t/t_trace_off_sp.pl
+++ /dev/null
@@ -1,25 +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.
-
-top_filename("t/t_trace_ena.v");
-
-compile (
-	 verilator_flags2 => ['-notrace -sp'],
-	 );
-
-execute (
-	 check_finished=>1,
-	 );
-
-if ($Self->{vlt}) {
-    !-r "$Self->{obj_dir}/simx.vcd" or $Self->error("Tracing should be off\n");
-}
-
-ok(1);
-1;
diff --git a/test_regress/t/t_psl_basic.pl b/test_regress/t/t_trace_scstruct.pl
similarity index 77%
rename from test_regress/t/t_psl_basic.pl
rename to test_regress/t/t_trace_scstruct.pl
index 21301e5..9c08b40 100755
--- a/test_regress/t/t_psl_basic.pl
+++ b/test_regress/t/t_trace_scstruct.pl
@@ -8,12 +8,10 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 # Version 2.0.
 
 compile (
-	 v_flags2 => [$Self->{v3}?'--assert --psl-deprecated':($Self->{nc}?'+assert':'')],
-	 );
+    verilator_flags2 => ['--sc --trace --trace-structs --pins-bv 2'],
+    );
 
-execute (
-	 check_finished=>1,
-	 );
+#execute ();  # didn't bother with top shell
 
 ok(1);
 1;
diff --git a/test_regress/t/t_trace_scstruct.v b/test_regress/t/t_trace_scstruct.v
new file mode 100644
index 0000000..0993f0f
--- /dev/null
+++ b/test_regress/t/t_trace_scstruct.v
@@ -0,0 +1,26 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Wilson Snyder.
+
+// verilator lint_off UNUSED
+// verilator lint_off UNDRIVEN
+
+//bug858
+
+typedef struct packed {
+    logic m_1;
+    logic m_2;
+} struct_t;
+
+typedef struct packed {
+    logic [94:0] m_1;
+    logic m_2;
+} struct96_t;
+
+module t
+  (
+   input struct_t   test_input,
+   input struct96_t t96
+   );
+endmodule
diff --git a/test_regress/t/t_var_pins_sc1.pl b/test_regress/t/t_var_pins_sc1.pl
index 871ad5e..cd42fa7 100755
--- a/test_regress/t/t_var_pins_sc1.pl
+++ b/test_regress/t/t_var_pins_sc1.pl
@@ -12,28 +12,28 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp -pins-bv 1 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc -pins-bv 1 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<8>\s> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<32>\s> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<8>\s> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<32>\s> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<8>\s> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<32>\s> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<8>\s> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<32>\s> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc2.pl b/test_regress/t/t_var_pins_sc2.pl
index eb03cbc..9846c71 100755
--- a/test_regress/t/t_var_pins_sc2.pl
+++ b/test_regress/t/t_var_pins_sc2.pl
@@ -12,28 +12,28 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp -pins-bv 2 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc -pins-bv 2 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<8>\s> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<32>\s> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<8>\s> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<32>\s> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<8>\s> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<32>\s> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<8>\s> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<32>\s> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc32.pl b/test_regress/t/t_var_pins_sc32.pl
index 329ff94..92976f4 100755
--- a/test_regress/t/t_var_pins_sc32.pl
+++ b/test_regress/t/t_var_pins_sc32.pl
@@ -12,28 +12,28 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp -no-pins64 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc -no-pins64 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<64>\s> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<64>\s> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc64.pl b/test_regress/t/t_var_pins_sc64.pl
index 896b740..f5d06e7 100755
--- a/test_regress/t/t_var_pins_sc64.pl
+++ b/test_regress/t/t_var_pins_sc64.pl
@@ -12,28 +12,28 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp -pins64 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc -pins64 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<vluint64_t> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<vluint64_t> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<vluint64_t> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<vluint64_t> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc_biguint.pl b/test_regress/t/t_var_pins_sc_biguint.pl
index 9a4584b..439abd8 100755
--- a/test_regress/t/t_var_pins_sc_biguint.pl
+++ b/test_regress/t/t_var_pins_sc_biguint.pl
@@ -12,32 +12,32 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp --pins-sc-biguint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc --pins-sc-biguint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<vluint64_t> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_biguint<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_biguint<128>\s> \s+ i128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<vluint64_t> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_biguint<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_biguint<128>\s> \s+ i128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<vluint64_t> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_biguint<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_biguint<128>\s> \s+ o128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<vluint64_t> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_biguint<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_biguint<128>\s> \s+ o128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc_uint.pl b/test_regress/t/t_var_pins_sc_uint.pl
index 3d1bedd..9c81467 100755
--- a/test_regress/t/t_var_pins_sc_uint.pl
+++ b/test_regress/t/t_var_pins_sc_uint.pl
@@ -12,32 +12,32 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp --pins-sc-uint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc --pins-sc-uint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<8>\s> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<16>\s> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<32>\s> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<64>\s> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<128>\s> \s+ i128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<8>\s> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<16>\s> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<32>\s> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<64>\s> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<128>\s> \s+ i128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<8>\s> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<16>\s> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<32>\s> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<64>\s> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<128>\s> \s+ o128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<8>\s> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<16>\s> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<32>\s> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<64>\s> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<128>\s> \s+ o128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_sc_uint_biguint.pl b/test_regress/t/t_var_pins_sc_uint_biguint.pl
index 9bc5234..258f3ba 100755
--- a/test_regress/t/t_var_pins_sc_uint_biguint.pl
+++ b/test_regress/t/t_var_pins_sc_uint_biguint.pl
@@ -12,32 +12,32 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp --pins-sc-uint --pins-sc-biguint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc --pins-sc-uint --pins-sc-biguint --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<8>\s> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<16>\s> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<32>\s> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_uint<64>\s> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_biguint<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_biguint<128>\s> \s+ i128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<8>\s> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<16>\s> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<32>\s> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_uint<64>\s> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_biguint<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_biguint<128>\s> \s+ i128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<513>\s> \s+ i513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<8>\s> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<16>\s> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<32>\s> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_uint<64>\s> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_biguint<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_biguint<128>\s> \s+ o128;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<8>\s> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<16>\s> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<32>\s> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_uint<64>\s> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_biguint<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_biguint<128>\s> \s+ o128;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<513>\s> \s+ o513;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_var_pins_scui.pl b/test_regress/t/t_var_pins_scui.pl
index 5c2fddf..3c54085 100755
--- a/test_regress/t/t_var_pins_scui.pl
+++ b/test_regress/t/t_var_pins_scui.pl
@@ -12,28 +12,28 @@ $Self->{vlt} or $Self->skip("Verilator only test");
 top_filename("t/t_var_pinsizes.v");
 
 compile (
-	 verilator_flags2 => ["-sp -pins-uint8 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
+	 verilator_flags2 => ["-sc -pins-uint8 --trace --exe $Self->{t_dir}/t_var_pinsizes.cpp"],
 	 make_main => 0,
 	 );
 
 if ($Self->{vlt}) {
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<bool> \s+ i1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint8_t> \s+ i8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint16_t> \s+ i16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<uint32_t> \s+ i32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<vluint64_t> \s+ i64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<bool> \s+ i1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint8_t> \s+ i8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint16_t> \s+ i16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<uint32_t> \s+ i32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<vluint64_t> \s+ i64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<65>\s> \s+ i65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<1>\s> \s+ ibv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_in<sc_bv<16>\s> \s+ ibv16;/x);
 
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<bool> \s+ o1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint8_t> \s+ o8;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint16_t> \s+ o16;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<uint32_t> \s+ o32;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<vluint64_t> \s+ o64;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
-    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.sp", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<bool> \s+ o1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint8_t> \s+ o8;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint16_t> \s+ o16;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<uint32_t> \s+ o32;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<vluint64_t> \s+ o64;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<65>\s> \s+ o65;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<1>\s> \s+ obv1;/x);
+    file_grep ("$Self->{obj_dir}/$Self->{VM_PREFIX}.h", qr/sc_out<sc_bv<16>\s> \s+ obv16;/x);
 }
 
 execute();
diff --git a/test_regress/t/t_sv_enum_type_methods.pl b/test_regress/t/t_var_static.pl
similarity index 83%
rename from test_regress/t/t_sv_enum_type_methods.pl
rename to test_regress/t/t_var_static.pl
index fda118f..823ae5c 100755
--- a/test_regress/t/t_sv_enum_type_methods.pl
+++ b/test_regress/t/t_var_static.pl
@@ -7,8 +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.
 
-# Not yet working on Verilator
-$Self->{vlt} and $Self->unsupported("Verilator unsupported");
+$Self->{vlt} and $Self->unsupported("Verilator unsupported, bug546");
 
 compile (
     );
diff --git a/test_regress/t/t_var_static.v b/test_regress/t/t_var_static.v
new file mode 100644
index 0000000..2e38c75
--- /dev/null
+++ b/test_regress/t/t_var_static.v
@@ -0,0 +1,69 @@
+// DESCRIPTION: Verilator: Verilog Test module
+//
+// This file ONLY is placed into the Public Domain, for any use,
+// without warranty, 2014 by Wilson Snyder.
+
+module t (/*AUTOARG*/
+   // Inputs
+   clk
+   );
+
+   input clk;
+
+   function int f_no_no ();
+      int st = 2; st++; return st;
+   endfunction
+   function int f_no_st ();
+      static int st = 2; st++; return st;
+   endfunction
+   function int f_no_au ();
+      automatic int st = 2; st++; return st;
+   endfunction
+   
+   function static int f_st_no ();
+      int st = 2; st++; return st;
+   endfunction
+   function static int f_st_st ();
+      static int st = 2; st++; return st;
+   endfunction
+   function static int f_st_au ();
+      automatic int st = 2; st++; return st;
+   endfunction
+
+   function automatic int f_au_no ();
+      int st = 2; st++; return st;
+   endfunction
+   function automatic int f_au_st ();
+      static int st = 2; st++; return st;
+   endfunction
+   function automatic int f_au_au ();
+      automatic int st = 2; st++; return st;
+   endfunction
+ 
+   initial begin
+      if (f_no_no() != 3) $stop;
+      if (f_no_no() !=   4) $stop;
+      if (f_no_st() != 3) $stop;
+      if (f_no_st() !=   4) $stop;
+      if (f_no_au() != 3) $stop;
+      if (f_no_au() !=   3) $stop;
+      //
+      if (f_st_no() != 3) $stop;
+      if (f_st_no() !=   4) $stop;
+      if (f_st_st() != 3) $stop;
+      if (f_st_st() !=   4) $stop;
+      if (f_st_au() != 3) $stop;
+      if (f_st_au() !=   3) $stop;
+      //
+      if (f_au_no() != 3) $stop;
+      if (f_au_no() !=   3) $stop;
+      if (f_au_st() != 3) $stop;
+      if (f_au_st() !=   4) $stop;
+      if (f_au_au() != 3) $stop;
+      if (f_au_au() !=   3) $stop;
+      //
+      $write("*-* All Finished *-*\n");
+      $finish;
+   end
+
+endmodule
diff --git a/test_regress/t/t_vlcov_data_a.dat b/test_regress/t/t_vlcov_data_a.dat
new file mode 100644
index 0000000..5acd5df
--- /dev/null
+++ b/test_regress/t/t_vlcov_data_a.dat
@@ -0,0 +1,5 @@
+# SystemC::Coverage-3
+C 'CoverPoint0ffile1.sphl159' 0
+C 'CoverPoint1ffile1.sphl159' 1
+C 'CoverPoint2ffile1.sphl159' 10
+C 'CoverPoint3ffile1.sphl159' 0
diff --git a/test_regress/t/t_vlcov_data_b.dat b/test_regress/t/t_vlcov_data_b.dat
new file mode 100644
index 0000000..d06b129
--- /dev/null
+++ b/test_regress/t/t_vlcov_data_b.dat
@@ -0,0 +1,5 @@
+# SystemC::Coverage-3
+C 'CoverPoint2ffile1.sphl159' 10
+C 'CoverPoint3ffile1.sphl159' 0
+C 'CoverPoint4ffile1.sphl159' 1
+C 'CoverPoint5ffile1.sphl159' 9
diff --git a/test_regress/t/t_vlcov_data_c.dat b/test_regress/t/t_vlcov_data_c.dat
new file mode 100644
index 0000000..73f5bb1
--- /dev/null
+++ b/test_regress/t/t_vlcov_data_c.dat
@@ -0,0 +1,2 @@
+# SystemC::Coverage-3
+C 'CoverPoint6ffile1.sphl159' 10
diff --git a/test_regress/t/t_vlcov_data_d.dat b/test_regress/t/t_vlcov_data_d.dat
new file mode 100644
index 0000000..d9e06d0
--- /dev/null
+++ b/test_regress/t/t_vlcov_data_d.dat
@@ -0,0 +1,2 @@
+# SystemC::Coverage-3
+C 'CoverPoint6ffile1.sphl159' 12
diff --git a/test_regress/t/t_vlcov_merge.out b/test_regress/t/t_vlcov_merge.out
new file mode 100644
index 0000000..7ac2cab
--- /dev/null
+++ b/test_regress/t/t_vlcov_merge.out
@@ -0,0 +1,8 @@
+# SystemC::Coverage-3
+C 'CoverPoint0ffile1.sphl159' 0
+C 'CoverPoint1ffile1.sphl159' 1
+C 'CoverPoint2ffile1.sphl159' 20
+C 'CoverPoint3ffile1.sphl159' 0
+C 'CoverPoint4ffile1.sphl159' 1
+C 'CoverPoint5ffile1.sphl159' 9
+C 'CoverPoint6ffile1.sphl159' 22
diff --git a/test_regress/t/t_preproc_psl_off.pl b/test_regress/t/t_vlcov_merge.pl
similarity index 61%
copy from test_regress/t/t_preproc_psl_off.pl
copy to test_regress/t/t_vlcov_merge.pl
index 0bea790..e7143ab 100755
--- a/test_regress/t/t_preproc_psl_off.pl
+++ b/test_regress/t/t_vlcov_merge.pl
@@ -9,16 +9,13 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 $Self->{vlt} or $Self->skip("Verilator only test");
 
-my $stdout_filename = "$Self->{obj_dir}/$Self->{name}__test.vpp";
-
-top_filename("t/t_preproc_psl.v");
-
-compile (
-    verilator_flags2 => ['-E'],
-    verilator_make_gcc=>0,
-    stdout_filename => $stdout_filename,
+$Self->_run(cmd=>["../bin/verilator_coverage",
+		  "--write", "$Self->{obj_dir}/coverage.dat",
+		  "t/t_vlcov_data_a.dat",
+		  "t/t_vlcov_data_b.dat",
+		  "t/t_vlcov_data_c.dat",
+		  "t/t_vlcov_data_d.dat",
+	    ],
     );
-
-ok(files_identical($stdout_filename, "t/$Self->{name}.out"));
-
+ok(files_identical("$Self->{obj_dir}/coverage.dat", "t/$Self->{name}.out"));
 1;
diff --git a/test_regress/t/t_vlcov_rank.out b/test_regress/t/t_vlcov_rank.out
new file mode 100644
index 0000000..4439fcb
--- /dev/null
+++ b/test_regress/t/t_vlcov_rank.out
@@ -0,0 +1,6 @@
+Tests:
+  Covered,     Rank,  RankPts,  Filename
+        2,        2,        1,  "t/t_vlcov_data_a.dat"
+        3,        1,        3,  "t/t_vlcov_data_b.dat"
+        1,        3,        1,  "t/t_vlcov_data_c.dat"
+        1,        0,        0,  "t/t_vlcov_data_d.dat"
diff --git a/test_regress/t/t_preproc_psl_on.pl b/test_regress/t/t_vlcov_rank.pl
similarity index 59%
rename from test_regress/t/t_preproc_psl_on.pl
rename to test_regress/t/t_vlcov_rank.pl
index fd818a9..febe59c 100755
--- a/test_regress/t/t_preproc_psl_on.pl
+++ b/test_regress/t/t_vlcov_rank.pl
@@ -9,16 +9,15 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 $Self->{vlt} or $Self->skip("Verilator only test");
 
-my $stdout_filename = "$Self->{obj_dir}/$Self->{name}__test.vpp";
-
-top_filename("t/t_preproc_psl.v");
-
-compile (
-    verilator_flags2 => ['-psl-deprecated -E'],
-    verilator_make_gcc=>0,
-    stdout_filename => $stdout_filename,
+$Self->_run(cmd=>["../bin/verilator_coverage",
+		  "--rank",
+		  "t/t_vlcov_data_a.dat",
+		  "t/t_vlcov_data_b.dat",
+		  "t/t_vlcov_data_c.dat",
+		  "t/t_vlcov_data_d.dat",
+	    ],
+	    logfile=>"$Self->{obj_dir}/vlcov.log",
+	    tee => 0,
     );
-
-ok(files_identical($stdout_filename, "t/$Self->{name}.out"));
-
+ok(files_identical("$Self->{obj_dir}/vlcov.log", "t/$Self->{name}.out"));
 1;
diff --git a/test_regress/t/t_preproc_psl_off.pl b/test_regress/t/t_vlcov_rewrite.pl
similarity index 55%
rename from test_regress/t/t_preproc_psl_off.pl
rename to test_regress/t/t_vlcov_rewrite.pl
index 0bea790..c538a94 100755
--- a/test_regress/t/t_preproc_psl_off.pl
+++ b/test_regress/t/t_vlcov_rewrite.pl
@@ -9,16 +9,17 @@ if (!$::Driver) { use FindBin; exec("$FindBin::Bin/bootstrap.pl", @ARGV, $0); di
 
 $Self->{vlt} or $Self->skip("Verilator only test");
 
-my $stdout_filename = "$Self->{obj_dir}/$Self->{name}__test.vpp";
-
-top_filename("t/t_preproc_psl.v");
-
-compile (
-    verilator_flags2 => ['-E'],
-    verilator_make_gcc=>0,
-    stdout_filename => $stdout_filename,
-    );
-
-ok(files_identical($stdout_filename, "t/$Self->{name}.out"));
-
+foreach my $basename ("t_vlcov_data_a.dat",
+		      "t_vlcov_data_b.dat",
+		      "t_vlcov_data_c.dat",
+		      "t_vlcov_data_d.dat",
+    ) {
+    $Self->_run(cmd=>["../bin/verilator_coverage",
+		      "t/${basename}",
+		      "--write", "$Self->{obj_dir}/${basename}"
+		],
+		tee=>0,
+	);
+    ok(files_identical("$Self->{obj_dir}/${basename}", "t/${basename}"));
+}
 1;
diff --git a/test_sc/Makefile b/test_sc/Makefile
index 60a850b..e97196c 100644
--- a/test_sc/Makefile
+++ b/test_sc/Makefile
@@ -26,8 +26,8 @@ SYSTEMC_TESTING ?= $(SYSTEMC)$(SYSTEMC_INCLUDE)
 
 ######################################################################
 ifneq ($(SYSTEMC_TESTING),)
-test_default:  precopy prep        preproc compile run
-test_debug:    precopy prep_dbg    preproc compile run
+test_default:  precopy prep        compile run
+test_debug:    precopy prep_dbg    compile run
 else
 test_default:  nosc
 test_debug:    nosc
@@ -44,9 +44,6 @@ prep:
 prep_dbg:
 	$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
 
-preproc:
-	cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
-
 compile:
 	cd obj_dir ; $(MAKE) -j 3 -f ../Makefile_obj
 
diff --git a/test_sc/sc_main.cpp b/test_sc/sc_main.cpp
index ba6be6a..d878152 100644
--- a/test_sc/sc_main.cpp
+++ b/test_sc/sc_main.cpp
@@ -12,15 +12,8 @@
 #include <sys/times.h>
 #include <sys/stat.h>
 
-#ifdef SYSTEMPERL
-# include "systemperl.h"	// SystemC + SystemPerl global header
-# include "sp_log.h"		// Logging cout to files
-# include "SpTraceVcd.h"
-# include "SpCoverage.h"
-#else
-# include "systemc.h"		// SystemC global header
-# include "verilated_vcd_sc.h"	// Tracing
-#endif
+#include "systemc.h"		// SystemC global header
+#include "verilated_vcd_sc.h"	// Tracing
 
 #include "Vtop.h"		// Top level header, generated from verilog
 
@@ -33,10 +26,6 @@ int sc_main(int argc, char* argv[]) {
 
     // General logfile
     ios::sync_with_stdio();
-#ifdef SYSTEMPERL
-    sp_log_file simlog ("sim.log");
-    simlog.redirect_cout();
-#endif
 
     // Defaults
 #if (SYSTEMC_VERSION>20011000)
@@ -70,19 +59,6 @@ int sc_main(int argc, char* argv[]) {
     //==========
     // Part under test
 
-#ifdef SYSTEMPERL
-    SP_CELL (top, Vtop);
-    SP_PIN (top, clk,		clk);
-    SP_PIN (top, fastclk,	fastclk);
-    SP_PIN (top, reset_l,	reset_l);
-    SP_PIN (top, passed,	passed);
-    SP_PIN (top, in_small,	in_small);
-    SP_PIN (top, in_quad,	in_quad);
-    SP_PIN (top, in_wide,	in_wide);
-    SP_PIN (top, out_small,	out_small);
-    SP_PIN (top, out_quad,	out_quad);
-    SP_PIN (top, out_wide,	out_wide);
-#else
     Vtop* top = new Vtop("top");
     top->clk		(clk);
     top->fastclk	(fastclk);
@@ -94,7 +70,6 @@ int sc_main(int argc, char* argv[]) {
     top->out_small	(out_small);
     top->out_quad	(out_quad);
     top->out_wide	(out_wide);
-#endif
 
     //==========
     //  Waves
@@ -119,11 +94,7 @@ int sc_main(int argc, char* argv[]) {
 
 #if VM_TRACE
     cout << "Enabling waves...\n";
-# ifdef SYSTEMPERL
-    SpTraceFile* tfp = new SpTraceFile;
-# else
     VerilatedVcdSc* tfp = new VerilatedVcdSc;
-# endif
     top->trace (tfp, 99);
     tfp->open ("vlt_dump.vcd");
 #endif
@@ -134,10 +105,10 @@ int sc_main(int argc, char* argv[]) {
     cout <<("Test beginning...\n");
 
     reset_l = 1;
-    while (VL_TIME_Q() < 60 && !passed && !Verilated::gotFinish()) {
+    while (VL_TIME_Q() < 60 && !Verilated::gotFinish()) {
 #if VM_TRACE
 	// Flush the wave files each cycle so we can immediately see the output
-	// Don't do this in "real" programs, do it in a abort() handler instead
+	// Don't do this in "real" programs, do it in an abort() handler instead
 	if (tfp) tfp->flush();
 #endif
 	if (VL_TIME_Q() > 10) {
diff --git a/test_sp/.gitignore b/test_sp/.gitignore
deleted file mode 100644
index b491e81..0000000
--- a/test_sp/.gitignore
+++ /dev/null
@@ -1,8 +0,0 @@
-*.old
-*.dmp
-*.log
-*.csrc
-*.vcd
-obj_*
-logs
-project
diff --git a/test_sp/Makefile b/test_sp/Makefile
deleted file mode 100644
index 78dbffb..0000000
--- a/test_sp/Makefile
+++ /dev/null
@@ -1,86 +0,0 @@
-#*****************************************************************************
-#
-# DESCRIPTION: Verilator Example: Makefile for inside source directory
-#
-# This calls the object directory makefile.  That allows the objects to
-# be placed in the "current directory" which simplifies the Makefile.
-#
-# Copyright 2003-2014 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.
-#
-#****************************************************************************/
-
-default: test_default
-
-# This must point to the root of the VERILATOR kit
-VERILATOR_ROOT := $(shell pwd)/..
-export VERILATOR_ROOT
-
-# Pick up PERL and other variable settings
-include $(VERILATOR_ROOT)/include/verilated.mk
-
-DEBUG_ON = --debug --trace-dups
-
-######################################################################
-ifneq ($(SYSTEMPERL),)
-test_default:  precopy prep        preproc compile     run coverage
-test_debug:    precopy prep_dbg    preproc compile_dbg run coverage
-test_nopublic: precopy prep_dbg_np preproc compile_dbg run coverage
-else
-test_default:  nosp
-test_debug:    nosp
-test_nopublic: nosp
-endif
-
-V_FLAGS = -f $(VERILATOR_ROOT)/test_v/input.vc
-
-# Note the --public --output-split-cfunc is here for testing only,
-# Avoid using these settings in real application Makefiles!
-VERILATOR_FLAGS = --public --output-split-cfuncs 1000 --output-split 1000 \
-	--sp --coverage --stats --trace $(V_FLAGS) top.v
-
-precopy: obj_dir obj_dir/sc_main.cpp
-obj_dir/sc_main.cpp: ../test_sc/sc_main.cpp
-	mkdir -p obj_dir
-	cp $^ $@
-
-prep:
-	$(PERL) $(VERILATOR_ROOT)/bin/verilator             $(VERILATOR_FLAGS)
-prep_dbg:
-	$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS)
-prep_dbg_np:
-	$(PERL) $(VERILATOR_ROOT)/bin/verilator $(DEBUG_ON) $(VERILATOR_FLAGS) --nopublic
-
-preproc:
-	cd obj_dir ; $(MAKE) -j 1 -f ../Makefile_obj preproc
-
-compile:
-	cd obj_dir ; $(MAKE)        -j 3 -f ../Makefile_obj
-
-compile_dbg:
-	cd obj_dir ; $(MAKE) OPT=-g -j 3 -f ../Makefile_obj
-
-run:
-	obj_dir/simx
-
-coverage:
-	vcoverage $(V_FLAGS)
-
-######################################################################
-
-obj_dir:
-	mkdir $@
-
-nosp:
-	@echo
-	@echo %Skip: SYSTEMPERL not in environment
-	@echo
-
-######################################################################
-
-maintainer-copy::
-clean mostlyclean distclean maintainer-clean::
-	-rm -rf obj_dir *.log *.dmp *.vpd *.vcd core logs
-
diff --git a/test_sp/Makefile_obj b/test_sp/Makefile_obj
deleted file mode 100644
index 9386bb5..0000000
--- a/test_sp/Makefile_obj
+++ /dev/null
@@ -1,37 +0,0 @@
-# -*- Makefile -*-
-#*****************************************************************************
-#
-# DESCRIPTION: Verilator Example: Makefile for inside object directory
-#
-# This is executed in the object directory, and called by ../Makefile
-#
-# Copyright 2003-2014 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.
-#
-#*****************************************************************************
-
-default: simx
-include Vtop.mk
-
-#######################################################################
-# Use sp_log.cpp, so we can get output in sim.log
-
-CPPFLAGS += -DUTIL_PRINTF=sp_log_printf
-CPPFLAGS += -Wno-deprecated
-CPPFLAGS += $(SYSTEMC_CXX_FLAGS)
-CPPFLAGS += $(OPT)
-
-LDFLAGS += $(SYSTEMC_CXX_FLAGS)
-
-#######################################################################
-# Linking final exe -- presumes have a sim_main.cpp
-
-SC_LIB = $(SYSTEMC_LIBDIR)/libsystemc.a
-
-simx: sc_main.o $(VK_GLOBAL_OBJS) \
-	  $(VM_PREFIX)__ALL.a $(SC_LIB)
-	$(LINK) $(LDFLAGS) -g $^ $(LOADLIBES) $(LDLIBS) -o $@ $(SC_LIBS) $(LIBS) 2>&1 | c++filt
-
-sc_main.o: sc_main.cpp $(VM_PREFIX).h
diff --git a/test_vcs/.gitignore b/test_vcs/.gitignore
deleted file mode 100644
index 485ec44..0000000
--- a/test_vcs/.gitignore
+++ /dev/null
@@ -1,13 +0,0 @@
-*.old
-*.dmp
-*.log
-*.csrc
-*.vcd
-csrc
-vcs.key
-ucli.key
-*.daidir
-simv
-obj_*
-project
-INCA_libs
diff --git a/test_vcs/Makefile b/test_vcs/Makefile
deleted file mode 100644
index 1619183..0000000
--- a/test_vcs/Makefile
+++ /dev/null
@@ -1,76 +0,0 @@
-#*****************************************************************************
-#
-# DESCRIPTION: Verilator Example: Makefile for inside source directory
-#
-# This calls the object directory makefile.  That allows the objects to
-# be placed in the "current directory" which simplifies the Makefile.
-#
-# Copyright 2003-2014 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.
-#
-#****************************************************************************/
-
-default: test
-
-# This must point to the root of the VERILATOR kit
-VERILATOR_ROOT := $(shell pwd)/..
-export VERILATOR_ROOT
-
-# Pick up PERL and other variable settings
-include $(VERILATOR_ROOT)/include/verilated.mk
-
-######################################################################
-
-V_FILES := $(wildcard *.v ../test_v/*.v)
-
-######################################################################
-
-ifneq ($(VCS_HOME),)
-test::	vcs
-else
-test::	novcs
-endif
-
-ifneq ($(NC_ROOT),)
-test::	nc
-else
-test::	nonc
-endif
-
-######################################################################
-
-novcs:
-	@echo "No VCS simulator installed."
-	@echo "Not running VCS regression test."
-
-vcs:	vcs_passed.log
-
-simv:	$(V_FILES) ../test_v/input.vc
-	vcs +cli -I -sverilog +define+VCS+1 -f ../test_v/input.vc -q bench.v
-
-vcs_passed.log	: simv
-	-rm -f test_passed.log
-	./simv -l sim.log
-	grep -q Finished sim.log && grep Finished sim.log > vcs_passed.log
-
-######################################################################
-
-nonc:
-	@echo "No NC-Verilog simulator installed."
-	@echo "Not running NC-Verilog regression test."
-
-nc:	nc_passed.log
-
-nc_passed.log: $(V_FILES) ../test_v/input.vc
-	ncverilog +define+ncverilog=1 +licqueue -f ../test_v/input.vc -q bench.v
-	-rm -f nc_passed.log
-	grep -q Finished ncverilog.log && grep Finished ncverilog.log > nc_passed.log
-
-######################################################################
-
-maintainer-copy::
-clean mostlyclean distclean maintainer-clean::
-	-rm -rf obj_dir *.log *.dmp *.vpd simv* *.key csrc INCA_libs
-
diff --git a/test_vcs/bench.v b/test_vcs/bench.v
deleted file mode 100644
index 0139014..0000000
--- a/test_vcs/bench.v
+++ /dev/null
@@ -1,81 +0,0 @@
-// DESCRIPTION: Verilator Test: Top level testbench for VCS or other fully Verilog compliant simulators
-//
-// This file ONLY is placed into the Public Domain, for any use,
-// without warranty, 2003 by Wilson Snyder.
-
-`timescale 1 ns / 1ns
-
-module bench;
-
-   /*AUTOWIRE*/
-   // Beginning of automatic wires (for undeclared instantiated-module outputs)
-   wire [39:0]		out_quad;		// From top of top.v
-   wire [1:0]		out_small;		// From top of top.v
-   wire [69:0]		out_wide;		// From top of top.v
-   wire			passed;			// From top of top.v
-   // End of automatics
-
-   reg  clk;
-   reg 	       fastclk;
-   reg 	       reset_l;
-   reg [1:0]   in_small;
-   reg [39:0]  in_quad;
-   reg [69:0]  in_wide;
-
-   // Test cases
-   top top (/*AUTOINST*/
-	    // Outputs
-	    .passed			(passed),
-	    .out_small			(out_small[1:0]),
-	    .out_quad			(out_quad[39:0]),
-	    .out_wide			(out_wide[69:0]),
-	    // Inputs
-	    .clk			(clk),
-	    .fastclk			(fastclk),
-	    .reset_l			(reset_l),
-	    .in_small			(in_small[1:0]),
-	    .in_quad			(in_quad[39:0]),
-	    .in_wide			(in_wide[69:0]));
-
-    //surefire lint_off STMINI
-    //surefire lint_off STMFVR
-    //surefire lint_off DLYONE
-
-   integer fh;
-
-   // surefire lint_off CWECBB
-   initial begin
-      reset_l = 1'b1;	// Want to catch negedge
-      fastclk = 0;
-      clk = 0;
-      forever begin
-	 in_small = 0;
-	 in_wide = 0;
-	 $write("[%0t] %x %x %x %x %x\n", $time, clk, reset_l, passed, out_small, out_wide);
-	 if (($time % 10) == 3) clk = 1'b1;
-	 if (($time % 10) == 8) clk = 1'b0;
-	 if ($time>10) reset_l = 1'b1;
-	 else if ($time > 1) reset_l = 1'b0;
-	 if ($time>60 || passed === 1'b1) begin
-	    if (passed !== 1'b1) begin
-	       $write("A Test failed!!!\n");
-	       $stop;
-	    end
-	    else begin
-	       $write("*-* All Finished *-*\n");  // Magic if using perl's Log::Detect
-	       fh = $fopen("test_passed.log");
-	       $fclose(fh);
-	    end
-	    $finish;
-	 end
-	 #1;
-	 fastclk = !fastclk;
-      end
-   end
-
-endmodule
-
-// Local Variables:
-// verilog-library-directories:("." "../test_v")
-// compile-command: "vlint --brief -f ../test_v/input.vc bench.v"
-// End:
diff --git a/verilator.1 b/verilator.1
index 0a29938..feabb43 100644
--- a/verilator.1
+++ b/verilator.1
@@ -124,7 +124,7 @@
 .\" ========================================================================
 .\"
 .IX Title "VERILATOR 1"
-.TH VERILATOR 1 "2014-11-13" "perl v5.14.2" "User Contributed Perl Documentation"
+.TH VERILATOR 1 "2014-12-20" "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
@@ -143,17 +143,13 @@ Verilator \- Convert Verilog code to C++/SystemC
 .SH "DESCRIPTION"
 .IX Header "DESCRIPTION"
 Verilator converts synthesizable (not behavioral) Verilog code, plus some
-Synthesis, SystemVerilog and a small subset of Verilog \s-1AMS\s0
-assertions, into \*(C+, SystemC or SystemPerl code.  It is not a complete
-simulator, just a compiler.
+Synthesis, SystemVerilog and a small subset of Verilog \s-1AMS\s0 assertions, into
+\&\*(C+ or SystemC code.  It is not a complete simulator, but a compiler.
 .PP
 Verilator is invoked with parameters similar to \s-1GCC\s0, Cadence
 Verilog\-XL/NC\-Verilog, or Synopsys's \s-1VCS\s0.  It reads the specified Verilog
 code, lints it, and optionally adds coverage and waveform tracing code.
-For \*(C+ and SystemC formats, it outputs .cpp and .h files.  For SystemPerl
-format, it outputs .sp files for the SystemPerl preprocessor, which greatly
-simplifies writing SystemC code and is available at
-<http://www.veripool.org>.
+For \*(C+ and SystemC formats, it outputs .cpp and .h files.
 .PP
 The files created by Verilator are then compiled with \*(C+.  The user writes
 a little \*(C+ wrapper file, which instantiates the top level module, and
@@ -249,8 +245,8 @@ descriptions in the next sections for more information.
 \&    \-\-report\-unoptflat          Extra diagnostics for UNOPTFLAT
 \&    \-\-savable                   Enable model save\-restore
 \&    \-\-sc                        Create SystemC output
-\&    \-\-sp                        Create SystemPerl output
 \&    \-\-stats                     Create statistics file
+\&    \-\-stats\-vars                Provide statistics on variables
 \&     \-sv                        Enable SystemVerilog parsing
 \&     +systemverilogext+<ext>    Synonym for +1800\-2012ext+<ext>
 \&    \-\-top\-module <topname>      Name of top level input module
@@ -376,7 +372,7 @@ run on the generated makefile these will be passed to the \*(C+ compiler
 (gcc/g++/msvc++).
 .IP "\-\-cc" 4
 .IX Item "--cc"
-Specifies \*(C+ without SystemC output mode; see also \-\-sc and \-\-sp.
+Specifies \*(C+ without SystemC output mode; see also \-\-sc.
 .IP "\-\-cdc" 4
 .IX Item "--cdc"
 Experimental.  Perform some clock domain crossing checks and issue related
@@ -838,13 +834,15 @@ other data the process needs saved/restored.  For example:
 .Ve
 .IP "\-\-sc" 4
 .IX Item "--sc"
-Specifies SystemC output mode; see also \-\-cc and \-sp.
-.IP "\-\-sp" 4
-.IX Item "--sp"
-Specifies SystemPerl output mode; see also \-\-cc and \-sc.
+Specifies SystemC output mode; see also \-\-cc.
 .IP "\-\-stats" 4
 .IX Item "--stats"
 Creates a dump file with statistics on the design in {prefix}_\|_stats.txt.
+.IP "\-\-stats\-vars" 4
+.IX Item "--stats-vars"
+Creates more detailed statistics including a list of all the variables by
+size (plain \-\-stats just gives a count).  See \-\-stats, which is implied by
+this.
 .IP "\-sv" 4
 .IX Item "-sv"
 Specifies SystemVerilog language features should be enabled; equivalent to
@@ -1141,7 +1139,7 @@ when your source changes it will automatically run all of these steps.  See
 the test_c directory in the distribution for an example.
 .SH "EXAMPLE SYSTEMC EXECUTION"
 .IX Header "EXAMPLE SYSTEMC EXECUTION"
-This is an example similar to the above, but using SystemPerl.
+This is an example similar to the above, but using SystemC.
 .PP
 .Vb 2
 \&    mkdir test_our_sc
@@ -1181,21 +1179,9 @@ your operating system (as an \s-1RPM\s0), first you need to point to the kit:
 Now we run Verilator on our little example.
 .PP
 .Vb 1
-\&    verilator \-Wall \-\-sp our.v
+\&    verilator \-Wall \-\-sc our.v
 .Ve
 .PP
-Then we convert the SystemPerl output to SystemC.
-.PP
-.Vb 3
-\&    cd obj_dir
-\&    export SYSTEMPERL=/path/to/where/systemperl/kit/came/from
-\&    $SYSTEMPERL/sp_preproc \-\-preproc *.sp
-.Ve
-.PP
-(You can also skip the above sp_preproc by getting pure SystemC from
-Verilator by replacing the verilator \-\-sp flag in the previous step with
-\&\-sc.)
-.PP
 We then can compile it
 .PP
 .Vb 2
@@ -1231,7 +1217,7 @@ And we get the same output as the \*(C+ example:
 .PP
 Really, you're better off using a Makefile to do all this for you.  Then,
 when your source changes it will automatically run all of these steps.  See
-the test_sp directory in the distribution for an example.
+the test_sc directory in the distribution for an example.
 .SH "BENCHMARKING & OPTIMIZATION"
 .IX Header "BENCHMARKING & OPTIMIZATION"
 For best performance, run Verilator with the \*(L"\-O3 \-\-x\-assign=fast
@@ -1289,6 +1275,10 @@ especially if you link in \s-1DPI\s0 code.  To enable \s-1LTO\s0 on \s-1GCC\s0,
 both compilation and link.  Note \s-1LTO\s0 may cause excessive compile times on
 large designs.
 .PP
+If you are using your own makefiles, you may want to compile the Verilated
+code with \-DVL_INLINE_OPT=inline. This will inline functions, however this
+requires that all cpp files be compiled in a single compiler run.
+.PP
 You may uncover further tuning possibilities by profiling the Verilog code.
 Use Verilator's \-\-profile\-cfuncs, then \s-1GCC\s0's \-g \-pg.  You can then run
 either oprofile or gprof to see where in the \*(C+ code the time is spent.
@@ -1318,13 +1308,6 @@ For \-cc and \-sc mode, it also creates:
 \&    {prefix}{each_verilog_module}.h     // Lower level internal header files
 .Ve
 .PP
-For \-sp mode, instead of .cpp and .h it creates:
-.PP
-.Vb 2
-\&    {prefix}.sp                         // Top level SystemC file
-\&    {prefix}{each_verilog_module}.sp    // Lower level internal SC files
-.Ve
-.PP
 In certain optimization modes, it also creates:
 .PP
 .Vb 8
@@ -1395,19 +1378,6 @@ If set, specifies the directory containing the libsystemc.a library. If not
 specified, it will come from a default optionally specified at configure
 time (before Verilator was compiled), or computed from
 SYSTEMC/lib\-SYSTEMC_ARCH.
-.IP "\s-1SYSTEMPERL\s0" 4
-.IX Item "SYSTEMPERL"
-Specifies the directory containing the SystemPerl distribution kit.  This
-is used to find the SystemPerl library and include files.  If not
-specified, it will come from a default optionally specified at configure
-time (before Verilator was compiled).  See also \s-1SYSTEMPERL_INCLUDE\s0.
-.IP "\s-1SYSTEMPERL_INCLUDE\s0" 4
-.IX Item "SYSTEMPERL_INCLUDE"
-Specifies the directory containing the Verilog-Perl include .cpp files,
-from the src/ directory of the SystemPerl kit.  If not specified, it will
-be computed from the \s-1SYSTEMPERL\s0 environment variable if it is set, and if
-\&\s-1SYSTEMPERL\s0 is not set \s-1SYSTEMPERL_INCLUDE\s0 will come from a default
-optionally specified at configure time (before Verilator was compiled).
 .IP "\s-1VCS_HOME\s0" 4
 .IX Item "VCS_HOME"
 If set, specifies the directory containing the Synopsys \s-1VCS\s0 distribution.
@@ -2022,8 +1992,8 @@ Specifies the module the comment appears in may be inlined into any modules
 that use this module.  This is useful to speed up simulation time with some
 small loss of trace visibility and modularity.  Note signals under inlined
 submodules will be named \fIsubmodule\fR_\|_DOT_\|_\fIsubsignal\fR as \*(C+ does not
-allow \*(L".\*(R" in signal names.  SystemPerl when tracing such signals will
-replace the _\|_DOT_\|_ with the period.
+allow \*(L".\*(R" in signal names.  When tracing such signals the tracing routines
+will replace the _\|_DOT_\|_ with the period.
 .IP "/*verilator isolate_assignments*/" 4
 .IX Item "/*verilator isolate_assignments*/"
 Used after a signal declaration to indicate the assignments to this signal
@@ -2427,8 +2397,9 @@ full nor unique.
 All specify blocks and timing checks are ignored.
 .IP "string" 4
 .IX Item "string"
-String is supported only to the point that they can be passed to \s-1DPI\s0
-imports.
+String is supported only to the point that they can be assigned,
+concatenated, compared, and passed to \s-1DPI\s0 imports.  Standard method calls
+on strings are not supported.
 .IP "timeunit, timeprecision" 4
 .IX Item "timeunit, timeprecision"
 All timing control statements are ignored.
@@ -3226,10 +3197,6 @@ flag.
 Note you can also call \->trace on multiple Verilated objects with the same
 trace file if you want all data to land in the same output file.
 .Sp
-Note also older versions of Verilator used the SystemPerl package and
-SpTraceVcdC class.  This still works, but is depreciated as it requires
-strong coupling between the Verilator and SystemPerl versions.
-.Sp
 .Vb 10
 \&    #include "verilated_vcd_c.h"
 \&    ...
@@ -3253,7 +3220,7 @@ Add the \-\-trace switch to Verilator, and in your top level C sc_main code,
 include verilated_vcd_sc.h.  Then call Verilated::traceEverOn(true).  Then
 create a VerilatedVcdSc object as you would create a normal SystemC trace
 file.  For an example, see the call to VerilatedVcdSc in the
-test_sp/sc_main.cpp file of the distribution, and below.
+test_sc/sc_main.cpp file of the distribution, and below.
 .Sp
 Alternatively you may use the \*(C+ trace mechanism described in the previous
 question, however the timescale and timeprecision will not inherited from
@@ -3304,22 +3271,21 @@ network disk.  Network disks are generally far slower.
 .IP "How do I do coverage analysis?" 4
 .IX Item "How do I do coverage analysis?"
 Verilator supports both block (line) coverage and user inserted functional
-coverage.  Both require the SystemPerl package to be installed but do not
-require use of the SystemPerl output mode.
+coverage.
 .Sp
 First, run verilator with the \-\-coverage option.  If you're using your own
-makefile, compile the model with the \s-1GCC\s0 flag \-DSP_COVERAGE (if using
+makefile, compile the model with the \s-1GCC\s0 flag \-DVM_COVERAGE (if using
 Verilator's, it will do this for you.)
 .Sp
 Run your tests in different directories.  Each test will create a
 logs/coverage.pl file.
 .Sp
-After running all of your tests, the vcoverage utility (from the SystemPerl
-package) is executed.  Vcoverage reads the logs/coverage.pl file(s), and
-creates an annotated source code listing showing code coverage details.
+After running all of your tests, verilator_coverage is executed.
+Verilator_coverage reads the logs/coverage.pl file(s), and creates an
+annotated source code listing showing code coverage details.
 .Sp
 For an example, after running 'make test' in the Verilator distribution,
-see the test_sp/logs/coverage_source directory.  Grep for lines starting
+see the test_sc/logs directory.  Grep for lines starting
 with '%' to see what lines Verilator believes need more coverage.
 .IP "Where is the translate_off command?  (How do I ignore a construct?)" 4
 .IX Item "Where is the translate_off command?  (How do I ignore a construct?)"
@@ -3607,7 +3573,7 @@ Wilson Snyder <wsnyder at wsnyder.org>
 Major concepts by Paul Wasson and Duane Galbi.
 .SH "SEE ALSO"
 .IX Header "SEE ALSO"
-verilator_profcfunc, systemperl, vcoverage, make,
+verilator_coverage, verilator_profcfunc, make,
 .PP
 \&\*(L"verilator \-\-help\*(R" which is the source for this document,
 .PP
diff --git a/verilator.html b/verilator.html
index 02007a4..551b3d7 100644
--- a/verilator.html
+++ b/verilator.html
@@ -121,16 +121,12 @@
 <hr />
 <h1><a name="description">DESCRIPTION</a></h1>
 <p>Verilator converts synthesizable (not behavioral) Verilog code, plus some
-Synthesis, SystemVerilog and a small subset of Verilog AMS
-assertions, into C++, SystemC or SystemPerl code.  It is not a complete
-simulator, just a compiler.</p>
+Synthesis, SystemVerilog and a small subset of Verilog AMS assertions, into
+C++ or SystemC code.  It is not a complete simulator, but a compiler.</p>
 <p>Verilator is invoked with parameters similar to GCC, Cadence
 Verilog-XL/NC-Verilog, or Synopsys's VCS.  It reads the specified Verilog
 code, lints it, and optionally adds coverage and waveform tracing code.
-For C++ and SystemC formats, it outputs .cpp and .h files.  For SystemPerl
-format, it outputs .sp files for the SystemPerl preprocessor, which greatly
-simplifies writing SystemC code and is available at
-<a href="http://www.veripool.org">http://www.veripool.org</a>.</p>
+For C++ and SystemC formats, it outputs .cpp and .h files.</p>
 <p>The files created by Verilator are then compiled with C++.  The user writes
 a little C++ wrapper file, which instantiates the top level module, and
 passes this filename on the command line.  These C files are compiled in
@@ -224,8 +220,8 @@ descriptions in the next sections for more information.</p>
     --report-unoptflat          Extra diagnostics for UNOPTFLAT
     --savable                   Enable model save-restore
     --sc                        Create SystemC output
-    --sp                        Create SystemPerl output
     --stats                     Create statistics file
+    --stats-vars                Provide statistics on variables
      -sv                        Enable SystemVerilog parsing
      +systemverilogext+<ext>    Synonym for +1800-2012ext+<ext>
     --top-module <topname>      Name of top level input module
@@ -364,7 +360,7 @@ run on the generated makefile these will be passed to the C++ compiler
 <dt><strong><a name="cc" class="item">--cc</a></strong></dt>
 
 <dd>
-<p>Specifies C++ without SystemC output mode; see also --sc and --sp.</p>
+<p>Specifies C++ without SystemC output mode; see also --sc.</p>
 </dd>
 <dt><strong><a name="cdc" class="item">--cdc</a></strong></dt>
 
@@ -920,17 +916,19 @@ other data the process needs saved/restored.  For example:</p>
 <dt><strong><a name="sc" class="item">--sc</a></strong></dt>
 
 <dd>
-<p>Specifies SystemC output mode; see also --cc and -sp.</p>
+<p>Specifies SystemC output mode; see also --cc.</p>
 </dd>
-<dt><strong><a name="sp" class="item">--sp</a></strong></dt>
+<dt><strong><a name="stats" class="item">--stats</a></strong></dt>
 
 <dd>
-<p>Specifies SystemPerl output mode; see also --cc and -sc.</p>
+<p>Creates a dump file with statistics on the design in {prefix}__stats.txt.</p>
 </dd>
-<dt><strong><a name="stats" class="item">--stats</a></strong></dt>
+<dt><strong><a name="stats_vars" class="item">--stats-vars</a></strong></dt>
 
 <dd>
-<p>Creates a dump file with statistics on the design in {prefix}__stats.txt.</p>
+<p>Creates more detailed statistics including a list of all the variables by
+size (plain --stats just gives a count).  See --stats, which is implied by
+this.</p>
 </dd>
 <dt><strong><a name="sv" class="item">-sv</a></strong></dt>
 
@@ -1256,7 +1254,7 @@ the test_c directory in the distribution for an example.</p>
 </p>
 <hr />
 <h1><a name="example_systemc_execution">EXAMPLE SYSTEMC EXECUTION</a></h1>
-<p>This is an example similar to the above, but using SystemPerl.</p>
+<p>This is an example similar to the above, but using SystemC.</p>
 <pre>
     mkdir test_our_sc
     cd test_our_sc</pre>
@@ -1289,15 +1287,7 @@ your operating system (as an RPM), first you need to point to the kit:</p>
     export PATH=$VERILATOR_ROOT/bin:$PATH</pre>
 <p>Now we run Verilator on our little example.</p>
 <pre>
-    verilator -Wall --sp our.v</pre>
-<p>Then we convert the SystemPerl output to SystemC.</p>
-<pre>
-    cd obj_dir
-    export SYSTEMPERL=/path/to/where/systemperl/kit/came/from
-    $SYSTEMPERL/sp_preproc --preproc *.sp</pre>
-<p>(You can also skip the above sp_preproc by getting pure SystemC from
-Verilator by replacing the verilator --sp flag in the previous step with
--sc.)</p>
+    verilator -Wall --sc our.v</pre>
 <p>We then can compile it</p>
 <pre>
     make -j -f Vour.mk Vour__ALL.a
@@ -1321,7 +1311,7 @@ depending on the operating system.</p>
     - our.v:2: Verilog $finish</pre>
 <p>Really, you're better off using a Makefile to do all this for you.  Then,
 when your source changes it will automatically run all of these steps.  See
-the test_sp directory in the distribution for an example.</p>
+the test_sc directory in the distribution for an example.</p>
 <p>
 </p>
 <hr />
@@ -1370,6 +1360,9 @@ feedback driven compilation.  With GCC, using -fprofile-arcs, then
 especially if you link in DPI code.  To enable LTO on GCC, pass "-flto" in
 both compilation and link.  Note LTO may cause excessive compile times on
 large designs.</p>
+<p>If you are using your own makefiles, you may want to compile the Verilated
+code with -DVL_INLINE_OPT=inline. This will inline functions, however this
+requires that all cpp files be compiled in a single compiler run.</p>
 <p>You may uncover further tuning possibilities by profiling the Verilog code.
 Use Verilator's --profile-cfuncs, then GCC's -g -pg.  You can then run
 either oprofile or gprof to see where in the C++ code the time is spent.
@@ -1393,10 +1386,6 @@ how Verilator compares, and may be able to suggest additional improvements.</p>
     {prefix}.h                          // Top level header
     {prefix}{each_verilog_module}.cpp   // Lower level internal C++ files
     {prefix}{each_verilog_module}.h     // Lower level internal header files</pre>
-<p>For -sp mode, instead of .cpp and .h it creates:</p>
-<pre>
-    {prefix}.sp                         // Top level SystemC file
-    {prefix}{each_verilog_module}.sp    // Lower level internal SC files</pre>
 <p>In certain optimization modes, it also creates:</p>
 <pre>
     {prefix}__Dpi.h                     // DPI import and export declarations
@@ -1474,23 +1463,6 @@ specified, it will come from a default optionally specified at configure
 time (before Verilator was compiled), or computed from
 SYSTEMC/lib-SYSTEMC_ARCH.</p>
 </dd>
-<dt><strong><a name="systemperl" class="item">SYSTEMPERL</a></strong></dt>
-
-<dd>
-<p>Specifies the directory containing the SystemPerl distribution kit.  This
-is used to find the SystemPerl library and include files.  If not
-specified, it will come from a default optionally specified at configure
-time (before Verilator was compiled).  See also SYSTEMPERL_INCLUDE.</p>
-</dd>
-<dt><strong><a name="systemperl_include" class="item">SYSTEMPERL_INCLUDE</a></strong></dt>
-
-<dd>
-<p>Specifies the directory containing the Verilog-Perl include .cpp files,
-from the src/ directory of the SystemPerl kit.  If not specified, it will
-be computed from the SYSTEMPERL environment variable if it is set, and if
-SYSTEMPERL is not set SYSTEMPERL_INCLUDE will come from a default
-optionally specified at configure time (before Verilator was compiled).</p>
-</dd>
 <dt><strong><a name="vcs_home" class="item">VCS_HOME</a></strong></dt>
 
 <dd>
@@ -2108,8 +2080,8 @@ appropriate --coverage flags are passed) after being disabled earlier with
 that use this module.  This is useful to speed up simulation time with some
 small loss of trace visibility and modularity.  Note signals under inlined
 submodules will be named <em>submodule</em>__DOT__<em>subsignal</em> as C++ does not
-allow "." in signal names.  SystemPerl when tracing such signals will
-replace the __DOT__ with the period.</p>
+allow "." in signal names.  When tracing such signals the tracing routines
+will replace the __DOT__ with the period.</p>
 </dd>
 <dt><strong><a name="verilator_isolate_assignments" class="item">/*verilator isolate_assignments*/</a></strong></dt>
 
@@ -2566,8 +2538,9 @@ full nor unique.</p>
 <dt><strong><a name="string" class="item">string</a></strong></dt>
 
 <dd>
-<p>String is supported only to the point that they can be passed to DPI
-imports.</p>
+<p>String is supported only to the point that they can be assigned,
+concatenated, compared, and passed to DPI imports.  Standard method calls
+on strings are not supported.</p>
 </dd>
 <dt><strong><a name="timeunit_timeprecision" class="item">timeunit, timeprecision</a></strong></dt>
 
@@ -3372,9 +3345,6 @@ Makefile's link rule.  This is done for you if using the Verilator --exe
 flag.</p>
 <p>Note you can also call ->trace on multiple Verilated objects with the same
 trace file if you want all data to land in the same output file.</p>
-<p>Note also older versions of Verilator used the SystemPerl package and
-SpTraceVcdC class.  This still works, but is depreciated as it requires
-strong coupling between the Verilator and SystemPerl versions.</p>
 <pre>
     #include "verilated_vcd_c.h"
     ...
@@ -3399,7 +3369,7 @@ strong coupling between the Verilator and SystemPerl versions.</p>
 include verilated_vcd_sc.h.  Then call Verilated::traceEverOn(true).  Then
 create a VerilatedVcdSc object as you would create a normal SystemC trace
 file.  For an example, see the call to VerilatedVcdSc in the
-test_sp/sc_main.cpp file of the distribution, and below.</p>
+test_sc/sc_main.cpp file of the distribution, and below.</p>
 <p>Alternatively you may use the C++ trace mechanism described in the previous
 question, however the timescale and timeprecision will not inherited from
 your SystemC settings.</p>
@@ -3449,18 +3419,17 @@ network disk.  Network disks are generally far slower.</p>
 
 <dd>
 <p>Verilator supports both block (line) coverage and user inserted functional
-coverage.  Both require the SystemPerl package to be installed but do not
-require use of the SystemPerl output mode.</p>
+coverage.</p>
 <p>First, run verilator with the --coverage option.  If you're using your own
-makefile, compile the model with the GCC flag -DSP_COVERAGE (if using
+makefile, compile the model with the GCC flag -DVM_COVERAGE (if using
 Verilator's, it will do this for you.)</p>
 <p>Run your tests in different directories.  Each test will create a
 logs/coverage.pl file.</p>
-<p>After running all of your tests, the vcoverage utility (from the SystemPerl
-package) is executed.  Vcoverage reads the logs/coverage.pl file(s), and
-creates an annotated source code listing showing code coverage details.</p>
+<p>After running all of your tests, verilator_coverage is executed.
+Verilator_coverage reads the logs/coverage.pl file(s), and creates an
+annotated source code listing showing code coverage details.</p>
 <p>For an example, after running 'make test' in the Verilator distribution,
-see the test_sp/logs/coverage_source directory.  Grep for lines starting
+see the test_sc/logs directory.  Grep for lines starting
 with '%' to see what lines Verilator believes need more coverage.</p>
 </dd>
 <dt><strong><a name="where_is_the_translate_off_command_how_do_i_ignore_a_construct" class="item">Where is the translate_off command?  (How do I ignore a construct?)</a></strong></dt>
@@ -3736,7 +3705,7 @@ License Version 2.0.</p>
 </p>
 <hr />
 <h1><a name="see_also">SEE ALSO</a></h1>
-<p><em>verilator_profcfunc</em>, <em>systemperl</em>, <em>vcoverage</em>, <em>make</em>,</p>
+<p><em>verilator_coverage</em>, <em>verilator_profcfunc</em>, <em>make</em>,</p>
 <p><a href="#verilator___help">verilator --help</a> which is the source for this document,</p>
 <p>and internals.txt in the distribution.</p>
 
diff --git a/verilator.pdf b/verilator.pdf
index ada2468..48b2a4a 100644
Binary files a/verilator.pdf and b/verilator.pdf differ
diff --git a/verilator.txt b/verilator.txt
index ed48441..6b3c258 100644
--- a/verilator.txt
+++ b/verilator.txt
@@ -11,16 +11,13 @@ SYNOPSIS
 DESCRIPTION
     Verilator converts synthesizable (not behavioral) Verilog code, plus
     some Synthesis, SystemVerilog and a small subset of Verilog AMS
-    assertions, into C++, SystemC or SystemPerl code. It is not a complete
-    simulator, just a compiler.
+    assertions, into C++ or SystemC code. It is not a complete simulator,
+    but a compiler.
 
     Verilator is invoked with parameters similar to GCC, Cadence
     Verilog-XL/NC-Verilog, or Synopsys's VCS. It reads the specified Verilog
     code, lints it, and optionally adds coverage and waveform tracing code.
-    For C++ and SystemC formats, it outputs .cpp and .h files. For
-    SystemPerl format, it outputs .sp files for the SystemPerl preprocessor,
-    which greatly simplifies writing SystemC code and is available at
-    <http://www.veripool.org>.
+    For C++ and SystemC formats, it outputs .cpp and .h files.
 
     The files created by Verilator are then compiled with C++. The user
     writes a little C++ wrapper file, which instantiates the top level
@@ -115,8 +112,8 @@ ARGUMENT SUMMARY
         --report-unoptflat          Extra diagnostics for UNOPTFLAT
         --savable                   Enable model save-restore
         --sc                        Create SystemC output
-        --sp                        Create SystemPerl output
         --stats                     Create statistics file
+        --stats-vars                Provide statistics on variables
          -sv                        Enable SystemVerilog parsing
          +systemverilogext+<ext>    Synonym for +1800-2012ext+<ext>
         --top-module <topname>      Name of top level input module
@@ -235,7 +232,7 @@ ARGUMENTS
         compiler (gcc/g++/msvc++).
 
     --cc
-        Specifies C++ without SystemC output mode; see also --sc and --sp.
+        Specifies C++ without SystemC output mode; see also --sc.
 
     --cdc
         Experimental. Perform some clock domain crossing checks and issue
@@ -704,15 +701,17 @@ ARGUMENTS
             }
 
     --sc
-        Specifies SystemC output mode; see also --cc and -sp.
-
-    --sp
-        Specifies SystemPerl output mode; see also --cc and -sc.
+        Specifies SystemC output mode; see also --cc.
 
     --stats
         Creates a dump file with statistics on the design in
         {prefix}__stats.txt.
 
+    --stats-vars
+        Creates more detailed statistics including a list of all the
+        variables by size (plain --stats just gives a count). See --stats,
+        which is implied by this.
+
     -sv Specifies SystemVerilog language features should be enabled;
         equivalent to "--language 1800-2005". This option is selected by
         default, it exists for compatibility with other simulators.
@@ -994,7 +993,7 @@ EXAMPLE C++ EXECUTION
     steps. See the test_c directory in the distribution for an example.
 
 EXAMPLE SYSTEMC EXECUTION
-    This is an example similar to the above, but using SystemPerl.
+    This is an example similar to the above, but using SystemC.
 
         mkdir test_our_sc
         cd test_our_sc
@@ -1030,17 +1029,7 @@ EXAMPLE SYSTEMC EXECUTION
 
     Now we run Verilator on our little example.
 
-        verilator -Wall --sp our.v
-
-    Then we convert the SystemPerl output to SystemC.
-
-        cd obj_dir
-        export SYSTEMPERL=/path/to/where/systemperl/kit/came/from
-        $SYSTEMPERL/sp_preproc --preproc *.sp
-
-    (You can also skip the above sp_preproc by getting pure SystemC from
-    Verilator by replacing the verilator --sp flag in the previous step with
-    -sc.)
+        verilator -Wall --sc our.v
 
     We then can compile it
 
@@ -1069,7 +1058,7 @@ EXAMPLE SYSTEMC EXECUTION
 
     Really, you're better off using a Makefile to do all this for you. Then,
     when your source changes it will automatically run all of these steps.
-    See the test_sp directory in the distribution for an example.
+    See the test_sc directory in the distribution for an example.
 
 BENCHMARKING & OPTIMIZATION
     For best performance, run Verilator with the "-O3 --x-assign=fast
@@ -1125,6 +1114,11 @@ BENCHMARKING & OPTIMIZATION
     "-flto" in both compilation and link. Note LTO may cause excessive
     compile times on large designs.
 
+    If you are using your own makefiles, you may want to compile the
+    Verilated code with -DVL_INLINE_OPT=inline. This will inline functions,
+    however this requires that all cpp files be compiled in a single
+    compiler run.
+
     You may uncover further tuning possibilities by profiling the Verilog
     code. Use Verilator's --profile-cfuncs, then GCC's -g -pg. You can then
     run either oprofile or gprof to see where in the C++ code the time is
@@ -1151,11 +1145,6 @@ FILES
         {prefix}{each_verilog_module}.cpp   // Lower level internal C++ files
         {prefix}{each_verilog_module}.h     // Lower level internal header files
 
-    For -sp mode, instead of .cpp and .h it creates:
-
-        {prefix}.sp                         // Top level SystemC file
-        {prefix}{each_verilog_module}.sp    // Lower level internal SC files
-
     In certain optimization modes, it also creates:
 
         {prefix}__Dpi.h                     // DPI import and export declarations
@@ -1223,21 +1212,6 @@ ENVIRONMENT
         at configure time (before Verilator was compiled), or computed from
         SYSTEMC/lib-SYSTEMC_ARCH.
 
-    SYSTEMPERL
-        Specifies the directory containing the SystemPerl distribution kit.
-        This is used to find the SystemPerl library and include files. If
-        not specified, it will come from a default optionally specified at
-        configure time (before Verilator was compiled). See also
-        SYSTEMPERL_INCLUDE.
-
-    SYSTEMPERL_INCLUDE
-        Specifies the directory containing the Verilog-Perl include .cpp
-        files, from the src/ directory of the SystemPerl kit. If not
-        specified, it will be computed from the SYSTEMPERL environment
-        variable if it is set, and if SYSTEMPERL is not set
-        SYSTEMPERL_INCLUDE will come from a default optionally specified at
-        configure time (before Verilator was compiled).
-
     VCS_HOME
         If set, specifies the directory containing the Synopsys VCS
         distribution. When set, a 'make test' in the Verilator distribution
@@ -1815,8 +1789,8 @@ LANGUAGE EXTENSIONS
         time with some small loss of trace visibility and modularity. Note
         signals under inlined submodules will be named
         *submodule*__DOT__*subsignal* as C++ does not allow "." in signal
-        names. SystemPerl when tracing such signals will replace the __DOT__
-        with the period.
+        names. When tracing such signals the tracing routines will replace
+        the __DOT__ with the period.
 
     /*verilator isolate_assignments*/
         Used after a signal declaration to indicate the assignments to this
@@ -2240,8 +2214,9 @@ LANGUAGE LIMITATIONS
         All specify blocks and timing checks are ignored.
 
     string
-        String is supported only to the point that they can be passed to DPI
-        imports.
+        String is supported only to the point that they can be assigned,
+        concatenated, compared, and passed to DPI imports. Standard method
+        calls on strings are not supported.
 
     timeunit, timeprecision
         All timing control statements are ignored.
@@ -3021,11 +2996,6 @@ FAQ/FREQUENTLY ASKED QUESTIONS
         the same trace file if you want all data to land in the same output
         file.
 
-        Note also older versions of Verilator used the SystemPerl package
-        and SpTraceVcdC class. This still works, but is depreciated as it
-        requires strong coupling between the Verilator and SystemPerl
-        versions.
-
             #include "verilated_vcd_c.h"
             ...
             int main(int argc, char **argv, char **env) {
@@ -3047,7 +3017,7 @@ FAQ/FREQUENTLY ASKED QUESTIONS
         code, include verilated_vcd_sc.h. Then call
         Verilated::traceEverOn(true). Then create a VerilatedVcdSc object as
         you would create a normal SystemC trace file. For an example, see
-        the call to VerilatedVcdSc in the test_sp/sc_main.cpp file of the
+        the call to VerilatedVcdSc in the test_sc/sc_main.cpp file of the
         distribution, and below.
 
         Alternatively you may use the C++ trace mechanism described in the
@@ -3099,25 +3069,23 @@ FAQ/FREQUENTLY ASKED QUESTIONS
 
     How do I do coverage analysis?
         Verilator supports both block (line) coverage and user inserted
-        functional coverage. Both require the SystemPerl package to be
-        installed but do not require use of the SystemPerl output mode.
+        functional coverage.
 
         First, run verilator with the --coverage option. If you're using
-        your own makefile, compile the model with the GCC flag -DSP_COVERAGE
+        your own makefile, compile the model with the GCC flag -DVM_COVERAGE
         (if using Verilator's, it will do this for you.)
 
         Run your tests in different directories. Each test will create a
         logs/coverage.pl file.
 
-        After running all of your tests, the vcoverage utility (from the
-        SystemPerl package) is executed. Vcoverage reads the
-        logs/coverage.pl file(s), and creates an annotated source code
-        listing showing code coverage details.
+        After running all of your tests, verilator_coverage is executed.
+        Verilator_coverage reads the logs/coverage.pl file(s), and creates
+        an annotated source code listing showing code coverage details.
 
         For an example, after running 'make test' in the Verilator
-        distribution, see the test_sp/logs/coverage_source directory. Grep
-        for lines starting with '%' to see what lines Verilator believes
-        need more coverage.
+        distribution, see the test_sc/logs directory. Grep for lines
+        starting with '%' to see what lines Verilator believes need more
+        coverage.
 
     Where is the translate_off command? (How do I ignore a construct?)
         Translate on/off pragmas are generally a bad idea, as it's easy to
@@ -3396,7 +3364,7 @@ AUTHORS
     Major concepts by Paul Wasson and Duane Galbi.
 
 SEE ALSO
-    verilator_profcfunc, systemperl, vcoverage, make,
+    verilator_coverage, verilator_profcfunc, make,
 
     "verilator --help" which is the source for this document,
 
diff --git a/verilator_coverage.1 b/verilator_coverage.1
new file mode 100644
index 0000000..f3ece0f
--- /dev/null
+++ b/verilator_coverage.1
@@ -0,0 +1,238 @@
+.\" Automatically generated by Pod::Man 2.25 (Pod::Simple 3.16)
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sp \" Vertical space (when we can't use .PP)
+.if t .sp .5v
+.if n .sp
+..
+.de Vb \" Begin verbatim text
+.ft CW
+.nf
+.ne \\$1
+..
+.de Ve \" End verbatim text
+.ft R
+.fi
+..
+.\" Set up some character translations and predefined strings.  \*(-- will
+.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left
+.\" double quote, and \*(R" will give a right double quote.  \*(C+ will
+.\" give a nicer C++.  Capital omega is used to do unbreakable dashes and
+.\" therefore won't be available.  \*(C` and \*(C' expand to `' in nroff,
+.\" nothing in troff, for use with C<>.
+.tr \(*W-
+.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p'
+.ie n \{\
+.    ds -- \(*W-
+.    ds PI pi
+.    if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch
+.    if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\"  diablo 12 pitch
+.    ds L" ""
+.    ds R" ""
+.    ds C` ""
+.    ds C' ""
+'br\}
+.el\{\
+.    ds -- \|\(em\|
+.    ds PI \(*p
+.    ds L" ``
+.    ds R" ''
+'br\}
+.\"
+.\" Escape single quotes in literal strings from groff's Unicode transform.
+.ie \n(.g .ds Aq \(aq
+.el       .ds Aq '
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.ie \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.el \{\
+.    de IX
+..
+.\}
+.\"
+.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2).
+.\" Fear.  Run.  Save yourself.  No user-serviceable parts.
+.    \" fudge factors for nroff and troff
+.if n \{\
+.    ds #H 0
+.    ds #V .8m
+.    ds #F .3m
+.    ds #[ \f1
+.    ds #] \fP
+.\}
+.if t \{\
+.    ds #H ((1u-(\\\\n(.fu%2u))*.13m)
+.    ds #V .6m
+.    ds #F 0
+.    ds #[ \&
+.    ds #] \&
+.\}
+.    \" simple accents for nroff and troff
+.if n \{\
+.    ds ' \&
+.    ds ` \&
+.    ds ^ \&
+.    ds , \&
+.    ds ~ ~
+.    ds /
+.\}
+.if t \{\
+.    ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u"
+.    ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u'
+.    ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u'
+.    ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u'
+.    ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u'
+.    ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u'
+.\}
+.    \" troff and (daisy-wheel) nroff accents
+.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V'
+.ds 8 \h'\*(#H'\(*b\h'-\*(#H'
+.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#]
+.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H'
+.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u'
+.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#]
+.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#]
+.ds ae a\h'-(\w'a'u*4/10)'e
+.ds Ae A\h'-(\w'A'u*4/10)'E
+.    \" corrections for vroff
+.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u'
+.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u'
+.    \" for low resolution devices (crt and lpr)
+.if \n(.H>23 .if \n(.V>19 \
+\{\
+.    ds : e
+.    ds 8 ss
+.    ds o a
+.    ds d- d\h'-1'\(ga
+.    ds D- D\h'-1'\(hy
+.    ds th \o'bp'
+.    ds Th \o'LP'
+.    ds ae ae
+.    ds Ae AE
+.\}
+.rm #[ #] #H #V #F C
+.\" ========================================================================
+.\"
+.IX Title "VERILATOR_COVERAGE 1"
+.TH VERILATOR_COVERAGE 1 "2014-12-19" "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
+.nh
+.SH "NAME"
+verilator_coverage \- Verilator coverage analyzer
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+.Vb 2
+\&    verilator_coverage \-\-help
+\&    verilator_coverage \-\-version
+\&
+\&    verilator_coverage \-\-annotate <obj>
+\&
+\&    verilator_coverage  \-write merged.dat \-read <datafiles>...
+.Ve
+.PP
+Verilator_coverage processes Verilator coverage reports.
+.PP
+With \-\-anotate, it reads the specified data file and generates annotated
+source code with coverage metrics annotated.  If multiple coverage points
+exist on the same line, additional lines will be inserted to report the
+additional points.
+.PP
+Additional Verilog-standard arguments specify the search paths necessary to
+find the source code that the coverage analysis was performed on.
+.PP
+To get correct coverage percentages, you may wish to read logs/coverage.pl
+into Emacs and do a M\-x keep-lines to include only those statistics of
+interest.
+.PP
+For Verilog conditions that should never occur, you should add a \f(CW$stop\fR
+statement.  This will remove the coverage during the next build.
+.SH "ARGUMENTS"
+.IX Header "ARGUMENTS"
+.IP "\fIfilename\fR" 4
+.IX Item "filename"
+Specify input data file, may be repeated to read multiple inputs.  If no
+data file is specified, by default coverage.dat is read.
+.IP "\-\-annotate \fIoutput_directory\fR" 4
+.IX Item "--annotate output_directory"
+Sprcifies the directory name that source files with annotated coverage data
+should be written to.
+.IP "\-\-annotate\-all" 4
+.IX Item "--annotate-all"
+Specifies all files should be shown.  By default, only those source files
+which have low coverage are written to the output directory.
+.IP "\-\-annotate\-min \fIcount\fR" 4
+.IX Item "--annotate-min count"
+Specifies the minimum occurrence count that should be flagged if the
+coverage point does not include a specified threshold.  Defaults to 10.
+.IP "\-\-help" 4
+.IX Item "--help"
+Displays this message and program version and exits.
+.IP "\-\-rank" 4
+.IX Item "--rank"
+Print an experimental report listing the relative importance of each test
+in covering all of the coverage points.  The report shows \*(L"Covered\*(R" which
+indicates the number of points that test covers; a test is considered to
+cover a point if it has a bucket count of at least 1. The \*(L"rank\*(R" column has
+a higher number t indicate the test is more important, and rank 0 means the
+test does not need to be run to cover the points.  \*(L"RankPts\*(R" indicates the
+number of coverage points this test will contribute to overall coverage if
+all tests are run in the order of highest to lowest rank.
+.IP "\-\-unlink" 4
+.IX Item "--unlink"
+When using \-\-write to combine coverage data, unlink all input files after
+the output has been created.
+.IP "\-\-version" 4
+.IX Item "--version"
+Displays program version and exits.
+.IP "\-\-write \fIfilename\fR" 4
+.IX Item "--write filename"
+Specifies the aggregate coverage results, summed across all the files,
+should be written to the given filename.  This is useful in scripts to
+combine many sequential runs into one master coverage file.
+.SH "VERILOG ARGUMENTS"
+.IX Header "VERILOG ARGUMENTS"
+The following arguments are compatible with \s-1GCC\s0, \s-1VCS\s0 and most Verilog
+programs.
+.IP "+libext+\fIext\fR+\fIext\fR..." 4
+.IX Item "+libext+ext+ext..."
+Defines the extensions for Verilog files.
+.IP "+define+\fIvar\fR+\fIvalue\fR =item \-D\fIvar\fR=\fIvalue\fR" 4
+.IX Item "+define+var+value =item -Dvar=value"
+Defines the given variable.
+.IP "+incdir+\fIdir\fR =item \-I\fIdir\fR" 4
+.IX Item "+incdir+dir =item -Idir"
+Specifies a directory for finding include files.
+.IP "\-f \fIfile\fR" 4
+.IX Item "-f file"
+Specifies a file containing additional command line arguments.
+.IP "\-y \fIdir\fR" 4
+.IX Item "-y dir"
+Specifies a module search directory.
+.SH "DISTRIBUTION"
+.IX Header "DISTRIBUTION"
+The latest version is available from <http://www.veripool.org/>.
+.PP
+Copyright 2003\-2014 by Wilson Snyder.  Verilator is free software; you can
+redistribute it and/or modify the Verilator internals under the terms of
+either the \s-1GNU\s0 Lesser General Public License Version 3 or the Perl Artistic
+License Version 2.0.
+.SH "AUTHORS"
+.IX Header "AUTHORS"
+Wilson Snyder <wsnyder at wsnyder.org>
+.SH "SEE ALSO"
+.IX Header "SEE ALSO"
+\&\f(CW\*(C`verilator\*(C'\fR
+.PP
+\&\*(L"verilator_coverage \-\-help\*(R" which is the source for this document.

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-electronics/verilator.git



More information about the Pkg-electronics-commits mailing list