diff --git a/bin/htmlgen/filelist_compile.py b/bin/htmlgen/filelist_compile.py
new file mode 100755
index 0000000000000000000000000000000000000000..1ccbf2afa0faab6483f56b9c0aea9d90518a8a4e
--- /dev/null
+++ b/bin/htmlgen/filelist_compile.py
@@ -0,0 +1,104 @@
+#!/usr/bin/env python3
+#------------------------------------------------------------------------------------
+# Verilog Filelist compilation script
+# A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+#
+# Contributors
+#
+# David Mapstone (d.a.mapstone@soton.ac.uk)
+# Copyright (c) 2023, SoC Labs (www.soclabs.org)
+#------------------------------------------------------------------------------------
+
+import argparse
+import os
+
+verilog_extensions = (".v", ".sv")
+
+filelist_header = """//-----------------------------------------------------------------------------
+// AUTOGENERATED: Compiled Filelist
+// A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+//
+// Contributors
+//
+// David Mapstone (d.a.mapstone@soton.ac.uk)
+//
+// Copyright � 2021-3, SoC Labs (www.soclabs.org)
+//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// Abstract : Verilog Command File with expanded system variables
+//-----------------------------------------------------------------------------
+
+"""
+
+def env_var_substitute(path):
+    # Interpret the path and remove brackets from path
+    sub_path = path.translate(str.maketrans('', '', '()'))
+    # Expand environment variables in Path
+    sub_path = os.path.expandvars(sub_path)
+    return sub_path
+
+def read_list(filelist):
+    # Create Filelist List Structure
+    compiled_filelist = []
+    # Open Filelist and Read Lines
+    f = open(filelist, "r")
+    filelines = f.readlines()
+    f.close()
+    # Remove Black Lines from list
+    filelines = [x.rstrip("\n") for x in filelines]
+    filelines = [x for x in filelines if x != ""]
+    # Iterate over list and process
+    for line in filelines:
+        # Remove whitespace and split line into arguments
+        line_list = line.strip().split()
+        # print(line_list)
+        # Check Line isn't a comment
+        if not line_list[0].startswith("//"):
+            # If line is a reference to another filelist 
+            if line_list[0] == "-f":
+                # Recursively call this function and append list to this compiled Filelist
+                print(line_list[1])
+                compiled_filelist += read_list(env_var_substitute(line_list[1]))
+
+            elif line_list[0] == "-y":
+                # Append to filelist
+                for file in os.listdir(env_var_substitute(line_list[1])):
+                    if file.endswith(verilog_extensions): 
+                        compiled_filelist.append(env_var_substitute(line_list[1])+"/"+str(file))
+            
+            elif line_list[0].startswith("+incdir+"):
+                # Append to filelist
+                for file in os.listdir(env_var_substitute(line_list[0].lstrip("+incdir+"))):
+                    if file.endswith(verilog_extensions): 
+                        compiled_filelist.append(env_var_substitute(line_list[0].lstrip("+incdir+"))+"/"+str(file))
+                
+            # If file list a verilog file
+            elif line_list[0].endswith(verilog_extensions):
+                # Append to filelist
+                compiled_filelist.append(env_var_substitute(line_list[0]))
+    return compiled_filelist
+            
+
+def filelist_compile(args):
+    input_filelist = args.filelist
+    output_filelist = args.output
+    print("------------------")
+    print("Compiling Filelist")
+    print("------------------")
+    filelist = read_list(input_filelist)
+    filelist = [x+"\n" for x in filelist]
+    filelist_str = filelist_header
+    for path in filelist: filelist_str += path
+    print("Compile Done")
+    print("------------------")
+    f_outlist = open(output_filelist, "w")
+    f_outlist.write(filelist_str)
+    f_outlist.close()
+
+if __name__ == "__main__":
+    # Capture Arguments from Command Line
+    parser = argparse.ArgumentParser(description='Compiles Filelist to Read')
+    parser.add_argument("-f", "--filelist", type=str, help="Input Filelist to Read")
+    parser.add_argument("-o", "--output", type=str, help="Output Filelist location")
+    args = parser.parse_args()
+    filelist_compile(args)
\ No newline at end of file
diff --git a/bin/htmlgen/makefile b/bin/htmlgen/makefile
new file mode 100644
index 0000000000000000000000000000000000000000..e89d9d0b141a4d6b4e386e158196cd04495bdf60
--- /dev/null
+++ b/bin/htmlgen/makefile
@@ -0,0 +1,33 @@
+#-----------------------------------------------------------------------------
+# HTML Generatoration Makefile 
+# A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+#
+# Contributors
+#
+# David Mapstone (d.a.mapstone@soton.ac.uk)
+#
+# Copyright � 2021-3, SoC Labs (www.soclabs.org)
+#-----------------------------------------------------------------------------
+
+# Top-level module of Hierarchy
+TOP_MODULE      ?= nanosoc_chip
+
+# Filelist to give to v2html
+FILELIST        ?= $(PROJECT_DIR)/flist/project/system.flist
+
+# Directory to store generated HTML
+OUT_DIR         ?= $(PROJECT_DIR)
+
+# Name of generated filelist by python script
+OUTPUT_FILELIST := $(OUT_DIR)/filelist.flist
+
+bootrom:
+	make -C $(NANOSOC_TECH_DIR)/system bootrom
+
+htmlgen: bootrom
+	@echo building HTML tree
+	@mkdir -p $(OUT_DIR)/build
+	@(cd $(OUT_DIR)/build; \
+	rm *.html; rm *.gif; \
+	$(SOCTOOLS_FLOW_DIR)/bin/htmlgen/filelist_compile.py -f $(FILELIST) -o $(OUTPUT_FILELIST) ; \
+	$(SOCTOOLS_FLOW_DIR)/bin/htmlgen/v2html/v2html -f $(OUTPUT_FILELIST) -ht $(TOP_MODULE) ; )
diff --git a/bin/htmlgen/v2html/LICENCE.TXT b/bin/htmlgen/v2html/LICENCE.TXT
new file mode 100644
index 0000000000000000000000000000000000000000..e2a72de1787620ebf7c84fe3b6cdc146bf37a4f0
--- /dev/null
+++ b/bin/htmlgen/v2html/LICENCE.TXT
@@ -0,0 +1,67 @@
+			v2html Conversion Software
+
+			Limited Copyright Licence
+
+BACKGROUND
+
+The accompanying v2html conversion software (the software) is a 
+copyrighted work.  This document describes conditions under which the 
+software can be copied, modified and distributed.
+
+All rights, including copyright, in the software are retained by the 
+owner(s) as identified in each software file.
+
+Subject to the conditions described below, you may modify source 
+files included with the software and distribute the modified 
+versions.  The software accompanying this notice may include such 
+derivative works.
+
+CONDITIONS FOR AUTHORIZED COPYING, MODIFICATION AND DISTRIBUTION
+
+If you agree to all of the following conditions, you may copy, modify 
+and distribute the software subject to these conditions.
+
+You do not need to agree to these conditions.  However, if you do not 
+agree to all of the following conditions, you are not authorized to 
+do anything with regard to the copyrighted work that is within the 
+exclusive domain of a copyright owner, such as copying, modification, 
+and distribution.
+
+(1) No fee (monetary or otherwise) may be charged for the software or 
+any derivative work (whether in exchange for copying, distribution, 
+use, or otherwise).
+
+(2) The software includes copyright notices, references to this 
+document, and warnings concerning the intended use of the software.  
+All such notices are to be included in all copies of the software.  
+Any code copied or moved to a file not having such notices must be 
+accompanied by such notices.  Notices that are displayed to a user 
+during execution of the software are to remain intact.
+
+(3) This document may not be modified.  A copy of this document must 
+be included with each copy of the software, including derivative 
+works.
+
+(4) Failure to abide by these conditions terminates any rights that 
+you may otherwise have had under this licence.
+
+(5) NO WARRANTY:  The software has NO warranty from anyone; for 
+example, there is NO warranty that the software is error free and 
+there is NO warranty with respect to infringement of patents, 
+copyrights or any other intellectual property rights.  The software 
+is provided "AS IS."  NO support is provided for the software.
+
+THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 
+PARTICULAR PURPOSE ARE SPECIFICALLY DISCLAIMED.
+
+(6) LIMITATIONS OF REMEDIES AND LIABILITY:
+In no event shall Hewlett-Packard be liable for direct, indirect, 
+special, incidental or consequential damages (including lost 
+profits), whether based on contract, tort or any other legal theory.
+
+(7) DERIVATIVE WORKS:  In this document, the phrase "derivative work" 
+is intended to include only those works that include sufficient 
+copyrightable material from the software such that the derivative 
+work would be a copyright infringement if made without authorization 
+of the owner of the copyright in the software.
+
diff --git a/bin/htmlgen/v2html/README b/bin/htmlgen/v2html/README
new file mode 100644
index 0000000000000000000000000000000000000000..e705ed620ce47245260b1dc75c4ac8653111df26
--- /dev/null
+++ b/bin/htmlgen/v2html/README
@@ -0,0 +1,43 @@
+
+v2html - verilog to html converter
+----------------------------------
+
+See LICENCE.TXT for details of licencing.
+
+See http://www.burbleland.com/v2html for more information.
+
+Files included:
+
+README		- this file
+v2html 		- v2html perl script
+v2html-cgi	- CGI helper script (for collapsible hierarchy)
+LICENCE.TXT	- licence
+v2html.man.html - man page in html format
+v2html.1	- man page in nroff format
+
+- Make sure you have perl version 5.004 or later (perl -v tells you
+  the version).
+
+Unix Installation
+-----------------
+
+- Copy v2html to somewhere like /usr/local/bin.
+- If you are using the CGI script then see your web-server's documentation
+  on where to put CGI scripts.
+- Copy v2html.1 to somewhere like /usr/local/man.
+
+If your copy of perl is not in /usr/bin then you will have to edit the
+first line of v2html and v2html-cgi to refer to where your copy of
+perl in installed. Alternatively you could install a link from 
+/usr/bin/perl to your copy of perl.
+
+Windows Installation
+--------------------
+
+- Put the v2html script somewhere (eg C:\v2html)
+- Then, assuming you have Perl installed as c:\perl\bin\perl.exe, you should
+ be able to run v2html from a DOS box with a command like this:
+
+  c:\perl\bin\perl.exe c:\v2html\v2html -f my_cmd_file.vc
+
+
diff --git a/bin/htmlgen/v2html/v2html b/bin/htmlgen/v2html/v2html
new file mode 100755
index 0000000000000000000000000000000000000000..6e0f8c74c5352f81c1ee177c38dca81046966b58
--- /dev/null
+++ b/bin/htmlgen/v2html/v2html
@@ -0,0 +1,7488 @@
+#!/usr/bin/perl -w
+###############################################################################
+#
+# File:         v2html
+# RCS:          $Header: /home/cc/v2html/build/../RCS/v2html,v 7.30.1.3 2006/05/03 20:19:55 cc Exp $
+# Description:  Verilog to html converter
+# Author:       Costas Calamvokis
+# Created:      Wed Aug 20 11:24:31 1997
+# Modified:     Fri Apr  7 11:03:32 2006
+# Language:     Perl
+#
+# Copyright 1998-2006 Costas Calamvokis
+# Copyright 1997      Hewlett-Packard Company
+#
+#  This file nay be copied, modified and distributed only in accordance
+#  with the terms of the limited licence contained in the accompanying
+#  file LICENCE.TXT.
+#
+###############################################################################
+
+#use strict;
+
+# Define the global variables 
+
+use vars qw($output_hier $output_index $hier_file $frame_file $quiet $incremental
+	    $maint $frames $frame_bottom $frame_middle $frame_top $frame_code
+	    $link_to_source $cgi_script $web_base $js_hier
+	    $js_file $out_dir $js_cookies
+	    $print_unconnected $print_no_mods $grey_ifdefed_out $cgi_key
+	    $t_and_f_in_hier $compress @compress_cmd $compress_extension
+	    $hier_comment $tabstop $js_sigs $help_info @inc_dirs @lib_dirs 
+	    @lib_exts %navbar %classes $lines_per_file $index_info $style_sheet_link
+	    @output_files @args $css
+
+	    $verilog_db
+
+	    @verilog_keywords 
+	    %verilog_keywords_hash %verilog_compiler_keywords_hash
+
+            $version $vert_frames $mail_regexp $http_regexp $VID $icon_c $icon_i
+	    $icon_x @newer_files @files $file @hier_tops %cmd_line_defines
+	    $module $debug $ul_id @index_stack );
+
+# check the perl version is high enough
+if ( $] < 5.004 ) {
+    print "Error: this script can only run with Perl version 5.004 or greater\n";
+    exit 1;
+}
+
+# initialize
+&init;
+
+# read the arguments
+&process_args;
+
+# legal stuff - do not delete
+if (!$quiet) {
+    print "v2html version $version. See LICENCE.TXT for licence.\n";
+    print " Copyright 1998-2006 Costas Calamvokis\n";
+    print " Copyright 1997      Hewlett-Packard Company\n";
+}
+
+$style_sheet_link  =  "<link rel=\"Stylesheet\" title=\"v2html stylesheet\" ". 
+    "media=\"Screen\" href=\"$css\">\n";
+
+# set up the navbar
+$navbar{order} = [ ];
+if ( $output_hier ) {
+    push ( @{$navbar{order}} , ( 'Hierarchy' ) );
+}
+if ( $output_index ) { 
+    push ( @{$navbar{order}} , ( 'Files' , 'Modules' , 'Signals' , 'Tasks' , 'Functions' ));
+}
+push ( @{$navbar{order}} , ( 'Help' ) );
+# now set what each navbar item links to
+$navbar{Hierarchy} = $hier_file;
+($navbar{Files}    = $hier_file) =~ s/(\..*|)$/-f$1/;
+($navbar{Modules}  = $hier_file) =~ s/(\..*|)$/-m$1/;
+($navbar{Signals}  = $hier_file) =~ s/(\..*|)$/-s$1/;
+($navbar{Tasks}    = $hier_file) =~ s/(\..*|)$/-t$1/;
+($navbar{Functions}= $hier_file) =~ s/(\..*|)$/-fn$1/;
+$navbar{Help}      = "http://www.burbleland.com/v2html/help_7_30.html?$help_info";
+
+# check incremental
+if ($incremental) {
+    if (check_incremental($out_dir)) {
+	print "All html files are up to date, nothing to do.\n" unless $quiet;
+	exit 0;
+    }
+    print "Rebuilding all files\n" unless $quiet;
+}
+
+$verilog_db = &rvp::read_verilog(\@files,[],\%cmd_line_defines,
+				 $quiet,\@inc_dirs,\@lib_dirs,\@lib_exts);
+
+if ($output_index) {
+    print "Writing indexes\n" unless $quiet;
+    print_indexes($verilog_db,$js_hier);
+}
+
+# write the hierarchy (must be done after the indexes)
+if ($output_hier) {
+    print "Writing hierarchy to $hier_file\n" unless $quiet;
+    print_hier($hier_file,$js_hier,\@hier_tops);
+}
+
+# write the frames
+if ($frames) {
+    print "Writing frames to $frame_file\n" unless $quiet;
+    if ((@hier_tops)) {
+	print_frame_top($frame_file,$hier_file,join(", ",@hier_tops),
+			$js_hier,$vert_frames);
+    }
+    else {
+	print_frame_top($frame_file,$hier_file,$web_base,
+			$js_hier,$vert_frames);
+    }
+}
+
+# print out gif icons used 
+print_gifs($out_dir, ($cgi_script || $js_hier), $output_index );
+
+# print out the cascading style sheet
+print_css($out_dir);
+
+# convert each file
+foreach $file (&rvp::get_files($verilog_db)) {
+    convert(&rvp::get_files_full_name($verilog_db,$file));
+}
+
+# Write out a file list for incremental - we can not rely on the user provided
+#  one because we may have read more files finding modules and includes
+if ($incremental) {
+    write_filelist($verilog_db,$out_dir);
+}
+
+foreach my $problem (&rvp::get_problems($verilog_db)) {
+    if ( $problem !~ m/\n/ ) {
+	$problem =~ s/(.{60,79}) /$1\n    /g;
+    }
+    print "$problem.\n";
+}
+
+exit 0;
+
+###############################################################################
+#   Subroutines
+###############################################################################
+
+###############################################################################
+# initialize global variables
+#
+sub init {
+
+    @output_files=(); # stores a list of files we've written for incremental
+    $output_hier = 1;
+    $output_index = 1;
+    $hier_file = 'hierarchy.html';
+    $frame_file="frame.html";
+    $quiet     = 0;
+    $incremental = 0;
+    $maint     = '';
+    $frames      = 0;
+    $vert_frames = 0;
+    $frame_bottom = "";
+    $frame_middle = "";
+    $frame_code   = ""; # frame for jumping to code
+    $frame_top    = "";
+    $link_to_source = 0;
+    $cgi_script = "";
+    $web_base  = "";
+    $js_file = "";
+    $help_info = "";
+    $print_unconnected=1;
+    $print_no_mods=1;
+    $grey_ifdefed_out = 1;
+    $t_and_f_in_hier=0;
+    $compress=0;
+    $hier_comment = "";
+    @compress_cmd = ('compress', '-f');
+    $compress_extension = '.Z';
+    srand( time() ^ ( $$ + ( $$ << 15)));
+    $cgi_key= substr(rand,2,-1);
+    $tabstop=0;
+    @inc_dirs=('.');
+    @lib_dirs=('.');
+    @lib_exts=('');
+    $lines_per_file=1000;
+    $js_hier   =1; # javascript hierarchy
+    $js_sigs   =1; # javascript signals
+    $js_cookies=1; # javascript cookies
+    $css= 'v2html.css'; # default cascading style sheet name
+
+    $out_dir='./';
+
+    @verilog_keywords = (
+       qw(
+       always assign attribute begin case casex casez deassign default
+       defparam disable edge else end endattribute endcase endfunction
+       endmodule endprimitive endspecify endtable endtask event for force
+       forever fork function highz0 highz1 if initial join large macromodule
+       medium module negedge parameter posedge primitive pull0 pull1 release
+       repeat rtranif1 scalared small specify specparam strength strong0
+       strong1 table task trior use vectored wait weak0 weak1 while),
+       (@rvp::verilog_gatetype_keywords),
+       (@rvp::verilog_sigs),
+       qw(
+       config endconfig design instance liblist use library cell
+       generate endgenerate automatic));  # V2001
+
+    @verilog_keywords_hash{@verilog_keywords} = "" x @verilog_keywords;
+
+    @verilog_compiler_keywords_hash{@rvp::verilog_compiler_keywords} = 
+	"" x @rvp::verilog_compiler_keywords;
+
+
+    $version = '$Header: /home/cc/v2html/build/../RCS/v2html,v 7.30.1.3 2006/05/03 20:19:55 cc Exp $'; #'
+    $version =~ s/^\S+ \S+ (\S+) .*$/$1/;
+
+    # map from easy to remember names to the crytic class names used in html files
+    %classes = (comment=>'C', pp_ignore=>'P', string=>'S', compiler=>'M',
+		systemtask=>'ST', keyword=>'K', signal_input=>'SI',
+		signal_output=>'SO', signal_output_reg=>'SOR',
+		signal_inout_reg=>'SIOR', signal_inout=>'SIO', signal_reg=>'SR',
+		signal_integer=>'SIT', signal_wire=>'SW', signal_tri=>'STI',
+		signal_tri0=>'ST0', signal_tri1=>'ST1', signal_triand=>'STA',
+		signal_trireg=>'STR', signal_supply0=>'SS0',signal_trior=>'STO',
+		signal_supply1=>'SS1', signal_wand=>'SWA', signal_wor=>'SWO',
+		signal_time=>'STM', signal_realtime=>'SRT', signal_real=>'SRL', 
+		module=>'MM', task=>'T',
+		function=>'F', define=>'D', parameter=>'PA',
+		navbar=>'NB',
+		signal_genvar=>'GV', attribute=>'AT',  # V2001
+		);
+ 
+    # the regexp to find a mail address in a comment (for linking)
+    $mail_regexp='\b([^@ \t\n]+@[^@ \t\n\.]+\.[^@ \n\t]+)\b';
+    $http_regexp='\b(http:[^ \n\t]+)';
+
+    # a verilog identifier is this reg exp 
+    #  a non-escaped identifier is A-Z a-z _ 0-9 or $ 
+    #  an escaped identifier is \ followed by non-whitespace
+    #   why \\\\\S+ ? This gets \\\S+ in to the string then when it
+    #   it used we get it searching for \ followed by non-whitespace (\S+)
+    $VID = '[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+';
+
+    # icons for hierarchy when using javascript 
+    $icon_c = "<img align=bottom border=0 src=\"v2html-c.gif\">";
+    $icon_x = "<img align=bottom border=0 src=\"v2html-x.gif\">";
+    $icon_i = "<img align=top border=0 alt=\"Index\" src=\"v2html-i.gif\">";
+}
+
+###############################################################################
+#   Command line processing
+###############################################################################
+
+###############################################################################
+# Set up any variables as specified in the arg list.
+# Put input filenames in @files
+#
+sub process_args {
+    my ($f,$value,%files_seen);
+
+    # $#ARGV is the index of last arg. 
+    
+    @args=( @ARGV );
+
+    while ($_ = $ARGV[0]) {
+	shift(@ARGV);
+	if ( /^-debug$/ ) { 
+	    $debug = 1; 
+	    &rvp::set_debug();
+	    next;
+	    }
+	elsif ( /^-o$/ ) { 
+	    $out_dir = shift(@ARGV);
+	    $out_dir =~ s/[\/]?$/\//;
+	    next; 
+	    }
+	elsif ( /^-m$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $maint = shift(@ARGV);
+	    next; 
+	    }
+	elsif ( /^-ht$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    push(@hier_tops,shift(@ARGV));
+	    next; 
+	    }
+	elsif ( /^-h$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $hier_file = shift(@ARGV);
+	    next; 
+	    }
+	elsif ( /^-hc$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $hier_comment = shift(@ARGV);
+	    quote_html(\$hier_comment);
+	    next; 
+	    }
+	elsif ( /^-nh$/ ) { 
+	    $output_hier = 0;
+	    $help_info.='nh-';
+	    next; 
+	    }
+	elsif ( /^-htf$/ ) { 
+	    $t_and_f_in_hier=1;
+	    $help_info.='htf-';
+	    next; 
+	    }
+	elsif ( /^-nu$/ ) { 
+	    $print_unconnected = 0;
+	    $help_info.='nu-';
+	    next; 
+	    }
+	elsif ( /^-nnm$/ ) { 
+	    $print_no_mods = 0;
+	    $help_info.='nnm-';
+	    next; 
+	    }
+	elsif ( /^-ni$/ ) { 
+	    $grey_ifdefed_out = 0;
+	    $help_info.='ni-';
+	    next; 
+	    }
+	elsif ( /^-nindex$/ ) { 
+	    $output_index = 0;
+	    $help_info.='nindex-';
+	    next; 
+	    }
+	elsif ( /^-q$/ ) { 
+	    $quiet = 1;
+	    next; 
+	    }
+	elsif ( /^-i$/ ) { 
+	    $incremental = 1;
+	    $help_info.='i-';
+	    next; 
+	    }
+ 	elsif ( /^-c$/ ) { 
+	    &usage("$_ needs two arguments") if ($#ARGV < 1);
+	    $js_hier =0;
+ 	    $cgi_script = shift(@ARGV);
+ 	    $web_base  = shift(@ARGV);
+ 	    if (($cgi_script !~ m&^/&) || ($web_base   !~ m&^/&)) {
+ 		die "\nError: -c option must be followed by:\n".
+		    "   /path/cgi_script_name\n".
+		    "   /path_to_html_files\n".
+		    " relative web server's root (not file system root)\n\n";
+ 	    }
+ 	    $web_base =~ s|/$||;
+	    $help_info.='c-';
+ 	    next; 
+ 	    }
+	elsif ( /^-js$/ || /^-qs$/ || /^-nqs$/ ) { 
+	    print "Warning: obsolete option $_\n";
+	    # js hierarchy is now on by default - qs now wrapped into sigpopup
+	    next; 
+	    }
+	elsif ( /^-njshier$/ ) { 
+	    $js_hier = 0;
+	    $help_info.='njshier-';
+	    next; 
+	    }
+	elsif ( /^-nsigpopup$/ ) { 
+	    $js_sigs = 0;
+	    $help_info.='nsigpopup-';
+	    next; 
+	    }
+	elsif ( /^-ncookies$/ ) { 
+	    $js_cookies = 0;
+	    $help_info.='ncookies-';
+	    next; 
+	    }
+	elsif ( /^-s$/ ) { 
+	    $link_to_source = 1;
+	    $help_info.='s-';
+	    next; 
+	    }
+	elsif ( /^-z$/ ) { 
+	    $compress = 1;
+	    $help_info.='z-';
+	    next; 
+	    }
+	elsif ( /^-zc$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $_ = shift(@ARGV);
+	    @compress_cmd = split ;
+	    next; 
+	    }
+	elsif ( /^-ze$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $compress_extension = shift(@ARGV);
+	    next; 
+	    }
+	elsif ( /^-font$/ ) { 
+	    &usage if ($#ARGV < 0);
+	    $_ = shift(@ARGV);
+	    print "Warning -font option option is no longer supported ".
+		"edit cascading style sheet (v2html.css) instead\n";
+	    next; 
+	}
+	elsif ( /^-f$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    add_options_from_file(shift(@ARGV)); 
+	    next;
+	}
+	elsif ( /^-F$/ || /^-VF$/ ) { 
+	    $frames = 1;
+	    if ( /^-VF$/ ) {
+		$vert_frames = 1;
+		$help_info.='VF-';
+	    }
+	    else {
+		$help_info.='F-';
+	    }
+	    $frame_bottom = 'target="bottom"';
+	    $frame_middle = 'target="middle"';
+	    $frame_code   = 'target="middle"';
+	    $frame_top    = 'target="upper"';
+	    if ($#ARGV >= 0) { 
+		if ($ARGV[0] =~ m/.*\.html$/) {
+		    $frame_file = shift(@ARGV);
+		}
+	    }
+	    next; 
+	}
+	elsif ( /^-g$/ ) {
+	    print "Warning: obsolete option $_\n";
+	    $f = shift(@ARGV);
+	}
+	elsif ( /^-lines$/ ) {
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $lines_per_file = shift(@ARGV);
+	}
+	elsif ( /^\+define\+($VID)(?:(?:=)(.*))?$/o ) {
+	    # define with optional value (+define+NAME or +define+NAME=VALUE
+	    if ($2) {	
+		$cmd_line_defines{$1}=$2;
+	    }
+	    else {
+		$cmd_line_defines{$1}="";
+	    }
+	}
+	elsif ( /^-k$/ ) {
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $cgi_key = shift(@ARGV);
+	}
+	elsif ( /^-tab$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $tabstop = shift(@ARGV);
+	    next; 
+	    }
+	elsif ( /^-css$/ ) {
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    $css = shift(@ARGV);
+	}
+	elsif ( /^-y$/ ) { 
+	    &usage("$_ needs an argument") if ($#ARGV < 0);
+	    push(@lib_dirs,shift(@ARGV));
+	    next; 
+	    }
+	elsif ( /^\+incdir\+(.+)$/ ) { 
+	    push(@inc_dirs,split(/\+/,$1));
+	    next; 
+	    }
+	elsif ( /^\+libext\+(.+)$/ ) { 
+	    push(@lib_exts,split(/\+/,$1));
+	    next; 
+	    }
+	elsif ( /^-exp$/ ) { 
+	    print "Warning: obsolete option -exp (defines are always expanded)\n";
+	    next; 
+	    }
+	else {
+	    if ( /^-v$/ ) { # -v file is exactly the same as file without -v
+		&usage("$_ needs an argument") if ($#ARGV < 0);
+		$_=shift(@ARGV);
+	      }
+	    my @fglobbed;
+	    if (-r $_) { @fglobbed = ("$_"); }
+	    else       { @fglobbed = glob($_); }
+	    if ( 1 == @fglobbed && ! -r $fglobbed[0] ) { # arg didn't expand & is not readable as a file
+	      # try it as a VCS/verilog with no parameters
+	      if (/^-([BCIMRSVu])|(Mupdate)|(ID)|(O0)|(PP)|(RI)|(RIG)|(RPP)$/ ||
+		  /^-(line)|(lmc-hm)|(lmc-swif)|(location)|(platform)$/ ||
+		  /^-(p[a-zA-Z0-9]+)$/ ||
+		  /^\+.*$/ ) {
+		print "Warning: ignoring VCS/verilog option $_\n" unless $quiet;
+		next;
+	      }
+	      # try it as a VCS/verilog with one parameter
+	      if (/^-([jJlPL])|(ASFLAGS)|(CC)|(CFLAGS)|(LDFLAGS)|(as)$/ ||
+		  /^-(cc)|(grw)|(ld)|(syslib)|(vcd)$/) {
+		$value = $_ ." ". shift(@ARGV);
+		print "Warning: ignoring VCS/verilog option $value\n" 
+		  unless $quiet;
+		next;
+	      }
+	      # report an error: if it doesn't look like a bad option
+	      #   report it as an unreadable file
+	      if ( /^[-+]/ ) { &usage("Unrecognized option: $_"); }
+	      else        { &usage("Verilog file $_ is not readable"); }
+	    }
+	    else {
+	      # Must be a file
+	      foreach $f ( @fglobbed ) { 
+		if ( -r $f ) { # see if it is readable
+		  if (exists($files_seen{$f})) {
+		    print "Warning: ignoring duplicate file on command line $f\n";
+		  }
+		  else {
+		    push(@files,$f);
+		  }
+		  $files_seen{$f}=1;
+		}
+		else {
+		  &usage("Verilog file $_ is not readable");
+		}
+	      }
+	    }
+	  }
+    }
+
+    &usage("No verilog files specified") if (@files == 0);
+
+    die "\nError: You can not use Javascript and CGI at the same time\n\n"
+	if ($js_hier && $cgi_script);
+
+    $frame_code = 'target="_top"' if ($js_hier && !$frames);
+
+
+}
+
+###############################################################################
+# show usage
+#
+sub usage {
+    my ($msg) = @_;
+
+    print "\nError: $msg\n";
+    print <<EOF;
+
+usage: v2html [options] file1 [file2] ...
+
+Verilog like options:
+
+  +define: Specify a define for use when processing, can be either:
+            +define+NAME or +define+NAME=VALUE
+  +incdir: Specify a directory to search for includes +incdir+DIR_NAME
+  -y     : Specify a library to search for modules eg: -y DIR_NAME
+  +libext: Specify a the extension for libraries eg: +libext+.v or +libext+.v+.V
+  -v     : Specify a library file (same as putting the file without -v)
+
+options:
+ -f        : file to read options and file names from
+ -o        : output directory for html files (default: current directory).
+ -q        : be quiet.
+ -m        : mail address for site maintainer.
+ -F        : generate output using three frames - default output is frame.html
+             you can change this by putting a file name (with .html extension
+             after the -F option)
+ -VF       : same as -F but does vertical frames with the hierarchy down the side
+ -i        : incremental - check dates of files, if all .v.html files are newer
+              than their .v files then do nothing, otherwise convert them all.
+ -ht       : specify a top module to print the hierarchy for (the default
+             is to do all hierarchies found in the input files) multiple
+             -ht options can be specified.
+ -htf      : print tasks and functions in the hierarchy
+ -hc       : a comment to print at the top of the hierarchy
+ -nh       : skip writing the hierarchy.
+ -nindex   : skip writing the indexes.
+ -nu       : skip writing the list of unconnected modules in the hierarchy
+ -nnm      : skip writing the list of files with no modules in the hierarchy
+ -ni       : do not 'grey out' code that is ifdefed out
+ -s        : link to the source (in footer of each page) only works if:
+             - your web server has access to the source code
+             - you run v2html in the output directory or use absolute
+               path names for the verilog
+ -njshier  : turn off Javascript hierarchy generation.
+ -ncookies : turn off Javascript cookies (for remembering js hierarchy state)
+ -nsigpopup: turn off Javascript signal popup window.
+ -css      : specify a URL for the cascading style sheet to use
+ -z        : compress html files
+ -zc       : compress command to use (default is compress)
+ -ze       : extension of compressed files (default is .Z)
+ -tab      : set tabstop to specified value
+ -lines    : lines per html page (big files are split across multiple pages)
+ -c        : activate CGI features (expanding of hierarchy) - to use this 
+             you must have the v2html CGI script on your webserver - see man page.
+ -k        : key to use for hierarchy CGI (default is to use a random one)
+ -h        : name of file to write the hierarchy to (default: hierarchy.html).
+ -debug    : useless info for debugging
+
+Ignored options:
+ 
+  most VCS options (the only conflicts with v2html options are -o -s and -i)
+  all +options not mentioned above
+
+example:
+  v2html -hc "Our Chip" -o /users/www/p/html -m Joe_Blogs\@jb.com
+     +incdir+/p/includes -y /p/verilog +libext+.v+.V /p/verilog/chip_top.v
+
+See http://www.burbleland.com/v2html/v2html.html for more details
+
+EOF
+
+    exit 1;
+
+} #'
+
+###############################################################################
+# The argument specifies a file that contains arguments - exactly the
+#  same as on the command line
+# comments are # or // you can quote things like this: -zc 'gzip -f'
+#
+sub add_options_from_file {
+    my ($file) = @_;
+    my (@args_found,$text_s);
+    
+    open(F,"<$file") || usage("can not open $file to read arguments");
+    $/ = undef;
+    $text_s = <F>;
+    $/ = "\n";
+    close(F);
+
+    while ($text_s =~ m%((?:/\*.*?\*/)|(?://[^\n]*(?:\n|\Z))|(?:#[^\n]*\n)|(?:'[^']*')|(?:"[^"]*")|(?:\S+))%gs )
+    {   #'){ get emacs mode back in sync!
+	$_ = $1;
+	if ( m%((?:/\*.*?\*/)|(?://[^\n]*(?:\n|\Z)))%s ) { # comment, chuck it 
+	    print " cmdfile: chucking comment :|$_|\n" if $debug;
+	}
+	elsif ( m/^['"]/ ) {        # "']{
+	    s/\A.//;
+	    s/.\Z//;
+	    print " cmdfile: found string |$_|\n" if $debug;
+	    push(@args_found,$_);
+	}
+	else {
+	    print " cmdfile: found word |$_|\n" if $debug;
+	    push(@args_found,$_);
+	}
+    }
+
+    unshift( @ARGV, @args_found );
+    push( @args , @args_found );
+}
+
+###############################################################################
+#   Misc functions
+###############################################################################
+
+###############################################################################
+# given a source file name work out the .html file name
+#  without the path
+#
+sub hfile {
+    my ($sfile,$sline) = @_;
+    my ($page);
+
+    # debugging checks
+    # die "No line passed to hfile!\n" unless defined($sline);
+    # die  "bad sline: $sline\n" unless $sline=~m/^[0-9-]+$/;
+
+    # NB sline starts at 1
+    $page = ($sline <= $lines_per_file) ? '' : 
+	".p" . (1+int(($sline-1)/$lines_per_file));
+    $sfile  =~ s/^.*[\/\\]//;
+    $sfile .= "$page.html";
+    $sfile .= $compress_extension if $compress;
+
+    return $sfile;
+}
+
+###############################################################################
+# given a source file name work out the file without the path
+#
+sub ffile {
+    my ($sfile) = @_;
+
+    $sfile =~ s/^.*[\/\\]//;
+
+    return $sfile;
+}
+
+###############################################################################
+# Check whether we need to rebuild - delete any old files if we do
+#
+sub check_incremental {
+    my ($out_dir) = @_;
+    my ($incr_file,$filelist,$rebuild,@old_input_files,@old_output_files,@old_args,
+	$file,$mtime,$mtime_s,$mtime_o,$section);
+    local(*F);
+
+    $incr_file="$out_dir.v2html_incr";
+
+    $rebuild=0;
+    if ( ! -r $incr_file ) {
+	print "Could not find file list $incr_file\n" unless $quiet;
+	$rebuild= 1;
+    }
+    
+    # read the incremental file, and check that the options match
+    if ($rebuild==0) {
+	open(F,"<$incr_file") || die "can not open $filelist read to file list";
+	$section=1;
+	# Read incr file, be quite careful, as anything read into old_output_files 
+	#  can get deleted
+	while (<F>) { 
+	    chomp; 
+	    if (m/^---output files/) {
+		if ($section==1) {
+		    $section++;
+		}
+		else {
+		    print "Corrupt incremental file $out_dir.v2html_incr, remove and retry\n"; 
+		    exit;
+		}
+	    }
+	    elsif (m/^---options/) {
+		if ($section==2) {
+		    $section++;
+		}
+		else {
+		    print "Corrupt incremental file $out_dir.v2html_incr, remove and retry\n"; 
+		    exit;
+		}
+	    }
+	    else {
+		if    ($section==1) { push(@old_input_files,$_);  }
+		elsif ($section==2) { push(@old_output_files,$_); }
+		elsif ($section==3) { push(@old_args,$_); }
+	    }
+	}
+	if ($section!=3) {
+	    print "Corrupt incremental file $out_dir.v2html_incr, remove and retry\n"; exit;
+	}
+
+	if ("@args" ne "@old_args") {
+	    print "Arguments are different\n" unless $quiet;
+	    $rebuild=1;
+	}
+    }
+    if ($rebuild==0) {
+	$mtime_s=$mtime_o=0;
+	# find the newest source file
+	foreach $file (@old_input_files) {
+	    if ( -r $file ) {
+		$mtime   = (stat( $file ))[9];
+		$mtime_s = ($mtime>$mtime_s) ? $mtime : $mtime_s;
+	    }
+	    else {
+		print "Source file $file has gone\n" unless $quiet;
+		$rebuild=1;
+		last;
+	    }
+	}
+	# find the oldest output file
+	foreach $file (@old_output_files) {
+	    if ( -r $file ) {
+		$mtime   = (stat( $file ))[9];
+		$mtime_o = (($mtime<$mtime_o)||($mtime_o==0)) ? $mtime : $mtime_o;
+	    }
+	    else {
+		print "Output file $file has gone\n" unless $quiet;
+		$rebuild=1;
+		last;
+	    }
+	}
+    }
+
+    if ($rebuild==0) {
+	if ($mtime_o < $mtime_s ) {
+	    print "Some source files are newer than the output files\n"
+		unless $quiet;
+	    $rebuild=1;
+	}
+	elsif ($mtime_o < (stat( $0 ))[9]) {
+	    print "Some output files are older than $0\n"
+		unless $quiet;
+	    $rebuild=1;
+	}
+    }
+
+    # Need to remove files produced on the last run to stop junk accumulating
+    #  in the output dir (now that multiple pages
+    if ($rebuild) {
+	print "Removing old output files\n" unless $quiet;
+	foreach $file (@old_output_files) {
+	    if ( $file =~ m/\.html/ ) {
+		unlink($file);
+	    }
+	    else {
+		print "Warning: skipping remove of $file (does not end in .html)\n";
+	    }
+	}
+    }
+
+    return ($rebuild==0);
+}
+
+###############################################################################
+# Write out the files read for incremental compiles
+#
+sub write_filelist {
+    my ($fdata,$out_dir)= @_;
+    my ($file,$opt);
+    local (*F);
+
+    open(F,">$out_dir.v2html_incr") || die "Could not write to $out_dir.v2html_incr";
+
+    foreach $file (sort &rvp::get_files($verilog_db)) {
+	print F &rvp::get_files_full_name($verilog_db,$file) . "\n";
+    }
+
+    print F "---output files\n";
+    foreach $file (@output_files) {
+	print F "$file\n";
+    }
+
+    print F "---options\n";
+    foreach $opt (@args) {
+	print F "$opt\n";
+    }
+    close(F);
+}
+
+
+
+###############################################################################
+# Print out the footer
+#  arguments: $out: output file handle
+#              $src: name of source file (to put in footer)
+#              $js:  flag telling it whether to print it, or
+#                     to generate javascript to print it
+sub print_footer {
+    my ($out,$src,$narrow,$js) = @_;
+
+
+    print_h_or_js($out,"<hr>\n",$js);
+    print_h_or_js($out,"<table>\n <tr><td><i>This page:<\/i><\/td>\n",$js);
+
+    print_h_or_js($out,"<td> </td></tr><tr>\n",$js) if $narrow;
+
+    if ($maint ne '') {
+	print_h_or_js($out,"  <td><i>Maintained by:<\/i><\/td>\n",$js);
+	print_h_or_js($out,"  <td><i><a href=\"mailto:" . $maint . "\">\n",$js);
+	print_h_or_js($out,"  " . $maint . "<\/a><\/i><\/tr>\n<tr>\n",$js);
+	print_h_or_js($out,"<td> </td>\n",$js) if !$narrow;
+    }
+
+    print_h_or_js($out,"  <td><i>Created:<\/i><\/td><td><i>" . 
+	localtime() . "<\/i><\/td><\/tr>\n",$js);
+    
+    if ($src ne '') {
+	print_h_or_js($out,"<tr>\n",$js);
+	print_h_or_js($out," <td> </td>\n",$js) if !$narrow;
+	print_h_or_js($out," <td><i>From:<\/i><\/td><td><i>\n",$js);
+
+	if ($link_to_source) {
+	    print_h_or_js($out,"  <a href=\"" . $src . "\">\n",$js);
+	    quote_html(\$src);
+	    print_h_or_js($out,$src . "<\/a>",$js);
+	}
+	else {
+	    quote_html(\$src);
+	    print_h_or_js($out,$src,$js);
+	}
+	print_h_or_js($out, "<\/i><\/td><\/tr>\n",$js);
+    }
+
+    print_h_or_js($out,"</table>\n<hr>\n",$js);
+
+    ##################################################################
+    #             Do not alter any of this footer information        #
+    ##################################################################
+    print_h_or_js($out,'<table width="100%"><tr><td><i>Verilog converted to html by ',$js);
+    print_h_or_js($out,' <a target="_top" '.
+		  'href="http://www.burbleland.com/v2html/v2html.html">',$js);
+    print_h_or_js($out,"  v2html $version<\/a> \n",$js);
+    print_h_or_js($out," (written by",$js);
+    print_h_or_js($out," <a href=\"mailto:v2html730\@burbleland.com\">",$js);
+    print_h_or_js($out,"Costas Calamvokis<\/a>).<\/i></td>",$js);
+    print_h_or_js($out,'<td align="right"><b>'.
+		  '<a href="http://www.burbleland.com/v2html/help_7_30.html?'.
+		  $help_info.'">Help</a></b></td>',$js) if !$narrow;
+    print_h_or_js($out,'</tr></table>',$js);
+    ##################################################################
+    #                    End of footer information                   #
+    ##################################################################
+
+    # put a big blank table (90% of the size of the window) at the
+    # bottom of the page to make it scroll better
+    print_h_or_js($out, "<table height=\"90%\"><tr><td></td></tr></table>\n" , $js);
+}
+
+
+###############################################################################
+#   Print out a navigation bar
+###############################################################################
+
+sub print_navbar {
+    my ($out,$js,$type,$data,$prevnext,$prevnext_file,$narrow) = @_;
+    my ($elem,$col,$elem_num);
+
+    $col = @{$data->{order}};
+
+    # skip hierarchy if frames are on - it'll always be in top frame
+    if ($frames) {
+	foreach $elem (@{$data->{order}}) {
+	    $col-- if $elem eq 'Hierarchy';
+	}
+    }
+
+    if ($type eq 'Hierarchy' && ($cgi_script||$js_hier)) {
+	$col+=2; # put in two extra buttons for the show all/hide all
+    }
+
+
+    # prev next takes an extra column
+    $col++ if $prevnext;
+
+    return unless ($col);
+
+    my $width = $narrow ? 33 : int(100/$col);
+
+    my $td_code="<td align=\"center\" width=\"$width\%\" ".
+           "onmousedown=\"this.style.border=\\'inset\\';\" ". 
+	       "onmouseup=\"this.style.border=\\'outset\\';\" ";
+
+    # if we are framed then we can't just set location when a table
+    #  element is clicked, have to set parent.middle.location to put
+    #  code into the middle frame, and 
+    my $frame_code_js;
+    my $frame_top_js;
+    ($frame_code_js = $frame_code) =~ s/^.*"(.*)".*$/parent.$1./;
+    $frame_code_js="" if $frame_code_js =~ m/_top/;
+    ($frame_top_js  = $frame_top)  =~ s/^.*"(.*)".*$/parent.$1./;
+
+
+    print_h_or_js($out,"<center><table class=$classes{navbar} cols=$col ".
+		  "><tr>",$js);
+
+
+    if ($prevnext) {
+	print_h_or_js($out,"$td_code onclick=\"${frame_code_js}location=\\'$prevnext_file\\';\">".
+		      "<a $frame_code href=\"$prevnext_file\">$prevnext</a></td>",
+		      $js);
+    }
+    $elem_num=0;
+    foreach $elem (@{$data->{order}}) {
+	if ($type eq 'Hierarchy' && $elem eq 'Hierarchy') {
+	    if ($cgi_script) {
+		print_h_or_js($out,"$td_code onclick=\"${frame_top_js}location=\\'$cgi_script$web_base/?k=$cgi_key&x=C&in=$hier_file&f=$frames\\';\"><a $frame_top " . 
+		    "href=\"$cgi_script$web_base/?k=$cgi_key&x=C&in=$hier_file&f=$frames\">" .
+			"Hide All</a></td>\n",0);
+		print_h_or_js($out,"$td_code onclick=\"${frame_top_js}location=\\'$cgi_script$web_base/?k=$cgi_key&x=A&in=$hier_file&f=$frames\\';\"><a $frame_top " . 
+		    "href=\"$cgi_script$web_base/?k=$cgi_key&x=A&in=$hier_file&f=$frames\">" .
+			"Show All</a></td>\n",0);
+		$elem_num+=2;
+	    }
+	    if ($js_hier && $js) {
+		print_h_or_js($out,"$td_code onclick=\"javascript:parent.printIt(\\'C\\',-1)\">".
+			      "<a href=\"javascript:parent.printIt(\\'C\\',-1);\">".
+			      "Hide All</a></td>\n",1);
+		print_h_or_js($out,"$td_code onclick=\"javascript:parent.printIt(\\'A\\',-1);\">".
+			      "<a href=\"javascript:parent.printIt(\\'A\\',-1)\">".
+			      "Show All</a></td>\n",1);
+		$elem_num+=2;
+	    }
+	}
+	# skip hierarchy if frames are on - it'll always be in top frame
+	next if (($elem eq 'Hierarchy') && $frames);
+	if ($narrow && ($elem_num!=0) && (($elem_num%3)==0)) {  
+	    print_h_or_js($out,"</tr><tr>",$js); 
+	}
+	$elem_num++;
+	if ( $elem eq $type ) {
+	    print_h_or_js($out,"$td_code>".
+			  "<font color=\"#808080\">$elem</font></td>",$js);
+	}
+	else {
+	    my $i = $data->{$elem};
+	    $i =~ s|\\|\\\\|;
+	    print_h_or_js($out,"$td_code onclick=\"${frame_code_js}location=\\'$i\\';\">".
+			  "<a $frame_code href=\"$data->{$elem}\">$elem</a></td>",
+			  $js);
+	}
+    }
+
+    print_h_or_js($out,"<\/tr><\/table><\/center>\n",$js);
+
+}
+
+###############################################################################
+#   Index printing
+###############################################################################
+
+###############################################################################
+# Collect the data and print all indexes
+#
+sub print_indexes {
+    my ($fdata,$js) = @_;
+
+    my (@files,@modules,@signals,@tasks,@functions,$m,$sig,$tf,$t_type,$indl);
+
+    # this stores the mapping between index letter and index file name
+    #  for each of the indexes, as well as the nav bar
+    $index_info = {};
+
+    # approx line count we'd like for an index, divide be expected lines
+    #  per entry to give number of elements per index that we need to
+    #  call print index
+    $indl = 1000; 
+
+    @files = &rvp::get_files($fdata);           # get the files
+    @modules = &rvp::get_modules($fdata);       # get the modules
+
+    # get the signals
+    @signals = ();
+    foreach $m (&rvp::get_modules($fdata)) {
+	foreach $sig (&rvp::get_modules_signals($fdata,$m)) {
+	    push (@signals,"$sig $m");
+	}
+    }
+
+    # get the tasks and functions
+    @tasks = @functions = ();
+    foreach $m (&rvp::get_modules($fdata)) {
+	foreach $tf (&rvp::get_modules_t_and_f($fdata,$m)) {
+	    ($t_type)=&rvp::get_modules_t_or_f($fdata,$m,$tf);
+	    if ($t_type eq 'task') {  push (@tasks,"$tf $m");     }
+	    else {                    push (@functions,"$tf $m"); }
+	}
+    }
+
+    # sort and split them across files
+    $index_info->{Files}    = calc_index($fdata,$navbar{Files},\@files, $indl/4);
+    $index_info->{Modules}  = calc_index($fdata,$navbar{Modules},\@modules,$indl/8);
+    $index_info->{Signals}  = calc_index($fdata,$navbar{Signals},\@signals, $indl/20);
+    $index_info->{Tasks}    = calc_index($fdata,$navbar{Tasks},\@tasks, $indl/3);
+    $index_info->{Functions}= calc_index($fdata,$navbar{Functions},\@functions, $indl/3);
+
+    # now print all the indexes
+    print_index($fdata,$index_info->{Files},'Files',\@files,\&print_file_index);
+    print_index($fdata,$index_info->{Modules},'Modules',\@modules,\&print_module_index);
+    print_index($fdata,$index_info->{Signals},'Signals',\@signals,\&print_signal_index);
+    print_index($fdata,$index_info->{Tasks},'Tasks',\@tasks,\&print_tf_index);
+    print_index($fdata,$index_info->{Functions},'Functions',\@functions,\&print_tf_index);
+}
+
+###############################################################################
+# calculate all sorts of stuff about the index (also sorts the data)
+#  returns a hash for the that is stored in $index_info->{type}
+#
+sub calc_index {
+    my ($fdata,$fname, $data, $items_per_index) = @_;
+    my ($first_char,$elem_first_char,$info,$page,$ofile,$i,$items);
+
+    # do a case insensitive sort (but make sure it is determinate if the
+    #  items only differ in case)
+    @{$data} = sort { (uc($a) ne uc($b)) ? uc($a) cmp uc($b)  : 
+		                           $a cmp $b            } @{$data};
+
+    # work out the indexes
+    $first_char=""; # make sure it will not match
+    $page=$items=0;
+
+    $info            = {};
+    $info->{nb}        = {}; # navbar, labels and links eg {A}='hierarchy-fn#index--A'
+    $info->{nb}{order} = []; #  the navbar order, array of other keys (A,B...)
+    $info->{letters}   = {}; # hash mapping start letters to index files
+    $info->{pages}     = 0;  # number of pages
+    $info->{files}     = []; # array of hashes { name, start, end } indexed 1,2...
+
+    for ($i=0;$i<scalar(@{$data});$i++) {
+ 	$elem_first_char=uc(substr($data->[$i],0,1));
+	if ($elem_first_char ne $first_char) {
+	    if ($items==0 || $items_per_index<$items) {
+		if ($page) { $info->{files}[$page]{end} = $i; }
+		$page++;
+		$ofile=$fname;
+		$ofile =~ s/.html$/.p$page.html/ if ($page != 1);
+		$info->{files}[$page] = { name => $ofile, start => $i};
+		$items=0;
+	    }
+	    $info->{letters}{$elem_first_char} = $ofile;
+	    $first_char=$elem_first_char;
+	    push(@{$info->{nb}{order}},$first_char);
+	    $info->{nb}{$first_char} = "$ofile#index--$first_char";
+	}
+	$items++;
+    }
+    if ($page) {
+	$info->{pages}=$page;
+	$info->{files}[$page]{end} = $i;
+    }
+    else { # handle case where there was no data
+	$info->{pages}=1;
+	$info->{files}[1] = { name => $fname , start => 0 , end => 0 };
+    }
+    return $info;
+}
+
+###############################################################################
+# Print one index - calls out to printfn to print each entry
+#
+sub print_index {
+    my ($fdata,$info, $type, $data, $printfn) = @_;
+    my ($i,$first_char,$elem_first_char,$page,$ofile);
+    local (*OUT);
+
+
+    for ($page=1;$page<=$info->{pages};$page++) {
+	$ofile=$info->{files}[$page]{name};
+	
+	open(OUT,">$out_dir$ofile") || 
+	    die "Error: can not open file $out_dir$ofile to write: $!\n";
+	push(@output_files,"$out_dir$ofile");
+	print OUT "<!-- v2html $type index  -->\n";
+	print OUT "<html><head>\n";
+	print OUT "<title>$type index".(($page==1)?"":" page $page")."</title>\n";
+	print OUT $style_sheet_link;
+	print OUT "</head>\n";
+
+	if ($js_sigs) {
+	    # dummy function in case someone tries to do a search in the index 
+	    print OUT "<script language=\"JavaScript\" type=\"text\/javascript\"><!--\n";
+	    print_js_common(*OUT);
+	    print OUT "function search ()     { return false; }\n";
+	    print OUT "// -->\n";
+	    print OUT "</script>\n";
+	}
+
+	print OUT "<body>\n";
+	
+	print OUT "<a name=\"top_of_page\"></a>\n";
+
+	if ($page==1) { print_navbar(*OUT,0,$type,\%navbar,'','',0); }
+	else          { print_navbar(*OUT,0,$type,\%navbar,"Prev Page",
+				     $info->{files}[$page-1]{name}.'#bottom_of_page',
+				     0); }
+	print_navbar(*OUT,0,'',$info->{nb},'','',0);
+	print OUT "<center><h3>$type index</h3></center>\n";
+	
+	$first_char=""; # make sure it will not match 
+	
+	for ($i=$info->{files}[$page]{start};$i<$info->{files}[$page]{end};$i++) {
+	    $elem_first_char=uc(substr($data->[$i],0,1));
+	    if ($elem_first_char ne $first_char) {
+		$first_char=$elem_first_char;
+		print OUT "<a name=\"index--$first_char\"></a>\n";
+		print_navbar(*OUT,0,'',
+			     { order=>[$first_char], $first_char=>"#top_of_page"},
+			     '','',0);
+	    }
+	    &{$printfn}(*OUT,$fdata,$data->[$i]);
+	}
+	
+	print_navbar(*OUT,0,'',$info->{nb},'','',0);
+	if ($page==$info->{pages}) { print_navbar(*OUT,0,$type,\%navbar,'',''); }
+	else          { print_navbar(*OUT,0,$type,\%navbar,"Next Page",
+				     $info->{files}[$page+1]{name},0); }
+	print_footer(*OUT,'',0,0);
+	print OUT "</body>\n";
+	print OUT "</html>\n";
+	close(OUT);
+    }
+
+}
+
+###############################################################################
+# Called to print on entry in the file index
+#
+sub print_file_index {
+    my ($out,$fdata,$data) = @_;
+    my ($m,$ms,$qword,$title,$inc,$i,$comma,$inc_by);
+
+    $title  = "<b><a name=\"$data\"></a>".
+	"<a $frame_middle href=\"".hfile($data,1)."\">$data</a></b>\n";
+
+    $ms=$comma='';
+    foreach $m (sort &rvp::get_files_modules($fdata,$data)) {
+	$qword = $m; quote_html(\$qword);
+	if (&rvp::module_exists($fdata,$m)) {
+	    $ms .= "$comma<a href=\"".index_link("Modules",$m)."\">$qword</a>&nbsp;";
+	}
+	else { $ms .= "$comma$qword&nbsp;"; }
+	$comma=', ';
+    }
+
+    $inc=$comma='';
+    foreach $i (sort &rvp::get_files_includes($fdata,$data)) {
+	$qword = $i; quote_html(\$qword);
+	if (&rvp::file_exists($fdata,$i)) {
+	    $inc .= "$comma<a href=\"".index_link("Files",$i)."\">$qword</a>&nbsp;";
+	}
+	else { $inc .= "$comma$qword&nbsp;"; }
+	$comma=', ';
+    }
+
+    $inc_by=$comma='';
+    foreach $i (sort &rvp::get_files_included_by($fdata,$data)) {
+	$qword = $i; quote_html(\$qword);
+	if (&rvp::file_exists($fdata,$i)) {
+	    $inc_by .= "$comma<a href=\"".index_link("Files",$i)."\">$qword</a>&nbsp;";
+	}
+	else { $inc_by .= "$comma$qword&nbsp;"; }
+	$comma=', ';
+    }
+
+    print_itable( $out , $title  ,
+		 [ "Full name:"  , &rvp::get_files_full_name($fdata,$data) ,
+		   "Modules:"    , $ms  ,
+		   "Includes:"   , $inc ,
+		   "Included by:", $inc_by ]);
+
+}
+
+###############################################################################
+# Called to print on entry in the module index
+#
+sub print_module_index {
+    my ($out,$fdata,$data) = @_;
+    my ($qword,$title,$inst,$m,$f,$i,$file,$inst_by,$tasks,$funcs,@t_and_f,$tf,$t_type,
+	$comma,$fcomma,$m_line,$type);
+
+    ($file,$m_line)=&rvp::get_modules_file($fdata,$data);
+    $type=&rvp::get_modules_type($fdata,$data);
+    $qword=$data; quote_html(\$qword);
+    $title  = "<b><a name=\"$data\"></a>".
+	"<a $frame_middle href=\"".
+	    hfile($file,$m_line)."#$data\">$qword</a></b>\n";
+    $title .= "<i>($type)</i>\n" unless $type eq 'module';
+
+    $inst=$comma='';
+    ($m,$f,$i) = &rvp::get_first_instantiation($fdata,$data );
+    while ($m) {
+	if (&rvp::module_exists($fdata,$m)) {
+	    $inst.="$comma<a href=\"".index_link("Modules",$m)."\">$m:$i</a>&nbsp;";
+	}
+	else {
+	    $inst.="$comma$m:$i&nbsp;";
+	}
+	$comma=', ';
+	($m,$f,$i) = &rvp::get_next_instantiation($fdata);
+    }
+
+    $inst_by=$comma='';
+    ($m,$f,$i) = &rvp::get_first_instantiator($fdata,$data );
+    while ($m) {
+	if (&rvp::module_exists($fdata,$m)) {
+	    $inst_by.="$comma<a href=\"".index_link("Modules",$m)."\">$m:$i</a>&nbsp;";
+	}
+	else {
+	    $inst_by.="$comma$m:$i&nbsp;";
+	}
+	$comma=', ';
+	($m,$f,$i) = &rvp::get_next_instantiator($fdata);
+    }
+
+
+    $tasks=$funcs=$comma=$fcomma='';
+    if ( @t_and_f = &rvp::get_modules_t_and_f($fdata,$data) ) {
+	foreach $tf (sort @t_and_f) {
+	    ($t_type)=&rvp::get_modules_t_or_f($fdata,$data,$tf);
+	    if ($t_type eq 'function') { 
+		$funcs.="$fcomma<a href=\"".index_link("Functions","${tf}___$data").
+		    "\">$tf<\/a>&nbsp;";  
+		$fcomma=', ';
+	    }
+	    else { 
+		$tasks.="$comma<a href=\"".index_link("Tasks","${tf}___$data").
+		    "\">$tf<\/a>&nbsp;";
+		$comma=', ';
+	    }
+	}
+    }
+
+
+    print_itable( $out , $title ,
+		 [ "File:" , "<a href=\"".index_link("Files",$file)."\">$file</a>" .
+		            ((&rvp::module_ignored($fdata,$data)) ?
+                              " (Warning: Duplicate definition found)" : "") ,
+		   "Instantiates:" , $inst ,
+		   "Instantiated by:" , $inst_by,
+		   "Tasks:"           , $tasks , 
+		   "Functions:"       , $funcs ]);
+
+}
+
+###############################################################################
+# Called to print on entry in the Signal index
+#
+sub print_signal_index {
+    my ($out,$fdata,$data) = @_;
+    my ($qword,$sig,$m,$title,$s_line,$s_i_line,$s_type,$s_file,
+	$s_pos,$s_neg,$s_type2,$im,$in,$p,$port_con,$comma,$con_to,$cts,$cti,$ctm);
+
+    ($sig,$m) = split(' ',$data);
+
+    ($s_line,undef,$s_i_line,$s_type,$s_file,$s_pos,$s_neg,$s_type2) = 
+	&rvp::get_module_signal($fdata,$m,$sig);
+    $s_type.=" $s_type2" if $s_type2;
+    $s_type.=" (used in \@posedge)" if $s_pos;
+    $s_type.=" (used in \@negedge)" if $s_neg;
+
+    $qword="$sig : $m"; quote_html(\$qword);
+    $title  = "<b><a name=\"$sig"."___$m\"></a>".
+	"<a $frame_middle href=\"".
+	    hfile($s_file,$s_line)."#$s_line\">$qword</a></b> : $s_type";
+
+    $port_con=$comma='';
+    ($im,$in,$p,)=&rvp::get_first_signal_port_con($fdata,$m,$sig);
+    while ($im) {
+	if (&rvp::module_exists($fdata,$im) && ($p !~ m/^[0-9]/)) {
+	    $port_con.="$comma<a href=\"".index_link("Signals","${p}___$im")."\">$im:$in:$p</a>&nbsp;";
+	}
+	else { $port_con.="$comma$im:$in:$p&nbsp;"; }
+	$comma=', ';
+	($im,$in,$p,)=&rvp::get_next_signal_port_con($fdata);
+    }
+    
+    $con_to=$comma='';
+    ($cts,$ctm,$cti)=&rvp::get_first_signal_con_to($fdata,$m,$sig);
+    while ($cts) {
+	if (&rvp::module_exists($fdata,$ctm) && ($cts !~ m/^[0-9]/)) {
+	    $con_to.="$comma<a href=\"".index_link("Signals","${cts}___$ctm")."\">$ctm:$cti:$cts</a>&nbsp;";
+	}
+	else { $con_to.="$comma$ctm:$cti:$cts&nbsp;"; }
+	$comma=', ';
+	($cts,$ctm,$cti)=&rvp::get_next_signal_con_to($fdata);
+    }
+
+    # Only print table if there are some portcons to save space
+    if ($port_con || $con_to) {
+	print_itable( $out , $title ,
+		      [ "Connects down to:" , $port_con ,
+		        "Connects up to:" , $con_to ]);
+    }
+    else {
+	print_itable( $out , $title , []);
+    }
+
+}
+
+###############################################################################
+# Called to print on entry in the Tasks or Functions index
+#
+sub print_tf_index {
+    my ($out,$fdata,$data) = @_;
+    my ($qword,$tf,$m,$title,$t_type,$t_line ,$t_file,$t_anchor);
+
+    ($tf,$m) = split(' ',$data);
+
+    ($t_type,$t_line ,$t_file,$t_anchor)=&rvp::get_modules_t_or_f($fdata,$m,$tf);
+
+
+    $qword="$tf"; quote_html(\$qword);
+    $title  = "<b><a name=\"$tf"."___$m\"></a>".
+	"<a $frame_middle href=\"".
+	    hfile($t_file,$t_line)."#$t_anchor\">$qword</a></b>";
+
+    print_itable( $out , $title , 
+		 [ "File:" , "<a href=\"".index_link("Files",$t_file).
+		  "\">$t_file</a>" , 
+		  "Module:" , "<a href=\"".index_link("Modules",$m)."\">$m</a>" ]);
+
+}
+
+###############################################################################
+# Print out a table in the index, called with the output file, the title and
+#  a pointer to an array of table pairs (column 1 and column 2)
+#
+sub print_itable {
+    my ($out,$title,$tab) = @_;
+    my ($f1,$f2,$empty);
+    print $out "&nbsp;$title\n";
+    if (@{$tab}) {
+	$empty=1;
+	print $out "<div align=right><table cols=2 width=\"97%\">\n";
+	while ($f1=shift(@{$tab})) {
+	    $f2=shift(@{$tab});
+	    die "print_itable internal error" unless (defined($f2));
+	    if ($f2 ne '') {
+		$empty=0;
+		print $out "<tr><td valign=top width=\"17%\"><i>$f1</i></td>".
+		    "<td valign=top width=\"83%\">$f2</td></tr>\n";
+	    }
+	}
+	print $out "<tr><td></td></tr>\n" if ($empty); # NS does not like empty tables
+	print $out "</table></div>\n";
+    }
+    else {
+	print $out "<br>\n";
+    }
+}
+
+sub index_link {
+    my ($type,$elem) = @_;
+
+    # debugging checks
+    print "Error: Bad index link $type $elem\n" 
+    	unless (exists($index_info->{$type}{letters}{uc(substr($elem,0,1))}));
+    return $index_info->{$type}{letters}{uc(substr($elem,0,1))} . "#$elem";
+}
+
+###############################################################################
+#   Hierarchy and frame printing
+###############################################################################
+
+###############################################################################
+# Print out the hierarchy
+#  arguments: output_file_name, javascript flag
+#
+sub print_hier {
+    my ($h_file,$js,$hier_tops_p) = @_;
+    my ($out_file,$m,$imod);
+    local (*HIER,*JSF,*FT);
+
+    # write out the blank printIt file - this is a work around for a NS6 bug (22681)
+    open(FT,">$out_dir"."blank_printIt.html") || 
+	die "Error: can not open file blank_printIt.html to write: $!\n ";
+    push(@output_files,"$out_dir"."blank_printIt.html");
+    print FT "<html><head>\n";
+    print FT "<title></title>\n";
+    print FT $style_sheet_link;
+    print FT "</head><body onload=\"javascript:parent.printIt('',-1)\"></body></html>\n";
+    close (FT);
+
+
+    $out_file = $out_dir . $h_file;
+    open(HIER,">$out_file") || 
+	die "Error: can not open file $out_file to write: $!\n";
+    push(@output_files,"$out_file");
+
+    if ((@{$hier_tops_p})) {
+        # check that all the hierarchy tops (specified with -ht)  exist
+	foreach $module (@{$hier_tops_p}) {
+	    die "Error: Did not find top module $module\n"
+		if (!&rvp::module_exists($verilog_db,$module));
+	}
+    }
+    else {
+	# search for all hier tops - modules that are not instantiated
+	#  but do instantiate at least one module that we have source for
+	MOD_LOOP: foreach $m (sort &rvp::get_modules($verilog_db)) {
+	    print "  checking if module $m is a top\n" if $debug;
+	    if  (! &rvp::get_first_instantiator($verilog_db,$m)) {
+		($imod) = &rvp::get_first_instantiation($verilog_db,$m );
+		while ($imod) {
+		    print "   checking instantiation $imod\n" if $debug;
+		    if (&rvp::module_exists($verilog_db,$imod)) {
+			push(@{$hier_tops_p},$m);
+			next MOD_LOOP;
+		    }
+		    ($imod) = &rvp::get_next_instantiation($verilog_db);
+		}
+	    }
+	}
+    }
+
+    if ($js) {
+	print " doing js version\n" if $debug;
+	$js_file = $out_file;
+	$js_file =~ s/.html$//;
+	$js_file = $js_file . ".js";
+	open(JSF,">$js_file") || 
+	    die "Error: can not open file $js_file to write: $!\n";
+
+	# do the java script version first
+	print_js_hier_head(*JSF,join(" ",@{$hier_tops_p}));
+	print_hier_body(*JSF,$hier_tops_p,1);
+	print_js_hier_tail(*JSF);
+	close(JSF);
+    }
+
+    # now do the html version
+    print " doing html version\n" if $debug;
+    print_hier_head(*HIER,join(" ",@{$hier_tops_p}),$js,$js_file,$h_file);
+    print_hier_body(*HIER,$hier_tops_p,0);
+    print_hier_tail(*HIER,$js);
+    close(HIER);
+    print " done html version\n" if $debug;
+}
+
+###############################################################################
+# Print out header information in hierarchy file
+#
+sub print_hier_head {
+    my ($out,$t,$js,$js_file,$h_file) = @_;
+
+    print " print_hier_head\n" if $debug;
+    print $out "<!-- v2html hierarchy ";
+    print $out "K=$cgi_key " if $cgi_script;
+    print $out "-->\n";
+    print $out "<html><head>\n";
+    
+    if ($js) {
+	print_js_include( $out , $js_file);
+	unlink($js_file) unless $frames; # do not need the javascript file anymore
+    }
+
+    print $out "<title>hierarchy: $t</title>\n";
+    print $out $style_sheet_link;
+    print $out "</head>\n";
+
+    print $out "<noscript>" if ($js);
+
+    print $out "<body>\n";
+
+
+    print $out "<center><b>The Javascript features of this page are not ".
+	"working in your browser. Either you do not have a Javascript capable".
+	    " browser (NS3, IE4 or later) or you have Javascript".
+		" disabled in your preferences.</b></center><br>"
+		if ($js);
+}
+
+###############################################################################
+# Print out the hierarchy
+#  arguments: output_file_name, javascript flag
+#
+sub print_hier_body {
+    my ($out,$hier_tops_p,$js) = @_;
+    my ($f,$m,$m_line,$fb,@no_mods,$nm,@unconnected,$imod);
+
+    print " print_hier_body\n" if $debug;
+    $ul_id=0; # used for folding hierarchy
+
+    print_navbar($out,$js,'Hierarchy',\%navbar,'','',$vert_frames);
+    print_h_or_js($out, "<center><h3>$hier_comment</h3></center>\n",$js) if $hier_comment;
+
+    #
+    # Go through each module you were asked for
+    #
+    foreach $m (@{$hier_tops_p}) {
+	($f,$m_line) = &rvp::get_modules_file($verilog_db,$m);
+	print_h_or_js($out, "<h3>Hierarchy for " . $m . "</h3>\n",$js);
+	print_h_or_js($out, "<nobr><ul>\n",$js);
+	print_tree($out,$m,$m_line,$f,0,1,$js);
+	print_h_or_js($out, "</ul></nobr>\n",$js);
+	print_h_or_js($out, "<hr>\n",$js);
+    }
+
+    # 
+    # now do files containing no modules
+    #
+    if ($print_no_mods) {
+	foreach $f (&rvp::get_files($verilog_db)) {
+	    push(@no_mods,$f) 
+		if (0 == &rvp::get_files_modules($verilog_db,$f));
+	}
+	if (@no_mods) {
+	    print_h_or_js($out, "<h3>Files containing no modules</h3>\n",$js);
+	    print_h_or_js($out, "<ul>\n",$js);
+	    foreach $f (@no_mods) {
+		($fb = $f) =~ s/^.*\///;
+		print_h_or_js($out, "<li>" . "<a $frame_code href=\"" 
+			      . hfile($f,1) . "\">$fb</a>\n",$js);
+		if ($output_index) {
+		    print_h_or_js($out,"<a $frame_code href=\"".
+				  index_link("Files",$fb)."\">$icon_i<\/a>\n",$js);
+		}
+	    }
+	    print_h_or_js($out, "</ul>\n",$js);
+	    print_h_or_js($out, "<hr>\n",$js);
+	}
+    }
+
+    #
+    # Now do unconnected modules
+    #  (unreffed modules that do not instantiate any other modules
+    #   that we have source for)
+    #
+    if ($print_unconnected) {
+	MOD_LOOP: foreach $m (sort &rvp::get_modules($verilog_db)) {
+	    print "  checking if module $m is unconnected\n" if $debug;
+	    # the hier tops have been done already, so ignore them
+	    foreach $imod (@{$hier_tops_p}) {
+		if ($imod eq $m) { next MOD_LOOP; }
+	    }
+	    if  ( ! &rvp::get_first_instantiator($verilog_db,$m)) {
+		($imod) = &rvp::get_first_instantiation($verilog_db,$m );
+		while ($imod) { 
+		    if (&rvp::module_exists($verilog_db,$imod)) {
+			next MOD_LOOP;
+		    }
+		    ($imod) = &rvp::get_next_instantiation($verilog_db );
+		} 
+		# if we got here we are unconnected
+		push(@unconnected,$m);
+	    }
+	}
+	if (scalar(@unconnected) != 0) {
+	    if ((scalar(@unconnected) == 1)&&(!(@{$hier_tops_p}))) { 
+		print_h_or_js($out, "<h3>$unconnected[0]</h3>\n",$js);
+	    }
+	    else {
+		print_h_or_js($out, "<h3>Unconnected modules</h3>\n",$js);
+	    }
+	    
+	    print_h_or_js($out, "<nobr><ul>\n",$js);
+	    foreach $m (@unconnected) {
+		# even though we're unconnected print_tree is called
+		#  because there may be submodules we do not have source for
+		($f,$m_line) = &rvp::get_modules_file($verilog_db,$m);
+		print_tree($out,$m,$m_line,$f,0,1,$js);
+	    }
+	    print_h_or_js($out, "</ul></nobr>\n",$js);
+	    print_h_or_js($out, "<hr>\n",$js);
+	}
+    }
+}
+
+###############################################################################
+# Recursively Print the hierarchical tree for a module
+#
+sub print_tree {
+    my ($out,$m,$m_line,$f,$depth,$n_inst,$js) = @_;
+    my (@t,$tt,$count,$this_ul_id,$this_ces_arg,$prev_ces_arg,$i,$imod,$tl,$tf);
+
+    print " print_hier_tree($out,$m,$m_line,$f,$depth,$n_inst,$js)\n" if $debug;
+    if ($js) {
+	if ( defined($index_stack[0]) ) {
+	    $prev_ces_arg = "ul_i_" . $index_stack[$#index_stack];
+	}
+	else {
+	    $prev_ces_arg = "1";
+	}
+	print $out "  if ( $prev_ces_arg ) {\n";
+    }
+
+    print_h_or_js($out," " x $depth  . "<li>" . 
+		   "<a $frame_code href=\"" . 
+		   hfile($f,$m_line) . "#" . $m . "\">" . $m . "</a>\n",$js);
+    if ($output_index) {
+	print_h_or_js($out,"<a $frame_code href=\"".index_link("Modules",$m)."\">".
+		      "$icon_i<\/a>\n",$js);
+    }
+
+
+    print_h_or_js($out," " x $depth  . "x $n_inst\n",$js) if ($n_inst!=1);
+    print $out "  }\n" if ($js);
+
+    @t=();
+    if ( (($imod) = &rvp::get_first_instantiation($verilog_db,$m )) ||
+	 ($t_and_f_in_hier && scalar(&rvp::get_modules_t_and_f($verilog_db,$m)))) {
+	# get all the things it instantiates and call print tree on them
+	while ($imod) {
+	    push(@t,$imod);
+	    ($imod) = &rvp::get_next_instantiation($verilog_db);
+	}
+	@t = sort( @t );
+	$this_ul_id = $ul_id;
+	$ul_id++;
+	push(@index_stack,$this_ul_id);
+	$this_ces_arg = "ul_i_$this_ul_id";
+	if ($js) {
+	    print $out "    $this_ces_arg = " .
+		"$prev_ces_arg && check_expand_string(control,$this_ul_id);\n";
+	    print_h_or_js($out,"<a name=\"ul_id_$this_ul_id\"></a>\n",1);
+	    print $out "  if ( $this_ces_arg ) {\n";
+	    print_h_or_js($out,"<a href=\"javascript:parent.printIt(\\'' + " . 
+			   " new_expand_string(control,$this_ul_id,'C') + " .
+			   " '\\', $this_ul_id)".
+			   "\"> $icon_c</a>\n<ul>\n",1);
+	    print $out "  }\n",; 
+	    print $out "  else { \n";
+	    print $out "    if ( $prev_ces_arg ) {\n";
+	    print_h_or_js($out,"<a href=\"javascript:parent.printIt(\\'' + " . 
+			   " new_expand_string(control,$this_ul_id,'X') + " .
+			   " '\\', $this_ul_id)".
+			   "\"> $icon_x</a>\n",1);
+	    print $out "    }\n  }\n";
+	    
+	}
+	else { 
+	    print_h_or_js($out, "<ul> <!-- ul_id=$this_ul_id -->\n",0); 
+	}
+	for ($i=0;$i<=$#t;$i++) {
+	    $tt = $t[$i];
+	    $count=1;
+	    while (($i<$#t) && ($t[$i] eq $t[$i+1])) { $i++; $count++; }
+
+	    if ( ! &rvp::module_exists($verilog_db,$tt) ) {
+		print $out "  if ( $this_ces_arg ) {\n" if ($js);
+		print_h_or_js($out," " x $depth . " <li>$tt\n",$js);
+		print_h_or_js($out," " x $depth . " x $count\n",$js) 
+		    if ($count!=1);
+		print_h_or_js($out,
+			      " (not linked because of duplicate definition)\n",
+			      $js) 
+		    if (&rvp::module_ignored($verilog_db,$tt));
+		print $out "  }\n" if ($js);
+	    }
+	    else {
+		($tf,$tl) = &rvp::get_modules_file($verilog_db,$tt),
+		print_tree($out,$tt,$tl,$tf,$depth+1,$count,$js);
+	    }
+	}
+	if ($t_and_f_in_hier) {
+	    print $out "  if ( $this_ces_arg ) {\n" if $js;
+	    &print_hier_t_and_f($out,$m,$depth,$js);
+	    print $out "  }\n" if $js;
+	}
+	if ($js) {
+	    print $out "  if ( $this_ces_arg ) {\n";
+	    print_h_or_js($out, "</ul>\n",1);
+	    # Print the string if it is getting too long, this stops netscape's memory usage exploding
+	    #  when viewing large hierarchies. Open the document before doing the first write.
+	    print $out "     if (Text.length >5000) { if (!doc_open) { parent.upper.document.open(); doc_open=1; }".
+		" parent.upper.document.write(Text); Text=''; }\n";
+	    print $out "  }\n";
+	}
+	else { 
+	    print_h_or_js($out, "</ul> <!-- ul_id=$this_ul_id -->\n",0); 
+	}
+	pop(@index_stack);
+    }
+
+}
+
+sub print_hier_t_and_f {
+    my($out,$m,$depth,$js) = @_;
+    my (@t_and_f,$tf,$t_type,$t_line,$t_file,$t_anchor);
+
+    if ( @t_and_f = &rvp::get_modules_t_and_f($verilog_db,$m) ) {
+	foreach $tf (sort @t_and_f) {
+	    ($t_type,$t_line ,$t_file,$t_anchor)=
+		&rvp::get_modules_t_or_f($verilog_db,$m,$tf);
+	    $t_type = 'func' if ($t_type eq 'function');
+	    print_h_or_js($out," " x $depth  . "<li><i>$t_type:</i> " .
+			  "<a $frame_code href=\"" . 
+			  hfile($t_file,$t_line) . "#" . $t_anchor . "\">" . 
+			  $tf . "</a>\n",$js);
+	    if ($output_index) {
+		if ($t_type eq 'task') {
+		    print_h_or_js($out,"<a $frame_code href=\"".
+				  index_link("Tasks","${tf}___$m")."\">".
+				  "$icon_i<\/a>\n",$js);
+		}
+		else {
+		    print_h_or_js($out,"<a $frame_code href=\"".
+				  index_link("Functions","${tf}___$m")."\">".
+				  "$icon_i<\/a>\n",$js);
+		}
+	    }
+	}
+    }
+
+}
+
+###############################################################################
+# Either print a string directly or output some javascript
+#  that will end up printing it
+#
+sub print_h_or_js {
+    my ($out,$s,$js) = @_;
+
+
+
+    if ($js) {
+	$s =~ s/\n/\\n/g;
+	$s =~ s|</|<\\/|g;
+	print $out "      Text += '" . $s . "';\n";
+    }
+    else {
+	$s =~ s|\\'|'|g; #'
+	print $out $s;
+    }
+}
+
+###############################################################################
+# print the bottom of the hierarchy
+#
+sub print_hier_tail {
+    my ($out,$js) = @_;
+
+    print " print_hier_tail\n" if $debug;
+    print_navbar($out,0,'Hierarchy',\%navbar,'','',$vert_frames);
+    print_footer($out,'',$vert_frames,0);
+    print $out "</body>\n";
+
+    if ($js) {
+	print $out "</noscript>\n";
+	print $out " <frameset cols=\"100%,*\">\n";
+	print $out "  <frame name=\"upper\" " .
+	    "src=\"blank_printIt.html\">\n";
+	print $out " </frameset>\n";
+    }
+    print $out "</html>\n";
+}
+
+###############################################################################
+# Print the top of the javascript hierarchy (functions that
+#  will end up printing the hierarchy)
+#
+sub print_js_hier_head {
+    my ($out,$t) = @_;
+
+    print_js_common($out);
+
+  #####################JAVASCRIPT START##################################
+    print $out <<EOF;
+
+// dummy function in case someone tries to do a search in the hierarchy window
+function search ()     { return false; } 
+
+function check_expand_string (control,index) {
+  if (control.charAt(0)=='A') {
+    return 1;
+  }
+  else if ( index < control.length ) {
+    return (control.charAt(index)=='X');
+  }
+  else {
+    return 0;
+  }
+}
+
+function new_expand_string (control,index,v) {
+  var newString;
+  if ( index < control.length ) {
+    newString = control.substring(0,index) + v + 
+           control.substring(index+1,control.length);
+  }
+  else {
+      if (control == 'A') { newString = 'X';     }
+      else                { newString = control; }
+      for (var i=0; i<(index-control.length); i++) {
+          if (control == 'A') { newString += 'X' }
+          else                { newString += 'C' }
+      }
+    newString += v;
+  }
+  return newString;
+}
+
+function getCookie(Name) {
+   var search = Name + "=";
+   if (document.cookie.length > 0) { // if there are any cookies
+      offset = document.cookie.indexOf(search) ;
+      if (offset != -1) { // if cookie exists 
+         offset += search.length ;
+         // set index of beginning of value
+         end = document.cookie.indexOf(";", offset) ;
+         // set index of end of cookie value
+         if (end == -1) 
+            end = document.cookie.length;
+         return unescape(document.cookie.substring(offset, end));
+      } 
+   }
+   return '';
+}
+
+function setCookie(name, value) {
+   var today = new Date();
+   var expires = new Date();
+   expires.setTime(today.getTime() + 1000*60*60*24*365);
+
+   document.cookie = name + "=" + escape(value)
+   + "; expires=" + expires.toGMTString();
+}
+
+function printIt (control,loc) {
+    var Text='';
+    var doc_open=0;
+EOF
+    #####################JAVASCRIPT END####################################
+    print $out "  if (control.length==0) control=getCookie(\"v2html $t\");\n" 
+	if $js_cookies;
+    print $out "  if (control.length==0) control='C';\n";
+    print $out "  setCookie(\"v2html $t\",control);\n"
+	if ($js_cookies);
+
+
+    print_h_or_js($out,"<html><head>\n",1);
+    print_h_or_js($out,"<title>hierarchy: $t</title>$style_sheet_link</head>\n",1);
+    print_h_or_js($out, "<body>",1);
+
+}
+
+###############################################################################
+# Print out the end of the javascript hierarchy
+#
+sub print_js_hier_tail {
+    my ($out) = @_;
+
+    print_navbar($out,1,'Hierarchy',\%navbar,'','',$vert_frames);
+    print_footer($out,'',$vert_frames,1);
+
+  #####################JAVASCRIPT START##################################
+    print $out <<EOF;
+
+    if (!doc_open) parent.upper.document.open();
+    parent.upper.document.write(Text);
+    Text='';
+    parent.upper.document.write('<\\/body><\\/html>');
+    parent.upper.document.close();
+    if (loc != -1) {
+      if (is_nav5up) 
+	// - 18 needed because this is the height of the icon (I think)
+	parent.upper.scrollTo(0,parent.upper.document.anchors[loc].offsetTop-18);
+      else if (is_nav4up) 
+	parent.upper.scrollTo(0,parent.upper.document.anchors[loc].y);
+      else if (is_ie4up)
+        parent.upper.document.anchors[loc].scrollIntoView(true)        
+    }
+}
+
+EOF
+  #####################JAVASCRIPT END####################################
+}
+
+###############################################################################
+# Print out the html that will include the javascript
+#
+sub print_js_include {
+    my ($out , $jsf) = @_;
+
+    # this does not work without server's mimetypes being configured:
+    #    print $out "<script language=\"JavaScript\" src=\"$jsf\"></script>\n";
+
+    # this works whatever (copy all the js code into current file!)
+    print $out "<script language=\"JavaScript\" type=\"text\/javascript\"><!--\n";
+    open (TTT,"<$jsf") || die "Error: can not open file $jsf to read: $!\n"; 
+    while (<TTT>) { print $out $_; }
+    close(TTT);
+    print $out "// -->\n";
+    print $out "</script>\n";
+}
+    
+sub print_js_sigpopup {
+    my ($out) = @_;
+
+    # Be careful when writing this: comments get stripped out later
+    #  rather crudely - so using // in a string for example will break!
+  #####################JAVASCRIPT START##################################
+    my $script = <<EOF;
+
+var disabled=1;
+if (!is_nav4up) {
+  var event=false; // prevent from dieing ns3 and ie4up
+}
+var last_link=0;     // last link found in search
+var last_class=null; // class of last link changed to highlighted
+
+// main quick search function called when any link is clicked
+function qs(e,t,extra_info_index) {
+  var inc=0,bnum=0,i,j;
+  if (disabled) return false;
+  // buttons for signal window in order of extra info
+  var sig_buttons = [ "Definition" , "Local Driver" , 
+                      "Up to Input Driver" , "Find Source" , "Index"];
+
+   if (is_nav4up || is_ie4up) {
+    // test if quicksearch is wanted:
+    //  forwards  = button 2  or        button 1 + control
+    //  backwards = button 2 + shift or button 1 + shift
+
+    if (((e.which==2) && (!(e.modifiers&Event.SHIFT_MASK))) ||
+	((e.which==1) &&  (e.modifiers&Event.CONTROL_MASK)))   inc = 1;
+    else if (((e.which==2) && (e.modifiers&Event.SHIFT_MASK)) ||
+	     ((e.which==1) && (e.modifiers&Event.SHIFT_MASK))) inc = -1;
+
+    if (inc == 0 && extra_info_index == 0) { // no quick search and no extra_info, so just return 
+      return true;  // follow link as normal
+    }
+
+    var linkText = is_nav4up ? t.text : t.innerText;
+    var linkY    = is_nav4up && ! is_nav5up ? t.y    : t.offsetTop;
+    // find the index of the current link
+    window.status="Searching...";
+    if ((last_link==-1) || (document.links[last_link]!=t)) // try previous link first
+      for (last_link=0;last_link<document.links.length;last_link++) 
+	if (document.links[last_link] == t)  
+	  break;
+
+    if (inc != 0) { // do the quick search
+      return search(linkText,linkY,last_link,inc,1);
+    }
+    else { // do something with the extra_info
+      window.status="";
+      extra_info_index--; // when passed, 0 means no data so decrement to get index
+      if (extra_info[extra_info_index][0] != 'S') { // check the type is signal
+	  return true;
+      }
+      //  open a window, or get a handle to an existing window - unfortunately
+      //   if the window is open and has been resized manually it will be 
+      //   changed back to its initial size (I do not know anyway around this
+      //   apart from opening it with nosize then checking if it has already
+      //   been written and if not closing it and opening one with default size.
+      //   This would look very clunky though!)
+      var w = window.open('','SignalPopUp','width=200,height=235');
+
+      // check to see if the window is already written and if it is then
+      //  if the latest file is in the same dir as the file that first 
+      //  opened to window  - if no then close and reopen the window
+      //  otherwise the old links go screwy
+      if (null != w.document.forms[0]) {
+	 if ((window.location.pathname.substring(0,window.location.pathname.lastIndexOf(dirSep)))!=
+            (w.pn.substring(0,w.pn.lastIndexOf(dirSep)))) {
+	   w.close();
+	   w = window.open('','SignalPopUp','width=200,height=235');
+	 }
+      }
+
+      w.focus(); // raise popup window (does not work on linux NS4.51)
+
+      if (null == w.document.forms[0]) { // true if the window has not yet been written
+	var Text = '<html><head></head>';
+	
+
+	// make some variables that are local to the popup window
+        if (is_nav4up) { // can not get the script way to work in NS...
+          w.loc = new Array(10);
+          w.sel = null;
+	  w.pn  = window.location.pathname;
+        }
+        else {     // ...can not get the w. way to work in IE
+          Text += '<script>var loc = new Array(10);<\\/script>\\n';
+          Text += '<script>var sel;<\\/script>\\n';
+          Text += '<script>var pn = opener.location.pathname;<\\/script>\\n';
+        }
+
+	Text += '<body bgcolor="white">\\n';
+	Text += '<form>';
+	Text += '  <select onchange="opener.setbuttons(window);">\\n';
+	// ns4 on windows does not grow the width so start it really wide
+	Text += '  <option>---------------------------</option>\\n';
+	// ns4 on windows does not grow the length and IE4 dies if
+	//  I leave the field blank!
+	for (j=0;j<9;j++) Text += '  <option>-</option>\\n';
+	Text += '  </select>\\n';
+	Text += '</form>';
+
+	Text += '<table cellspacing=0 cellpadding=0>\\n';
+
+	// length-1 because location 0 of extra_info is the type, so ignore it
+        for (var i=0;i<(extra_info[extra_info_index].length-1);i++) {
+	  Text += hbutton(sig_buttons[i], 
+			  'opener.location=loc[sel.selectedIndex]['+i+'];',
+			  bnum++);
+        }
+        Text += hbutton("Search Backwards", 
+			'opener.search(sel.options[ sel.selectedIndex ].text,' +
+			'0,opener.last_link,-1,0);',bnum++);
+        Text += hbutton("Search Forwards",
+			'opener.search(sel.options[ sel.selectedIndex ].text,' +
+			'0,opener.last_link, 1,0);',bnum++);
+        Text += hbutton("Close","window.close();",bnum++);
+
+	Text += '</table>\\n';
+	Text += '</body></html>\\n';
+
+	w.document.open();
+	w.document.write(Text);
+	w.document.close();
+	w.document.forms[0].elements[0].options[0].text  = linkText;
+	// save space in the window code by defining this short cut
+	w.sel = w.document.forms[0].elements[0]; // refer to the forms elements
+
+	for (j=0;j<10;j++) w.loc[j] = new Array(sig_buttons.length);  
+        copy_into_loc0(w,extra_info_index);
+      }
+      else {
+	var opts = w.document.forms[0].elements[0].options;
+	// this code is obsolete - I have to start at size 10 anyway
+	//  because ns4 under windows will not grow the list dynamically
+	if ( opts.length<10 ) { 
+           w.loc[opts.length] = new Array;
+           opts.length++; 
+        }
+	for (i=opts.length-2;i>=0;i--) {
+	  opts[i+1].text=opts[i].text;
+	  for (var j=0;j<w.loc[i].length;j++) w.loc[i+1][j] = w.loc[i][j];
+	}
+	opts[0].text  = linkText;
+        copy_into_loc0(w,extra_info_index);
+      }
+
+      return false; 
+    }
+  }
+  return true;
+}
+
+// Return the html for a button labeled with text that does the specified
+//  action. Also needs bnum which is the number of the buttons image in the
+//  imagesarray.
+//
+function hbutton (text,action,bnum) {
+  return '  <tr><td><a href="" '+
+    'onmousedown="'+
+	'if (images['+bnum+'].src.match(/v2html-b2.gif/)) return false; ' +
+	'images['+bnum+'].src=\\'v2html-b3.gif\\';" '+
+    'onmouseup="'+
+	'if (images['+bnum+'].src.match(/v2html-b2.gif/)) return false; ' +
+	'images['+bnum+'].src=\\'v2html-b1.gif\\';" '+
+    'onclick="'+
+	// do not do anything if the button is greyed out
+	'if (images['+bnum+'].src.match(/v2html-b2.gif/)) return false; ' +
+	// do action
+        action + 
+       ' return false;">'+
+    '<img border=0 src="v2html-b1.gif"></a></td>' +
+    '<td style="font-family:sans-serif; font-weight:bold; font-size:14px;"> '+text+'</td></tr>\\n';
+}
+
+function copy_into_loc0 (w,extra_info_index) {
+    for (var i=1;i<extra_info[extra_info_index].length;i++) {
+	w.loc[0][i-1] = extra_info[extra_info_index][i];
+    }
+    // the next line is here because mozilla 1.0 (and ns7 pr1) do not
+    //  update desplay of the first droplist idem when the item changes
+    //  (only when the selected Index changes)
+    w.document.forms[0].elements[0].selectedIndex=1;
+    w.document.forms[0].elements[0].selectedIndex=0;
+    setbuttons(w);
+}
+
+function search(text,y,i,inc,relative) {
+  var nextpage,wrappage,linkText,linkY;
+
+  window.status="Searching...";
+  if (last_class) document.links[i].className=last_class;
+
+  while (1) {
+    for (i+=inc;i<document.links.length && i>=0;i+=inc) {
+      linkText = is_nav4up ? document.links[i].text : document.links[i].innerText;
+      linkY    = is_nav4up && ! is_nav5up ? document.links[i].y    : document.links[i].offsetTop;
+      if ((linkText == text) && (linkY != y)) {
+	  window.status="";
+          // NOTE: have not done relative (used up Quick search) for IE4
+          //  because I have not got the button capture to work for QS under IE4
+          if (is_nav4up) 
+            if (relative) window.scrollBy(0,linkY - y);
+            else          window.scrollTo(0,linkY); 
+          else if (is_ie4up)
+	    document.links[i].scrollIntoView(true); // IE put link at top of screen
+	last_link=i;
+	last_class=document.links[i].className;
+	document.links[i].className='HI';
+	return false;
+      }
+    }
+    nextpage = (inc==1) ? next_page() : prev_page();
+    wrappage = (inc==1) ? first_page() : last_page();
+    if (nextpage!="" || wrappage!="") {
+      if (nextpage=="") { // only ask when wrapping around
+	if (!confirm(text + " not found. Search again from "+((inc==1)?"first":"last")+" page?"))
+	  return false;
+	nextpage=wrappage;
+      }
+      location=nextpage+ "?" + escape(text) + "&" + ( y - window.pageYOffset ) + "&" + inc;
+      return false;
+    }
+    if (confirm(text + " not found. Search again from "+((inc==1)?"start":"end")+"?")) {
+      if (inc==1) i=-1;
+      else i=document.links.length;
+    } else return false;
+  }
+  return true;
+}
+
+function loadqs() {
+  var opt=location.search, text="", s="", y=0, si=0, inc=1;
+
+  if (opt.length==0) return true;  // no query string
+  for (var i=1;i<opt.length;i++) { // parse query string: search_text&y_pos&direction
+    if (opt.charAt(i) != "&") 
+      s += opt.charAt(i);
+    else {
+      if (text=="") text=unescape(s);
+      else             y=s;
+      s="";
+    }
+  }
+  if (text=="") return true;
+  if (s == "-1") { si=document.links.length-1; inc=-1; }
+  window.scrollTo(0,0);
+  search(text,y,si,inc);
+  return true;
+}
+EOF
+  #####################JAVASCRIPT END####################################
+
+    if (!$debug) {
+	# save space in each file 
+	$script =~ s|//.*$||gm;  # strip comments
+	$script =~ s|^\s+||gm;   # strip leading whitespace
+	$script =~ s|^\n||gm;    # strip blank lines 
+    }
+
+    print $out "<script language=\"JavaScript\" type=\"text\/javascript\"><!--\n";
+    print_js_common($out);
+    print $out "// Unindented and uncommented to save spave ".
+	"- look in v2html for a prettier version\n";
+    print $out $script;
+    print $out "// -->\n";
+    print $out "</script>\n";
+
+}
+
+
+###############################################################################
+# Print javascript that occurs in every file
+#
+sub print_js_common {
+    my ($out) = @_;
+
+  #####################JAVASCRIPT START##################################
+    my $script= <<EOF;
+// this code is a cut down version of the netscape detector code
+var agt=navigator.userAgent.toLowerCase(); 
+var is_nav  = ((agt.indexOf('mozilla')!=-1) &&
+	       (agt.indexOf('spoofer')==-1) &&
+	       (agt.indexOf('compatible') == -1) &&
+	       (agt.indexOf('opera')==-1) &&
+	       (agt.indexOf('webtv')==-1)); 
+var is_major = parseInt(navigator.appVersion); 
+var is_nav4up = (is_nav && (is_major >= 4)); 
+var is_ie     = (agt.indexOf("msie") != -1); 
+var is_ie4up  = (is_ie  && (is_major >= 4)); 
+var is_nav5up = (is_nav && (is_major >= 5));
+
+// dirSep stores the directory separator. Note IE file urls
+// have \ _and_ / in - so look for \ and assume it is the separator
+// if you find it. Otherwise use the unix /
+var dirSep = (window.location.pathname.indexOf('\\\\') != -1) ? '\\\\' : '/' ;
+
+// Grey out buttons that will do nothing
+//  - called from the signal popup, so must be in all files to avoid errors
+function setbuttons (wndw) {
+  var i;
+
+  // first do the buttons from extra_info (locations stored in loc)
+  var sl=wndw.loc[ wndw.document.forms[0].elements[0].selectedIndex ];
+
+  for (i=0;i<sl.length;i++) {
+    if(sl[i]) wndw.document.images[i].src='v2html-b1.gif';
+    else      wndw.document.images[i].src='v2html-b2.gif';
+  }
+  // now do the search buttons
+  if ( wndw.document.forms[0].elements[0].options[ 
+	 wndw.document.forms[0].elements[0].selectedIndex ].text != '-') {
+    wndw.document.images[i  ].src='v2html-b1.gif';
+    wndw.document.images[i+1].src='v2html-b1.gif';
+  }
+  else {
+    wndw.document.images[i  ].src='v2html-b2.gif';
+    wndw.document.images[i+1].src='v2html-b2.gif';
+  }
+}
+
+EOF
+  #####################JAVASCRIPT END####################################
+
+    if (!$debug) {
+	# save space in each file 
+	$script =~ s|//.*$||gm;  # strip comments
+	$script =~ s|^\s+||gm;   # strip leading whitespace
+	$script =~ s|^\n||gm;    # strip blank lines 
+    }
+    print $out $script;
+}
+
+
+###############################################################################
+# Print the frame.html file
+#
+sub print_frame_top {
+    my ($f,$h,$title,$js,$vert_frames) = @_;
+    my ($out_file);
+    local (*FT);
+
+    # first write out the blank file
+    open(FT,">$out_dir"."blank.html") || 
+	die "Error: can not open file blank.html to write: $!\n ";
+    push(@output_files,"$out_dir"."blank.html");
+    print FT "<html><head>\n";
+    print FT "<title>verilog</title>\n";
+    print FT $style_sheet_link;
+    print FT "</head><body></body></html>\n";
+    close (FT);
+
+    
+    # now output the frame top
+    $out_file = $out_dir . $f;
+    open(FT,">$out_file") || 
+	die "Error: can not open file $out_file to write: $!\n ";
+    push(@output_files,$out_file);
+
+    print FT "<html><head>\n";
+
+    if ($js) {
+	print_js_include( *FT , $js_file);
+	unlink($js_file); # do not need the javascript file anymore
+    }
+
+    print FT "<title>verilog view: $title</title>\n";
+    print FT $style_sheet_link;
+    print FT "</head>\n";
+
+    print FT "<noscript>\n" if ($js);
+    print FT frameset( $vert_frames, $h );
+    
+    if ($js) {
+	print FT "</noscript>\n";
+	print FT frameset($vert_frames,"blank_printIt.html");
+    }
+    print FT "</html>\n";
+
+    close(FT);
+
+}	
+
+sub frameset {
+    my ($vert_frames,$middle_page_url) = @_;
+    my ($rval);
+    if ($vert_frames) {
+	$rval= "<frameset cols=\"30%,70%\">\n".
+	       " <frame name=\"upper\"  src=\"$middle_page_url\">\n".
+               " <frameset rows=\"90%,10%\">\n".
+	       "  <frame name=\"middle\" src=\"blank.html\">\n".
+	       "  <frame name=\"bottom\" src=\"blank.html\">\n".
+	       " </frameset>\n";
+    }
+    else {
+	$rval= "<frameset rows=\"20%,70%,10%\">\n".
+	       " <frame name=\"upper\"  src=\"$middle_page_url\">\n".
+	       " <frame name=\"middle\" src=\"blank.html\">\n".
+	       " <frame name=\"bottom\" src=\"blank.html\">\n";
+    }
+    if ($middle_page_url !~ /^javascript/) {
+	$rval .= "<body>\n<noframes>\n".
+	         " Your browser does not support frames click\n".
+                 " <a href=\"$middle_page_url\">here</a> to see the hierarchy\n".
+		 "</noframes></body>\n";
+    }
+    $rval.="</frameset>\n";
+    return $rval;
+
+}
+
+
+###############################################################################
+# Output open an closed suitcase icons
+#  scripts/encode_gif.pl can generate the print_gif code automagically
+#
+sub print_gifs {
+    my ($out_dir,$print_xc,$print_i)=@_ ;
+
+    if ($print_xc) {
+	# uuencoded gif file for v2html-c.gif
+	print_gif( "${out_dir}v2html-c.gif" ,
+                  'M1TE&.#EA&P`2`,(``/C\^`````@@6+C,R)AD,#`P,/_______R\'Y!`$*``<`'."\n".
+                  'M+``````;`!(```-:>!?<K##*&(2]-LP-*_[.PRU?"8Z>J6I;6KI8^,!7,-#V'."\n".
+                  'MH.L"8^:WT&XG*/A`PZ2RJ($!E4NCPO6$#IF=FA6*S?:V45:V"NY2R%NSA*8J'."\n".
+                  '.2%\'NN%PN&BUD>\'L"`#L`'."\n".
+                  '`'."\n");
+	# uuencoded gif file for v2html-x.gif
+	print_gif( "${out_dir}v2html-x.gif" ,
+                  'M1TE&.#EA%``2`,(``/C\^````+C,R`@@6#`P,,C\^/_______R\'Y!`$*``<`'."\n".
+                  'M+``````4`!(```-->!?<K#"J(*JM049ZNWO3T%FB-PE#JJ8CFG\'MF!),\'`\T'."\n".
+                  'M;)-XO7<]W6_F^Y%R1AXR60DR44Z45$2=HFB+E79+P"ZZX+"81H!\S@Y"(0$`'."\n".
+                  '!.P``'."\n".
+                  '`'."\n");
+
+    }
+    # uuencoded gif file for v2html-up.gif
+    print_gif( "${out_dir}v2html-up.gif" ,
+	       'M1TE&.#EA&P`2`*$``/C\^````+C,R/___R\'Y!`$*``,`+``````;`!(```(Z'."\n".
+	       'MG(^IRQC18@KB24E%A7=EO7432%KB\)&:>:7JRD7N"\O/K=XWIN?[B?(!#RX6'."\n".
+	       '/L!@[ZGY#U#+9C$H-!0`['."\n".
+                  '`'."\n");
+    if ($print_i) {
+	# uuencoded gif file for v2html-i.gif
+	print_gif( "${out_dir}v2html-i.gif" ,
+		   'M1TE&.#EA!``\'`(```/____\``"\'Y!`$`````+``````$``<```((1`*&R9>N'."\n".
+		   '$D"L`.P``'."\n".
+		   '`'."\n");
+    }
+
+    if ($js_sigs) {
+	print_gif( "${out_dir}v2html-b1.gif" ,
+                  'M1TE&.#EA&P`2`,(``/C\^+BXN`@@6,C\^+C,R#`P,/_______R\'Y!`$*``<`'."\n".
+                  'M+``````;`!(```-+>+K<_C#*$ZJ].%>FNQ9<,!!D:9ZE`"[5B+ZF&KHP++-B'."\n".
+                  'L7=]*J]NK7NZ\'XE&&Q%CP2$N2C#YG:AF5$J"JK\';++2R]W\'"X,"F;SXX$`#L`'."\n".
+                  '`'."\n");
+	print_gif( "${out_dir}v2html-b2.gif" ,
+                  'M1TE&.#EA&P`2`,(``/C\^+BXN`@@6+C,R,C\^#`P,/_______R\'Y!`$*``<`'."\n".
+                  'M+``````;`!(```-0>+K<_C#*$P*]-N-=F?Y<*#36<)CHJ:;FZ!W$*K.RNY1S'."\n".
+                  'MGMJ*%=/`&DE\';`U_Q1SO$FP>EKYD$"I5\'JNTY6C[[\'*_AT)##"Y[N^*)>LUN'."\n".
+                  '$)```.P``'."\n".
+                  '`'."\n");
+	print_gif( "${out_dir}v2html-b3.gif" ,
+                  'M1TE&.#EA&P`2`,(``/C\^#`P,`@@6+BXN+C,R/___________R\'Y!`$*``<`'."\n".
+                  'M+``````;`!(```-(>+K<_C#*$X2]..O`1-6@-G0"89YHB@[C8JFPRI)Q;<YN'."\n".
+                  'I:<>X\NZPWN$\'3`F)Q=-1EU2V?,PF82EU=EC8K\'8KY\'J]D[!X[$@``#L`'."\n".
+                  '`'."\n"); #`)
+    }
+}
+
+sub print_gif {
+    my ($file,$data) = @_;
+
+    print "Writing icon $file\n" unless $quiet;
+    open(GIF,">$file") || 
+	die "Error: can not open file $file to write: $!\n ";
+    binmode(GIF);
+    print GIF unpack("u",$data);
+    close(GIF);
+}
+
+
+###############################################################################
+# Output cascading style sheet
+#
+sub print_css {
+    my ($out_dir)=@_ ;
+    my ($c,$tag,$prop,$s,$checksum,$line);
+
+    # do not overwrite
+    if ( -r "${out_dir}v2html.css") {
+	open(CSS,"<${out_dir}v2html.css") || 
+	    die "Error: can not open file ${out_dir}v2html.css to check: $!\n ";
+
+	$checksum=$line=0;
+	while( defined($_=<CSS>)) { 
+	    $checksum += unpack("%32C*",$_) * ($line + 73);
+	    $checksum %= 65535;
+	    $line++;
+	}
+	close(CSS);
+	if (($checksum != 38677) &&   # the CSS generated by v2html 5.0 to 5.10
+	    ($checksum != 17848) &&   # temp checksum for versions 5.11 to 5.14
+	    ($checksum != 33561) &&   # temp checksum for versions to 6.14
+	    ($checksum != 56981) &&   # checksum for versions later than 6.39
+	    ($checksum != 39241)      # checksum for versions later than 7.13
+	    ) {
+	    print "Not overwriting edited CSS ".
+		"${out_dir}v2html.css (Checksum=$checksum)\n";
+	    return;
+	}
+    }
+    open(CSS,">${out_dir}v2html.css") || 
+	die "Error: can not open file ${out_dir}v2html.css to write: $!\n ";
+
+    # After changing the CSS run v2html in a blank directory twice
+    #  the second time it should say:
+    #  Not overwriting edited CSS new_html/v2html.css (Checksum=XXXXX)
+    # Put the XXXXX value into the list of checksum above, so that newer v2html
+    #  will overwrite unedited CSS files created by older v2html versions.
+    print CSS <<EOF;
+BODY { 	   /* main_body */
+  background:#FFFFFF;
+  color:#000000; 
+}
+A { /* default link */
+  text-decoration:underline; 
+  color:#08215A;
+} 
+TABLE.NB { /* navbar table */
+  width:100%;
+}
+TABLE.NB TD { /* navbar table text */
+  font-family:sans-serif;
+  background:#BBCCCC;
+  padding:0;
+  border:outset;
+  font-weight:bold;
+  font-size:12px;
+  text-decoration:none;
+}
+TABLE.NB A { /* navbar table links */
+  color:#08215A;
+  text-decoration:none;
+}
+A.HI { background:#FFFF00; } /* highlighted link found in search (not in NS4.x)*/
+
+/* verilog language elements */
+SPAN.C       { color:#0000FF; }				/* comment (non-link) */
+A.C          { color:#0000FF; background:#CCCCFF; }	/* comment (link) */
+SPAN.M       { color:#9933FF; font-weight:bold; }	/* compiler (non-link) */
+SPAN.D       { color:#990099; }				/* define (non-link) */
+A.D          { color:#990099; }				/* define (link) */
+SPAN.F       { color:#CC0033; }				/* function (non-link) */
+A.F          { color:#CC0033; }				/* function (link) */
+SPAN.K       { color:#CC3300; }				/* keyword (non-link) */
+SPAN.MM      { color:#6600FF; }				/* module (non-link) */
+A.MM         { color:#6600FF; }				/* module (link) */
+SPAN.PA      { color:#CC0066; }				/* parameter (non-link) */
+A.PA         { color:#CC0066; }				/* parameter (link) */
+SPAN.P       { color:#999999; }				/* pre-processor ignore (non-link) */
+SPAN.S       { color:#009900; }				/* string (non-link) */
+A.S          { color:#009900; }				/* string (link) */
+SPAN.ST      { color:#9933FF; }				/* systemtask (non-link) */
+SPAN.T       { color:#660033; }				/* task (non-link) */
+A.T          { color:#660033; }				/* task (link) */
+
+SPAN.SIO     { color:#00CC99; }				/* signal inout (non-link) */
+A.SIO        { color:#00CC99; }				/* signal inout (link) */
+SPAN.SIOR    { color:#009999; }				/* signal inout_reg (non-link) */
+A.SIOR       { color:#009999; }				/* signal inout_reg (link) */
+SPAN.SI      { color:#006600; }				/* signal input (non-link) */
+A.SI         { color:#006600; }				/* signal input (link) */
+SPAN.SIT     { color:#663333; }				/* signal integer (non-link) */
+A.SIT        { color:#663333; }				/* signal integer (link) */
+SPAN.SO      { color:#000066; }				/* signal output (non-link) */
+A.SO         { color:#000066; }				/* signal output (link) */
+SPAN.SOR     { color:#0000CC; }				/* signal output_reg (non-link) */
+A.SOR        { color:#0000CC; }				/* signal output_reg (link) */
+SPAN.SRL     { color:#663333; }				/* signal real (non-link) */
+A.SRL        { color:#663333; }				/* signal real (link) */
+SPAN.SR      { color:#FF9933; }				/* signal reg (non-link) */
+A.SR         { color:#FF9933; }				/* signal reg (link) */
+SPAN.SS0     { color:#CC6600; }				/* signal supply0 (non-link) */
+A.SS0        { color:#CC6600; }				/* signal supply0 (link) */
+SPAN.SS1     { color:#CC6600; }				/* signal supply1 (non-link) */
+A.SS1        { color:#CC6600; }				/* signal supply1 (link) */
+SPAN.STM     { color:#CC3333; }				/* signal time (non-link) */
+A.STM        { color:#CC3333; }				/* signal time (link) */
+SPAN.SRT     { color:#CC3333; }				/* signal realtime (non-link)*/
+A.SRT        { color:#CC3333; }				/* signal realtime (link) */
+SPAN.STI     { color:#CC6600; }				/* signal tri (non-link) */
+A.STI        { color:#CC6600; }				/* signal tri (link) */
+SPAN.ST0     { color:#CC6600; }				/* signal tri0 (non-link) */
+A.ST0        { color:#CC6600; }				/* signal tri0 (link) */
+SPAN.ST1     { color:#CC6600; }				/* signal tri1 (non-link) */
+A.ST1        { color:#CC6600; }				/* signal tri1 (link) */
+SPAN.STA     { color:#CC6600; }				/* signal triand (non-link) */
+A.STA        { color:#CC6600; }				/* signal triand (link) */
+SPAN.STO     { color:#CC6600; }				/* signal trior (non-link) */
+A.STO        { color:#CC6600; }				/* signal trior (link) */
+SPAN.STR     { color:#CC6600; }				/* signal trireg (non-link) */
+A.STR        { color:#CC6600; }				/* signal trireg (link) */
+SPAN.SWA     { color:#CC6600; }				/* signal wand (non-link) */
+A.SWA        { color:#CC6600; }				/* signal wand (link) */
+SPAN.SW      { color:#CC6600; }				/* signal wire (non-link) */
+A.SW         { color:#CC6600; }				/* signal wire (link) */
+SPAN.SWO     { color:#CC6600; }				/* signal wor (non-link) */
+A.SWO        { color:#CC6600; }				/* signal wor (link) */
+SPAN.GV      { color:#CC6600; font-weight:bold }	/* V2001 genvar */
+A.GV         { color:#CC6600; font-weight:bold }	/* V2001 genvar */
+SPAN.AT      { color:#CC00CC; font-weight:bold }	/* V2001 attribute */
+A.AT         { color:#CC00CC; font-weight:bold }	/* V2001 attribute */
+
+EOF
+    close(CSS);
+}
+
+###############################################################################
+#   Converting verilog files as html
+###############################################################################
+
+###############################################################################
+#  Convert a file to html
+# 
+sub convert {
+    my ($f) = @_;
+    my ($match,$start,$end,$length,$line,$previous,$last_pos,
+	$text_s,$include,$fb,$out_file,$vstate,$out,$i);
+    local (*F);
+
+    $line = 1;
+    $last_pos = 0;
+
+    print "Converting $f\n" unless $quiet;
+    open(F,"<$f") || die "Error: can not open file $f to read: $!\n";
+    $/ = undef;
+    $text_s = <F>;
+    $/ = "\n";
+    close(F);
+
+    if ($tabstop!=0) {
+	1 while ($text_s =~ s/(^|\n)([^\t\n]*)(\t+)/
+	    $1. $2 . (" " x ($tabstop * length($3) - (length($2) % $tabstop)))
+		/gsex);
+    }
+
+
+    $fb = ffile($f);
+
+    # this stores the state needed in output_v
+    $vstate = {};    
+    $vstate->{context}         = '1';
+    $vstate->{cur_inst}        = '$NONE'; # current instance
+    $vstate->{cur_inst_exists} = 0;       # current instance can be linked to
+    $vstate->{page}            = 0;       # page we're on
+    $vstate->{rhs}             = 0;       # on right hand side of = or <=
+    $vstate->{inst_link_done}  = 0;       # done the linking of the instance name
+    $vstate->{line_started}    = 0;       # done initial stuff for line
+    $vstate->{pre_ignore}      = 0;       # preprocessor told us to ignore 
+                                          #  lines until this one
+    $vstate->{name}            = '';      # name of module or t or f we are in
+    $vstate->{type}            = '';      # type of context module,task or function
+    $vstate->{lines}           = &rvp::get_files_stats( $verilog_db, $fb );
+    $vstate->{page_nb}         = {};      # navbar for pages
+
+    # we can put in shortened links (ie #x instead of file#x) unless we are using
+    #  qs on a multipage file (because the ?query_string breaks with short links)
+    $vstate->{short_links}     = (!$js_sigs) || ($vstate->{lines} < $lines_per_file);
+
+    # store extra info for output at end of file in javascript array
+    #  {NAME}{vindex} = number of index in javascript array
+    #  {NAME}{value} = [] list of strings to store in array at this index
+    $vstate->{extra_info}      = {};
+    $vstate->{extra_info_last} = 0;
+
+    # make page navbar for multipage files
+    if ($vstate->{lines} > $lines_per_file) {
+	$vstate->{page_nb}{order} = [ ];
+	for ($i=1;(($i-1)*$lines_per_file)<$vstate->{lines};$i++) {
+	    push ( @{$vstate->{page_nb}{order}} , $i );
+	    $vstate->{page_nb}{$i}= hfile($f,(($i-1)*$lines_per_file)+1);
+	}
+    }
+
+    if ($text_s) {
+	while ($text_s =~ 
+	        m%\G((/\*.*?\*/)|                # /* comments */
+		     (\(\*.*?\*\))|              # (* attributes *)  V2001
+		     (//.*?(?:\n|\Z))|           # // comment
+		     (\`include\s+\".*?\")|      # include (string unblanked)
+		     (\"(?:(?:\\\\)|(?:\\\")|([^\"]))*?\")| # string - ignore \\ and \"
+		     (.*?                        # anything else followed by..
+		      (?=(/\*|                   #  /*
+		     (\(\*)| #    or (* attribute
+			  \(\*(?!\s*\))|         # or (*  [but not (*)]   V2001
+			  //|                    # or // 
+			  \"|                    # or quote
+			  \`include\s+\".*?\"|   # or include
+			  \Z)                    #  or end of string
+		       ))
+		     )%gsox ) {
+
+	    $match  = $1;
+	    
+	    if ( ($vstate->{page}*$lines_per_file) < $line ) {
+		convert_end_file($out,$f,$line-$lines_per_file,1,$vstate) 
+		  if $vstate->{page};
+		$vstate->{page}++;
+		$out=convert_start_file($f,$line,$vstate->{page},$vstate->{lines},
+					$vstate->{page_nb});
+		$vstate->{file} = hfile($f,$line); # current html file
+	    }
+
+	    if ( $match =~ m%^/% ) { 
+		# either sort of comment
+		quote_html(\$match);
+		# link mail addresses in comments
+		$match =~ s/$mail_regexp/<a CLASS=C href=\"mailto:$1\">$1<\/a>/g;
+		# turn urls into links
+		$match =~ s/$http_regexp/<a CLASS=C href=\"$1\">$1<\/a>/g;
+		if ($grey_ifdefed_out && $vstate->{pre_ignore}) {
+		    print_with_font($out,"pp_ignore",$match);
+		}
+		else {
+		    print_with_font($out,"comment",$match);
+	        }
+	    }
+	    elsif ( $match =~ m%^\(\*(?!\s*\))% ) {
+		# attribute, but not (*)
+		quote_html(\$match);
+		if ($grey_ifdefed_out && $vstate->{pre_ignore}) {
+		    print_with_font($out,"pp_ignore",$match);
+		}
+		else {
+		    print_with_font($out,"attribute",$match);
+	        }
+	    }
+	    elsif ( $match =~ m%^\"% ) {
+		# string
+		quote_html(\$match);
+		if ($grey_ifdefed_out && $vstate->{pre_ignore}) {
+		    print_with_font($out,"pp_ignore",$match);
+		}
+		else {
+		    print_with_font($out,"string",$match);
+	        }
+	    }
+	    elsif ( $match =~ m%\`include(\s+)\"(.*?)\"% ) {
+		# include
+		if ($grey_ifdefed_out && $vstate->{pre_ignore}) {
+		    quote_html(\$match);
+		    print_with_font($out,"pp_ignore",$match);
+		}
+		else {
+		    print_with_font($out,"compiler","`include");
+		    print $out "$1";
+		    $include = $2;
+		    if ( &rvp::file_exists( $verilog_db, ffile($include) )) {
+			print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+				   hfile($include,1),'',"&quot;$include&quot;",
+				   "string",$vstate->{short_links},0);
+		    }
+		    else {
+			print_with_font($out,"string", "&quot;$include&quot;");
+		    }
+		}
+	    }
+	    elsif ( $match =~ m%\A\s*\Z% ) {
+		# whitespace
+		print $out $match;
+	    }
+	    else {
+		# verilog code (note: it can change $out if a new page is needed)
+		$out=&output_v($out,$match,$line,$fb,$vstate,$f);
+	    }
+	    
+	    $line += ($match =~ tr/\n/\n/);
+	}
+	print $out "\n";
+    }
+    else { # handle zero length files gracefully
+	$out=convert_start_file($f,$line,1,$vstate->{lines},$vstate->{page_nb});
+    }
+
+    convert_end_file($out,$f,$line,0,$vstate);
+
+}
+
+sub convert_end_file {
+    my ($out,$f,$line,$more,$vstate)=@_;
+    my ($out_file,$next_file,$first_file,@extra_info_array,$e);
+    print $out "</pre>\n";
+    
+    $first_file= (($vstate->{page}!=1)&&(!$more)) ? hfile($f,1) : ""; # used to wrap qs() on the last page
+    $next_file = $more ? hfile($f,$line+$lines_per_file) : ""; # used to qs() to next page
+
+    if (%{$vstate->{page_nb}}) {
+	print_navbar($out,0,$vstate->{page},$vstate->{page_nb},($more?"Next":""),$next_file,0);
+    }
+    if ( (!$frames)  && ($output_hier || $output_index)) {
+	print_navbar($out,0,'Verilog',\%navbar,'','',0);
+    }
+    if ($js_sigs) {
+	print $out "<script language=\"JavaScript\"type=\"text\/javascript\"><!--\n";
+	print $out "function next_page() { return \"$next_file\"; }\n";
+	print $out "function first_page() { return \"$first_file\"; }\n";
+	# put the values of extra info into the extra info array ordered by
+	#  the index value for printing out
+	foreach $e (keys %{$vstate->{extra_info}}) {
+	    $extra_info_array[$vstate->{extra_info}{$e}{vindex}] = 
+	      '"'. join('","',@{$vstate->{extra_info}{$e}{value}}) . '"';
+	}
+	print $out "var extra_info = [\n";
+	print $out "[" . join("],\n[",@extra_info_array) . "]\n";
+        print $out "];\n";
+        print $out "disabled=0;\n";
+	print $out "\/\/ -->\n<\/script>\n";
+	# clear extra info
+	$vstate->{extra_info} = {};
+	$vstate->{extra_info_last} = 0;
+    }
+
+    print_footer($out,$f,0,0);
+    print $out "</body>\n";
+    print $out "</html>\n";
+
+    close($out);
+
+    if ($compress) {
+	$out_file = $out_dir . hfile($f,$line);
+	# In this case we do not want the $compress_extension on
+	#  the file name
+	$out_file =~ s/$compress_extension$//;
+	system ( @compress_cmd , $out_file ) == 0 or die "System call failed";
+    }
+}
+
+sub convert_start_file {
+    my ($f,$line,$page,$lines,$page_nb)=@_;
+    my ($out_file,$prev_file,$last_file);
+    
+    local (*C_OUT);
+    
+    # last file to blank if there only is one file
+    $last_file= (hfile($f,$lines) eq hfile($f,0)) ? "" : hfile($f,$lines);
+    $prev_file= ($page==1)? "" : hfile($f,$line-$lines_per_file);
+
+    $out_file = $out_dir . hfile($f,$line);
+
+    push(@output_files,$out_file);
+    # In this case we do not want the $compress_extension on
+    #  the file name
+    $out_file =~ s/$compress_extension$// if $compress;
+    print "Outputting $out_file\n" if $debug;
+
+    open(C_OUT,">$out_file") || 
+	die "Error: can not open file $out_file to write: $!\n";
+
+    print C_OUT '<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">'."\n";
+
+    print C_OUT "<html><head>\n";
+    print C_OUT "<title>$f" . (($page==1)?"":" page $page"). "</title>\n";
+    print C_OUT $style_sheet_link;
+    print C_OUT "</head>\n";
+    print_js_sigpopup(*C_OUT) if ($js_sigs);
+    print C_OUT "<body".($js_sigs ? " onload='loadqs();'" : "" ).">\n";
+
+    if ($js_sigs) {
+	print C_OUT "<script language=\"JavaScript\"type=\"text\/javascript\"><!--\n";
+	print C_OUT "function prev_page() { return \"$prev_file\"; }\n";
+	print C_OUT "function last_page() { return \"$last_file\"; }\n";
+	print C_OUT "\/\/ -->\n<\/script>\n";
+    }
+    if ( (!$frames)  && ($output_hier || $output_index)) {
+	print_navbar(*C_OUT,0,'Verilog',\%navbar,'','',0);
+    }
+    if (%{$page_nb}) {
+	print_navbar(*C_OUT,0,$page,$page_nb,($prev_file)?"Prev":"",
+		     $prev_file."#bottom_of_page",0);
+    }
+    print C_OUT "<pre>\n";
+    return *C_OUT;
+}
+
+###############################################################################
+# quote a html string
+#
+sub quote_html {
+    my ($s) = @_;
+
+    $$s =~ s/&/&amp;/g;
+    $$s =~ s/</&lt;/g;
+    $$s =~ s/>/&gt;/g;
+    $$s =~ s/\"/&quot;/g;
+}
+
+###############################################################################
+# print some text with html font information
+#
+sub print_with_font {
+    my ($out,$fontname,$s) = @_;
+
+    print $out "<span class=$classes{$fontname}>$s</span>";
+}
+
+###############################################################################
+# print a link with class information
+#
+sub print_link {
+    my ($out,$current_file,$target,$js_sigs,$link_file,$link_anchor,
+	$link_text,$link_type,$short_links,$extra_data_index) = @_;
+    my ($href,$class);
+
+    $class='';
+    $class=" class=$classes{$link_type}" if exists($classes{$link_type});
+
+
+    $href='';
+    $href.=$link_file unless $short_links && ($link_file eq $current_file) && $link_anchor;
+
+    $href.="#$link_anchor" if $link_anchor;
+    
+    print $out "<a $target";
+    print $out " onClick=\"return qs(event,this,$extra_data_index)\"" if ($js_sigs); # for quick search
+    print $out " $class href=\"$href\">$link_text</a>";
+}
+
+###############################################################################
+# Put all the stuff for a signal into the extra info array this is outputted
+#  as a javascript array and then used in the qs() javascript function.
+#  search for sig_buttons to see how it is used
+# info should be pointer to:
+#   [ [def_file,def_line],[a_file,a_line],[i_file,i_line],[src_file,src_line]
+# Returns the index to be used in the qs call
+sub signal_extra_info {
+    my ($sig,$vstate,$index_ref,$info) = @_;
+
+    my $ex_name= "S_${sig}___$vstate->{name}";
+
+    unless (exists $vstate->{extra_info}{$ex_name}) {
+	$vstate->{extra_info}{$ex_name} =  {
+	    vindex => $vstate->{extra_info_last}++ ,
+	    value  => [ 'S' ] };   # type of extra info
+	foreach my $i (@$info) {
+	    my $file = $i->[0];
+	    my $line = $i->[1];
+	    push(@{$vstate->{extra_info}{$ex_name}{value}},
+		 ((($file eq "")||($line == -1)) ? "" :
+		  hfile($file,$line)."#".$line));
+	}
+	push(@{$vstate->{extra_info}{$ex_name}{value}},$index_ref);
+    }
+    
+    # Note that the index placed in the file starts at 1 
+    #  because 0 means no extra info
+    return ($vstate->{extra_info}{$ex_name}{vindex}+1);
+}
+
+###############################################################################
+# output a chunk of verilog
+#
+sub output_v {
+    my ($out,$s,$line,$file,$vstate,$sfile) = @_;
+    my ($anchor,$linebuf,$word,$link_line,$on_def,$qword,$inst,$n,
+	$new_context,$pre_ignore,$nextisdefine,$m,$ms,$f,$new_inst,$s_line,
+	$s_a_line,$s_a_file,$s_i_line,$s_i_file,$s_type,$s_file,$s_type2,
+	$t_type,$t_line,$t_file,$t_anchor,$p,$ex_index,$s_src_file,$s_src_line,
+        $index_ref);
+
+    # do a line at a time (so it can put down the anchors,
+    #  and change the contexts and current instance).
+    while ( $s =~ m/^(.*?(?:\n|\Z))/gm ) {
+	$linebuf = $1;
+	$nextisdefine=0; # for linking define after ifdef, define and undef
+	
+	if ( $line != $vstate->{line_started} ) {
+	    # we are on a new line - first see if we need a new file
+	    if ( ($vstate->{page}*$lines_per_file) < $line ) {
+		convert_end_file($out,$sfile,$line-$lines_per_file,1,$vstate) 
+		  if $vstate->{page};
+		$vstate->{page}++;
+		$out=convert_start_file($sfile,$line,$vstate->{page},$vstate->{lines},
+					$vstate->{page_nb});
+		$vstate->{file} = hfile($sfile,$line); # current html file
+	    }
+	    
+	    # do the anchors
+	    foreach $anchor ( &rvp::get_anchors($verilog_db,$file,$line) ) {
+		print $out "<a name=\"$anchor\"></a>";
+	    }
+	    
+	    # change the context if there is a new one
+	    if ( $new_context = &rvp::get_context($verilog_db,$file,$line) ) {
+
+		print " new context $new_context\n" if $debug;
+
+		if ( &rvp::get_has_value_by_context($verilog_db,$file,$line) ) {
+		    $vstate->{context} = $new_context;
+		    ($vstate->{name},$vstate->{type}) =
+			&rvp::get_context_name_type($verilog_db,$file,$line);
+		}
+
+		if ( (! $vstate->{pre_ignore}) && # not already ignoring
+		     ($pre_ignore = &rvp::get_pre_ignore_by_context($verilog_db,
+							       $file,$line))){
+		    print "  ignoring until $pre_ignore\n" if $debug;
+		    $vstate->{pre_ignore} = $pre_ignore;
+		}
+
+		if ( &rvp::get_module_start_by_context($verilog_db,$file,$new_context) &&
+		    (($m,$f,$inst,$link_line) = &rvp::get_first_instantiator_by_context(
+					   $verilog_db,$file,$new_context))) {
+		    print " putting in up links\n" if $debug;
+		    # put in the up links 
+		    $n=0;
+		    while ($m) {
+			$n++;
+			if ($n>32) {
+			    print $out "<b><i>... (truncated)</i></b>";
+			    last;
+			}
+			print $out "<a $frame_middle href=\"".
+			    hfile($f,$link_line) ."#" . $m . "_" . $inst . "\">".
+				"<img alt=\"[Up: $m $inst]\" align=bottom border=0 ". 
+				    "src=\"v2html-up.gif\"><\/a>";
+			($m,$f,$inst,$link_line)=&rvp::get_next_instantiator($verilog_db);
+		    }
+		    print $out "\n";
+		}
+	    }
+
+	    # change the current inst  if there is a new one
+	    if ( $new_inst = &rvp::get_inst_on_line($verilog_db,$file,$line) ) {
+		$vstate->{cur_inst}= $new_inst;
+		$vstate->{cur_inst_exists}=&rvp::module_exists($verilog_db,$new_inst);
+	    }
+	}
+	# do not do all that stuff again for this line
+	$vstate->{line_started} = $line;
+
+	if ($grey_ifdefed_out && $vstate->{pre_ignore}) {
+	    if ($vstate->{pre_ignore}==$line) {
+		$vstate->{pre_ignore}=0;
+	    }
+	    else {
+		if ( $linebuf =~ m/^\s*$/ ) {
+		    print $out $linebuf;
+		}
+		else {
+		    quote_html(\$linebuf);
+		    print_with_font($out,"pp_ignore",$linebuf);
+		}
+		$line++;
+		next;
+	    }
+	}
+
+	# do a word at a time within the line
+	foreach $word ( split /([.\`\$]?(?:$VID))/ , $linebuf ) {
+	    $qword=$word;
+	    quote_html(\$qword);
+
+	    if ($word !~ m/[.\`\$]?$VID/o ) { # anything that is not a $VID
+		# when we see a ; the next stuff is on the left had side
+		# when we see a = (not == != === !==) or <= we are on rhs
+		if    ($word =~ m/;/) { 
+		    $vstate->{rhs}=0;
+		    $vstate->{inst_link_done}  = 0;
+		    $vstate->{cur_inst}        = '$NONE';
+		    $vstate->{cur_inst_exists} = 0;
+		}
+		elsif ($word =~ m/((\A|[^=!])=(\Z|[^=!]))|<=/ ) { 
+		    $vstate->{rhs}=1;
+		}
+		print $out $qword;
+	    }
+	    elsif ($nextisdefine) {
+		if ((($f,$link_line)=&rvp::get_define($verilog_db,$word,
+						      $file,$line))&& $f && $link_line &&
+		    ($js_sigs || ($link_line!=$line))) {
+		    print_link($out,$vstate->{file},$frame_bottom,$js_sigs,
+			       hfile($f,$link_line),$link_line,$qword,"define",
+			       $vstate->{short_links},0);
+		}
+		else {
+		    print_with_font($out,"define",$qword);
+		}
+		$nextisdefine=0;
+	    }
+	    elsif ($word =~ m/^\$($VID)/o ) {
+		print_with_font($out,"systemtask",$qword);
+	    }
+	    elsif ($word =~ m/^\`/ ) {
+		# colour link 'define 'timescale etc.
+		if ( exists( $verilog_compiler_keywords_hash{$word} ) ) {
+		    print_with_font($out,"compiler",$qword);
+		    $nextisdefine = ($word eq "`ifdef" || $word eq "`ifndef" || 
+				     $word eq "`define" || $word eq "`undef");
+		}
+		# link 'defines 
+		elsif ((($f,$link_line) = &rvp::get_define($verilog_db,$word,
+							  $file,$line))  && $f && $link_line) {
+		    print " linking define $word at $line\n" if $debug;
+		    # do not link quote, makes qs work better because after `define or `ifdef
+		    #  it appears without the quote. Also looks better
+		    $qword=~s/^\`//; 
+		    print_with_font($out,"define",'`');
+		    print_link($out,$vstate->{file},$frame_bottom,$js_sigs,
+			       hfile($f,$link_line),$link_line,$qword,"define",
+			       $vstate->{short_links},0);
+		}
+		else {
+		    print_with_font($out,"define",$qword);
+		}
+	    }
+	    # link instance module names to the module definition
+	    elsif ( $word eq $vstate->{cur_inst} ) {
+		# check we have not already done it to cope with the case
+		#  where the instance name is the same as the modules name
+		if ( !$vstate->{inst_link_done} ) {
+		    if ( $vstate->{cur_inst_exists} ) {
+		      ($f,$link_line) = &rvp::get_modules_file($verilog_db,$word);
+		      print " linking module $word at $line\n" if $debug;
+		      print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+				 hfile($f,$link_line),$word,$qword,"module",
+				 $vstate->{short_links},0);
+		    }
+		    else {
+			# unlinkable instance
+			print_with_font($out,"module",$qword);
+		    }
+		    $vstate->{inst_link_done}=1;
+		}
+		else {
+		    print $out $qword;
+		}
+	    }
+	    elsif ( $word eq $vstate->{name} && $vstate->{type} eq 'module' &&
+		   $line == $vstate->{context} ) {
+		print_with_font($out,"module",$qword);
+		print $out "<a $frame_middle href=\"".
+		    index_link("Modules",$word)."\">".
+			"$icon_i<\/a>" if ($output_index);
+	    }
+	    # link .out( ) ports, set $rhs for .in( ) ports
+	    elsif ($word =~ m/^\.($VID)/o &&  $vstate->{cur_inst_exists}) {
+		if (($s_line,$s_a_line,undef,$s_type,$s_file,undef,undef,$s_type2,
+		     undef,undef,undef,$s_a_file,undef) = 
+		    &rvp::get_module_signal($verilog_db,$vstate->{cur_inst},$1)) {
+		    $vstate->{rhs}=0;
+		    $link_line = -1;
+		    $f='';
+		    $s_type2 = ($s_type2 eq 'reg') ? "_reg" : "";
+		    if ($s_type eq 'output') {
+			print " linking port .$1 at $line\n" if $debug;
+			if ($s_a_line != -1) { $link_line = $s_a_line; $f = $s_a_file;}
+			else                 { $link_line = $s_line;   $f = $s_file;}
+		    }
+		    if ($link_line != -1) {
+			print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+				   hfile($f,$link_line),$link_line,$qword,
+				   "signal_$s_type$s_type2",$vstate->{short_links},0);
+		    }
+		    else {
+			print_with_font($out,"signal_$s_type$s_type2",$qword);
+		    }
+		    if ($s_type eq 'input') { $vstate->{rhs}=1; }
+		}
+		else {
+		    # should only get here if there is a port used that
+		    #  does not exist on the submodule
+		    print $out $qword;
+		}
+	    }
+	    # link signals
+	    elsif (($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$p,$n,$s_type2,
+		    $s_src_file,$s_src_line,undef,$s_a_file,$s_i_file) = 
+		 &rvp::get_signal_by_context($verilog_db,$file,
+					 $vstate->{context},$word)) {
+
+		# figure out the link to link to the index
+		if ($output_index && $vstate->{name} && 
+		    ($vstate->{type} eq 'module')) {
+		    $index_ref=index_link("Signals","${word}___$vstate->{name}");
+		}
+		else { $index_ref = ''; }
+		# only do extra_info for module signals (not tasks or functions
+		if ($vstate->{name} && ($vstate->{type} eq 'module')) {
+		    $ex_index=signal_extra_info($word,$vstate,$index_ref,
+						[ [$s_file, $s_line],
+						  [$s_a_file, $s_a_line],
+						  [$s_i_file, $s_i_line],
+						  [$s_src_file,$s_src_line] ]);
+		}
+		else { $ex_index=0; }
+		# link the definition to the driver if you can,
+		#  otherwise do not link it to anything
+		$on_def=(($s_file eq $file) && ($s_line == $line));
+		$s_type2 = ($s_type2 eq 'reg') ? "_reg" : "";
+		if (($vstate->{rhs} || $on_def) && ($s_a_line != -1)) {
+		    $link_line = $s_a_line;
+		    $f         = $s_a_file;
+		}
+		else {
+		    # do not link to itself unless doing quick search
+ 		    if ($on_def && !$js_sigs) { $link_line = -1; $f =""; }
+ 		    else                 { $link_line = $s_line ; $f = $s_file; }
+		}
+
+		if ($on_def && ($s_i_line!=-1)) {
+		    #  link to an instantiator
+		    if ($s_i_file) {			
+			print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+				   hfile($s_i_file,$s_i_line),$s_i_line,$qword,
+				   "signal_$s_type$s_type2",$vstate->{short_links},
+				   $ex_index);
+		    }
+		    else { # we only get here in certain strange include situations
+			print_with_font($out,"signal_$s_type$s_type2",$qword);
+		    }
+		}
+		elsif ($link_line != -1) {
+		    print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+			       hfile($f,$link_line),$link_line,$qword,
+			       "signal_$s_type$s_type2",$vstate->{short_links},$ex_index);
+		}
+		else {
+		    print_with_font($out,"signal_$s_type$s_type2",$qword);
+		}
+		# put in index link - when on def, but not in quick search mode
+		if ($index_ref && $on_def && !$js_sigs) {
+		    print $out "<a $frame_middle href=\"$index_ref\">".
+		      "$icon_i<\/a>";
+		}
+
+	    }
+	    # link parameters
+	    elsif (($f,$link_line)=
+		   &rvp::get_parameter_by_context($verilog_db,$file,$vstate->{context},
+					      $word)) {
+		# do not link on definition line
+		if (($f eq $file) && (($link_line == $line)&&!$js_sigs)) {
+		    print_with_font($out,"parameter",$qword);
+		}
+		else {
+		    print " linking parameter $word at $line\n" if $debug;
+		    print_link($out,$vstate->{file},$frame_bottom,$js_sigs,
+			       hfile($f,$link_line),$link_line,$qword,
+			       "parameter",$vstate->{short_links},0);
+		}
+	    }
+	    # tasks & functions
+	    elsif (($t_type,$t_line,$t_file,$t_anchor)=
+		   &rvp::get_t_or_f_by_context($verilog_db,$file,$vstate->{context},
+					      $word)) {
+		# do not link on definition line
+		if (($t_file eq $file) && (($t_line == $line)&&!$js_sigs)) {
+		    print_with_font($out,$t_type,$qword);
+		}
+		else {
+		    print " linking $t_type $word at $line\n" if $debug;
+		    print_link($out,$vstate->{file},$frame_middle,$js_sigs,
+			       hfile($t_file,$t_line),$t_anchor,$qword,$t_type,
+			       $vstate->{short_links},0);
+		}
+	    }
+	    # colour begin end always etc.
+	    elsif ( exists( $verilog_keywords_hash{$word} ) ) {
+		print_with_font($out,"keyword",$qword);
+	    }
+	    else {
+		print $out $qword;
+	    }
+	}
+	$line++;
+    }
+    return $out;
+}
+
+#####The rest of this file is the rough verilog parser perl module#############
+###############################################################################
+#
+# File:         rvp.pm
+# RCS:          $Header: /home/cc/v2html/build/../RCS/v2html,v 7.30.1.3 2006/05/03 20:19:55 cc Exp $
+# Description:  The Rough Verilog Parser Perl Module
+# Author:       Costas Calamvokis
+# Created:      Fri Apr 10 16:59:30 1998
+# Modified:     Thu Jan 12 10:45:27 2006
+# Language:     Perl
+#
+# Copyright 1998-2006 Costas Calamvokis
+#
+#  This file nay be copied, modified and distributed only in accordance
+#  with the terms of the limited licence contained in the accompanying
+#  file LICENCE.TXT.
+#
+###############################################################################
+#
+
+=head1 rvp - Rough Verilog Parser Perl Module
+
+The basic idea is that first you call read_verilog will a list of all of your
+files. The files are parsed and information stored away. You are then 
+handed back a pointer to the information which you can use in calls
+to the various get_ function to get information about the verilog design.
+
+For Example:
+
+ #!/usr/bin/perl -w
+ use rvp;   # use the rough verilog parser
+
+ # Read in all the files specified on the command line
+ $vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
+
+ # Print out all the modules found
+ foreach $module ($vdata->get_modules()) { print "$module\n"; }
+
+Unless you are doing something very strange, you can probably ignore all
+of the functions that have the words 'context' or 'anchors' in them!
+
+=cut
+
+package rvp;
+
+#use strict;
+use File::Basename;
+
+use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp 
+	    @verilog_compiler_keywords
+	    @verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp 
+	    $quiet $debug $VID $HVID $VNUM
+	    $takenArcs
+            $baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
+            $version $VERSION);
+
+my $msort;
+
+
+BEGIN {
+    # a hack to make it match with the version that doesn't sort
+    #  the hashes. This is only done when PERL_HASH_SEED=0 ie when
+    #  hash randomising is explicitly turned off, because with
+    #  hash randomising on it won't match unless sorting is on.
+    if ( $ENV{PERL_HASH_SEED} eq "0" ) {
+	$msort = sub { return @_ };
+    }
+    else {
+	$msort = sub { return sort @_ };
+    }
+
+
+    # $VERSION is used by 'use', but keep $version for backwards compatibility
+    $version = '$Header: /home/cc/v2html/build/../RCS/v2html,v 7.30.1.3 2006/05/03 20:19:55 cc Exp $'; #'
+    $version =~ s/^\S+ \S+ (\S+) .*$/$1/;
+    $VERSION = $version; 
+
+    @verilog_signal_keywords = qw(input    output  inout  
+		       wire     tri     tri1   supply0 wand  triand tri0 
+		       supply1  wor     time   trireg  trior
+		       reg      integer real   realtime
+
+		       genvar
+		       );
+    @verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
+
+    #V2001
+
+    $verilog_sigs_regexp = "\\b(?:" . 
+	join("|",@verilog_signal_keywords) . 
+	    ")\\b";
+
+    @verilog_gatetype_keywords = qw(and  nand  or  nor xor xnor  buf  bufif0 bufif1  
+				    not  notif0 notif1  pulldown  pullup
+				    nmos  rnmos pmos rpmos cmos rcmos   tran rtran  
+				    tranif0  rtranif0  tranif1 rtranif1
+				    );
+
+    $verilog_gatetype_regexp = "\\b(?:" . 
+	join("|",@verilog_gatetype_keywords) . 
+	    ")\\b";
+
+    # Note: optimisation code in _search() assumes all of
+    #  these compiler keywords contain a ` 
+    @verilog_compiler_keywords = qw( 
+     `celldefine            `define 
+     `delay_mode_path       `disable_portfaults 
+     `else                  `enable_portfaults
+     `endcelldefine         `endif 
+     `ifdef                 `include 
+     `nosuppress_faults     `suppress_faults 
+     `timescale             `undef
+     `resetall              `delay_mode_distributed
+
+     `default_nettype  `file `line `ifndef `elsif
+    );    #`
+
+    # a verilog identifier is this reg exp 
+    #  a non-escaped identifier is A-Z a-z _ 0-9 or $ 
+    #  an escaped identifier is \ followed by non-whitespace
+    #   why \\\\\S+ ? This gets \\\S+ in to the string then when it
+    #   it used we get it searching for \ followed by non-whitespace (\S+)
+    $VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
+
+    # hierarchical VID - just $VID(.$VID)+ but can't write it like this
+    #  because of \ escaping (and must include whitespace after esc.ids.)
+    $HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
+           '(?:\.(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+))+)'; 
+  # V2001: added [sS] - is this correct
+    $VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
+
+
+    $quiet=0;
+    $debug=0;
+
+}
+
+###########################################################################
+
+=head1 read_verilog
+
+reads in verilog files, parses them and stores results in an internal 
+data structure (which I call a RVP database).
+
+  Arguments:  - reference to array of files to read (can have paths)
+              - reference to hash of defines with names as keys
+              - reference to array of global includes - not used anymore,
+                 just kept for backwards compatibility
+              - quite flag. 1=be quiet, 0=be chatty.
+              - reference to array of include directories
+              - reference to array of library directories
+              - library extension string (eg '.v') or reference to array of strings
+
+  Returns:    - a pointer to the internal data structure.
+
+  Example:
+    $defines{'TRUE'}=1;  # same as +define+TRUE=1 on verilog cmd line
+    $vdata = rvp->read_verilog(\@files,[],\%defines,1,
+				     \@inc_dirs,\@lib_dirs,\@lib_exts);
+
+=cut
+sub read_verilog {
+    # be backwards compatible with non-OO call
+    my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
+    my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
+	$lib_dirs,$lib_ext_arg,$exp)
+	= @_;
+    my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
+
+    my $self;
+
+    die "read_verilog needs an array ref as arg 1" unless "ARRAY" eq ref $files;
+    die "read_verilog needs an hash ref as arg 2" unless "HASH" eq ref $cmd_line_defines;
+    die "read_verilog needs 0 or 1 as arg 3" unless $local_quiet==0 || $local_quiet==1;
+
+    # be backwards compatible
+    if (!defined($inc_dirs)) { $inc_dirs=[]; }
+    if (!defined($lib_dirs)) { $lib_dirs=[]; }
+    
+    if (!defined($lib_ext_arg)) {  # no libexts given
+	$lib_exts=['']; 
+    }           
+    elsif (!ref($lib_ext_arg))  {  # a string given
+	$lib_exts=[$lib_ext_arg]; 
+    }
+    else {                         # an array ref given
+	$lib_exts=$lib_ext_arg; 
+    }
+
+
+    # make the parser
+    if (! defined &parse_line) {
+
+	my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
+				          [ $baseEval,$rvpEval ] ,
+				 $debug );
+	if ($debug) {
+	    open(PC,">v2html-parser.pl");
+	    print PC $perlCode;
+	}
+	eval($perlCode);
+	print STDERR $@ if ($@);
+    }
+
+    if (! defined &_parse_line) { die "Parse code generation failed";}
+
+    $old_quiet=$quiet;
+    $quiet=$local_quiet;
+    # set up top of main data structure
+    $self = {};
+    $self->{files}               = {}; # information on each file
+    $self->{modules}             = {}; # pointers to module info in {files}
+    $self->{defines}             = {};
+    $self->{ignored_modules}     = {}; # list of modules were duplicates were found
+    $self->{unresolved_modules}  = {}; # modules we have not found yet
+    $self->{problems}            = []; # warning/confused messages
+
+    bless($self,$class);
+
+    foreach my $d (keys(%$cmd_line_defines)) {
+	_add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
+    }
+
+    # go through all the files and find information
+    @new_search_files = @{$files};
+    while (@new_search_files) {
+	@search_files = @new_search_files;
+	@new_search_files = ();
+	foreach $file (@search_files) {
+	    $self->_search($file,$inc_dirs);
+	}
+	push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
+    }
+
+
+    if ($debug) {
+	_check_coverage();
+    }
+
+    # cross reference files' information
+    print "Cross referencing\n" unless $quiet;
+    $self->_cross_reference();
+    
+    $quiet=$old_quiet;
+
+    foreach my $m ( &$msort (keys %{$self->{unresolved_modules}} )) {
+	# find somewhere it is instantiated for warning message
+	my $file="";
+	my $line="";
+	foreach my $m2 (&$msort (keys %{$self->{modules}})) {
+	    foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
+		if ($inst->{module} eq $m) {
+		    $file = $inst->{file};
+		    $line = $inst->{line};
+		    last;
+		}
+	    }
+	}
+	$self->_add_warning("$file:$line: Could not find module $m");
+    }
+    return $self;
+} 
+
+###########################################################################
+
+=head1 get_problems
+
+Return any problems that happened during parsing
+
+  Returns:    - array of strings of problems. Each one is:
+                    "TYPE:FILE:LINE: description"
+
+=cut
+sub get_problems {
+    my ($self) = @_;
+    
+    return (@{$self->{problems}});
+}
+
+###########################################################################
+
+=head1 set_debug
+
+Turns on debug printing in the parser.
+
+  Returns:    - nothing
+
+=cut
+sub set_debug {
+    $debug=1;
+}
+
+###########################################################################
+
+=head1 unset_debug
+
+Turns off debug printing in the parser.
+
+  Returns:    - nothing
+
+=cut
+sub unset_debug {
+    $debug=0;
+}
+
+###########################################################################
+
+=head1 get_files
+
+Get a list of all the files in the database.
+
+  Returns:    - list of all the files
+
+  Example:   @all_files = $vdata->get_files();
+
+=cut
+sub get_files{
+    my ($self) = @_;
+
+    if (wantarray) { 
+	return &$msort (keys %{$self->{files}});
+    }
+    else { # in a scalar context keys returns the number of elements - sort doesn't
+	return keys %{$self->{files}};
+    }
+}
+
+###########################################################################
+
+=head1 get_files_modules
+
+Get a list of all the modules in a particular file.
+
+  Arguments:  - name of file
+
+  Returns:    - list of module names
+
+  Example:   @modules = $vdata->get_files_modules($file);
+
+=cut
+sub get_files_modules{
+    my ($self,$file) = @_;
+    my (@modules,$m);
+
+    foreach $m (&$msort (keys %{$self->{files}{$file}{modules}})) {
+	push(@modules,$m)
+    }
+
+    return @modules;
+}
+
+
+###########################################################################
+
+=head1 get_files_full_name
+
+Get the full name (including path) of a file.
+
+  Arguments:  - name of file
+
+  Returns:    - full path name
+
+  Example  $full_name = $vdata->get_files_full_name($file);
+
+=cut
+sub get_files_full_name{
+    my ($self,$file) = @_;
+
+    return $self->{files}{$file}{full_name};
+
+}
+
+###########################################################################
+
+=head1 get_files_stats
+
+Get statistics about a file
+
+  Arguments:  - name of file
+
+  Returns:    - number of lines in the file (more later...)
+
+  Example  $full_name = $vdata->get_files_stats($file);
+
+=cut
+sub get_files_stats{
+    my ($self,$file) = @_;
+
+    return $self->{files}{$file}{lines};
+
+}
+
+###########################################################################
+
+=head1 file_exists
+
+Test if a particular module file  in the database.
+
+  Arguments:  - file name to test.
+
+  Returns:    - 1 if exists otherwise 0
+
+  Example:   if ($vdata->file_exists($file))....
+
+=cut
+sub file_exists{
+    my ($self,$file) = @_;
+    return exists($self->{files}{_ffile($file)});
+}
+
+###########################################################################
+
+=head1 get_modules
+
+Get a list of all the modules in the database.
+
+
+  Returns:   - list of all the modules
+
+  Example:   @all_modules = $vdata->get_modules();
+
+=cut
+sub get_modules{
+    my ($self) = @_;
+
+    if (wantarray) { 
+	return &$msort (keys %{$self->{modules}});
+    }
+    else { # in a scalar context keys returns the number of elements - sort doesn't
+	return keys %{$self->{modules}};
+    }
+
+}
+
+
+###########################################################################
+
+=head1 get_modules_t_and_f
+
+Get a list of all the tasks and functions in a particular module.
+
+  Arguments:  - name of module
+
+  Returns:    - list of tasks and function names
+
+  Example:    if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
+
+=cut
+# return a list of all the tasks and functions in a module
+sub get_modules_t_and_f{
+    my ($self,$module) = @_;
+
+    if (wantarray) { 
+	return &$msort (keys %{$self->{modules}{$module}{t_and_f}});
+    }
+    else { # in a scalar context keys returns the number of elements - sort doesn't
+	return keys %{$self->{modules}{$module}{t_and_f}};
+    }
+
+}
+
+###########################################################################
+
+=head1 get_modules_t_or_f
+
+Get information on a task or function in a module.
+
+  Arguments:  - module name
+              - task or function name
+
+  Returns:    - A 4 element list: type (task or function), definition line,
+                  file, anchor
+
+  Example:    ($t_type,$t_line ,$t_file,$t_anchor)=
+		$vdata->get_modules_t_or_f($m,$tf);
+
+=cut
+sub get_modules_t_or_f{
+    my ($self,$mod,$t_or_f) = @_;
+
+    if (exists($self->{modules}{$mod}{t_and_f}{$t_or_f})) {
+	return($self->{modules}{$mod}{t_and_f}{$t_or_f}{type},
+	       $self->{modules}{$mod}{t_and_f}{$t_or_f}{line},
+	       $self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
+	       $self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_modules_signals
+
+Get a list of all the signals in a particular module.
+
+  Arguments:  - name of module
+
+  Returns:    - list of signal names
+
+  Example:    if ( @signs = $vdata->get_modules_signals($m))...
+
+=cut
+# return a list of all the tasks and functions in a module
+sub get_modules_signals{
+    my ($self,$module) = @_;
+
+    if (wantarray) { 
+	return &$msort (keys %{$self->{modules}{$module}{signals}});
+    }
+    else { # in a scalar context keys returns the number of elements - sort doesn't
+	return keys %{$self->{modules}{$module}{signals}};
+    }
+
+}
+
+###########################################################################
+
+=head1 get_modules_file
+
+Get the file name (no path) that a module is defined in.
+
+  Arguments:  - module name
+
+  Returns:    - file name without path, and the line number module starts on
+
+  Example:    ($f) = $vdata->get_modules_file($m);
+
+=cut
+# get the file name that contains a module
+sub get_modules_file{
+    my ($self,$module) = @_;
+
+    return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
+}
+
+
+###########################################################################
+
+=head1 get_modules_type
+
+Get the type of the module - It is one of: module, macromodule or primitive
+(rvp treats these all as modules).
+
+  Arguments:  - module name
+
+  Returns:    - type
+
+  Example:    $t = $vdata->get_modules_type($m);
+
+=cut
+# get the file name that contains a module
+sub get_modules_type{
+    my ($self,$module) = @_;
+
+    return ($self->{modules}{$module}{type});
+}
+
+###########################################################################
+
+=head1 get_files_includes
+
+Get the file names (no path) of files included in a file.
+
+  Arguments:  - file name
+
+  Returns:    - list of file names without paths
+
+  Example:    @f = $vdata->get_files_includes($file);
+
+=cut
+sub get_files_includes {
+    my ($self,$f) = @_;
+    my @includes_found = ();
+
+    if (exists($self->{files}{$f})) {
+	foreach my $inc ( &$msort ( keys %{$self->{files}{$f}{includes}} )) {
+	    push(@includes_found,$inc);
+	    # do the includes for the included file
+	    push(@includes_found, $self->get_files_includes($inc));
+	}
+    }
+
+    return @includes_found;
+}
+
+###########################################################################
+
+=head1 get_files_included_by
+
+Get the file names (no path) of files that included this file.
+
+  Arguments:  - file name
+
+  Returns:    - list of file names without paths
+
+  Example:    @f = $vdata->get_files_included_by($file);
+
+=cut
+sub get_files_included_by {
+    my ($self,$f) = @_;
+
+    return @{$self->{files}{$f}{included_by}};
+    
+}
+
+
+###########################################################################
+
+=head1 module_ignored
+
+Test if a particular module has been ignored because of duplicates found
+
+  Arguments:  - module name to test
+
+  Returns:    - 1 if ignored otherwise 0
+
+  Example:   if ($vdata->module_ignored($module))....
+
+=cut
+sub module_ignored {
+    my ($self,$module) = @_;
+    return (exists($self->{modules}{$module}) && 
+	    $self->{modules}{$module}{duplicate});
+}
+
+###########################################################################
+
+=head1 module_exists
+
+Test if a particular module exists in the database.
+
+  Arguments:  - module name to test
+
+  Returns:    - 1 if exists otherwise 0
+
+  Example:   if ($vdata->module_exists($module))....
+
+=cut
+sub module_exists{
+    my ($self,$module) = @_;
+    return exists($self->{modules}{$module});
+}
+
+###########################################################################
+
+=head1 get_ignored_modules
+
+Return a list of the ignored modules. These are modules where duplicates
+have been found.
+
+  Returns:    - List of ignored modules
+
+  Example:    - foreach $module ($vdata->get_ignored_modules())....
+
+=cut
+sub get_ignored_modules {
+    my ($self) = @_;
+    my @ig =();
+    foreach my $m (&$msort (keys %{$self->{modules}})) {
+	push(@ig, $m) if ($self->{modules}{$m}{duplicate});
+    }
+    return @ig;
+}
+
+###########################################################################
+
+=head1 get_module_signal
+
+Get information about a particular signal in a particular module.
+
+  Arguments:  - name of module
+              - name of signal
+
+  Returns:    - A list containing: 
+                 - the line signal is defined
+                 - the line signal is assigned first (or -1)
+                 - line in instantiating module where an input 
+                       is driven from (or -1)
+                 - the type of the signal (input,output,reg etc)
+                 - the file the signal is in
+                 - posedge flag (1 if signal ever seen with posedge)
+                 - negedge flag (1 if signal ever seen with negedge)
+                 - second type (eg reg for a registered output)
+                 - signal real source file
+                 - signal real source line
+                 - range string if any ( not including [ and ] )
+                 - the file signal is assigned first (or '')
+                 - file for the instantiating module where an input 
+                       is driven from (or "")
+                 - a pointer to an array of dimensions for memories
+                       each element of the array is a dimension, array
+                       is empty for non-memories
+
+  Note posedge and negedge information is propagated up the hierarchy to
+  attached signals. It is not propagated down the hierarchy.
+
+  Example:    ($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_p,$s_n,
+	       $s_type2,$s_r_file,$s_r_line,$range,$s_a_file,$s_i_file) = 
+                      $vdata->get_module_signal($m,$sig);
+
+=cut
+sub get_module_signal{
+    my ($self,$module,$sig) = @_;
+    
+    if (exists( $self->{modules}{$module}{signals}{$sig} )) {
+	return ($self->{modules}{$module}{signals}{$sig}{line},
+		$self->{modules}{$module}{signals}{$sig}{a_line},
+		$self->{modules}{$module}{signals}{$sig}{i_line},
+		$self->{modules}{$module}{signals}{$sig}{type},
+		$self->{modules}{$module}{signals}{$sig}{file},
+		$self->{modules}{$module}{signals}{$sig}{posedge},
+		$self->{modules}{$module}{signals}{$sig}{negedge},
+		$self->{modules}{$module}{signals}{$sig}{type2},
+		$self->{modules}{$module}{signals}{$sig}{source}{file},
+		$self->{modules}{$module}{signals}{$sig}{source}{line},
+		$self->{modules}{$module}{signals}{$sig}{range},
+		$self->{modules}{$module}{signals}{$sig}{a_file},
+		$self->{modules}{$module}{signals}{$sig}{i_file},
+		$self->{modules}{$module}{signals}{$sig}{dimensions});
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_first_signal_port_con
+
+Get the first port that this signal in this module is connected to.
+
+  Arguments:  - module name
+              - signal name
+
+  Returns:    - a 5 element list: instantiated module name, instance name
+                  port name, line number and file
+
+  Example:    ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
+
+=cut
+sub get_first_signal_port_con{
+    my ($self,$module,$signal) = @_;
+
+    $self->{current_signal_port_con}       =0;
+    $self->{current_signal_port_con_module}=$module;
+    $self->{current_signal_port_con_module_signal}=$signal;
+
+    return $self->get_next_signal_port_con();
+}
+
+###########################################################################
+
+=head1 get_next_signal_port_con
+
+Get the next port that this signal in this module is connected to.
+
+  Returns:    - a 5 element list: instantiated module name, instance name
+                  port name, line number and file
+
+  Example:    ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
+
+=cut
+sub get_next_signal_port_con{
+    my ($self) = @_;
+    my ($module,$signal,$i,$pcref);
+
+    $module = $self->{current_signal_port_con_module};
+    $signal = $self->{current_signal_port_con_module_signal};
+    $i      = $self->{current_signal_port_con};
+
+    $pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
+    if (@{$pcref} > $i ) {
+	$self->{current_signal_port_con}++;
+	return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
+		$pcref->[$i]{line},$pcref->[$i]{file});
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_first_signal_con_to
+
+Get the first signal that is connected to this port in an
+instantiation of this module. This only works for instances that use
+the .port(sig) notation.
+
+  Arguments:  - module name
+              - signal name
+
+  Returns:    - a 4 element list: signal connected to this port
+                                  module signal is in
+		                  instance (of this module) where the connection
+			            occurs
+
+  Example:    ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
+
+=cut
+sub get_first_signal_con_to{
+    my ($self,$module,$signal) = @_;
+
+    $self->{current_signal_con_to}       =0;
+    $self->{current_signal_con_to_module}=$module;
+    $self->{current_signal_con_to_module_signal}=$signal;
+
+    return $self->get_next_signal_con_to();
+}
+
+###########################################################################
+
+=head1 get_next_signal_con_to
+
+Get the next signal that is connected to this port in an
+instantiation of this module. This only works for instances that use
+the .port(sig) notation.
+
+  Arguments:  - module name
+              - signal name
+
+  Returns:    - a 4 element list: signal connected to this port
+                                  module signal is in
+		                  instance (of this module) where the connection
+			            occurs
+
+  Example:    ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
+
+=cut
+sub get_next_signal_con_to{
+    my ($self) = @_;
+    my ($module,$signal,$i,$ctref);
+
+    $module = $self->{current_signal_con_to_module};
+    $signal = $self->{current_signal_con_to_module_signal};
+    $i      = $self->{current_signal_con_to};
+
+    $ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
+    if (@{$ctref} > $i ) {
+	$self->{current_signal_con_to}++;
+	return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_first_instantiator
+
+Get the first thing that instantiates this module.
+
+  Arguments:  - module name
+
+  Returns:    - a 4 element list: instantiating module, file, instance name, line
+
+  Example:    
+		($im,$f,$i) = $vdata->get_first_instantiator($m );
+
+=cut
+# Get the first thing that instantiates or empty list if none.
+#  Returns: { module, file, inst }
+sub get_first_instantiator{
+    my ($self,$module) = @_;
+
+    if ( exists( $self->{modules}{$module} )) {
+	$self->{current_instantiator}       =0;
+	$self->{current_instantiator_module}=$module;
+	return $self->get_next_instantiator();
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_next_instantiator
+
+Get the first thing that instantiates the module specified in 
+get_first_instantiator (or _by_context).
+
+  Returns:    - a 4 element list: instantiating module, file, 
+                                    instance name, line
+
+  Example:    
+		($im,$f,$i) = $vdata->get_next_instantiator();
+
+=cut
+sub get_next_instantiator{
+    my ($self) = @_;
+    my ($module,$i);
+
+    $module = $self->{current_instantiator_module};
+    $i      = $self->{current_instantiator};
+
+    if (@{$self->{modules}{$module}{inst_by}} > $i ) {
+	$self->{current_instantiator}++;
+	return ($self->{modules}{$module}{inst_by}[$i]{module},
+	        $self->{modules}{$module}{inst_by}[$i]{file},
+		$self->{modules}{$module}{inst_by}[$i]{inst},
+		$self->{modules}{$module}{inst_by}[$i]{line} );
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_first_instantiation
+
+Get the first thing that this module instantiates.
+
+  Arguments:  - module name
+
+  Returns:    - a 4 element list: instantiated module name, file, 
+                  instance name, and line number
+
+  Example:    
+		($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
+
+=cut
+sub get_first_instantiation{
+    my ($self,$module) = @_;
+
+    if ( exists( $self->{modules}{$module} )) {
+	$self->{current_instantiation}       =0;
+	$self->{current_instantiation_module}=$module;
+	return $self->get_next_instantiation();
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_next_instantiation
+
+Get the next thing that this module instantiates.
+
+
+  Returns:    - a 4 element list: instantiated module name, file, 
+                  instance name, and line number
+
+  Example:    
+		($im,$f,$i,$l) = $vdata->get_next_instantiation();
+
+=cut
+sub get_next_instantiation{
+    my ($self) = @_;
+    my ($module,$i);
+
+    $module = $self->{current_instantiation_module};
+    $i      = $self->{current_instantiation};
+
+    if (@{$self->{modules}{$module}{instances}} > $i ) {
+	$self->{current_instantiation}++;
+	return ($self->{modules}{$module}{instances}[$i]{module},
+	        $self->{modules}{$module}{instances}[$i]{file},
+		$self->{modules}{$module}{instances}[$i]{inst_name},
+		$self->{modules}{$module}{instances}[$i]{line} );
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_current_instantiations_port_con
+
+Gets the port connections for the current instantiations (which is got
+using get_first_instantiation and get_next_instantiation). If the 
+instantiation does not use .port(...) syntax and rvp does not have the
+access to the source of the module then the port names will be returned as
+numbers in connection order starting at 0.
+
+
+  Returns:    - A hash (well, really a list that can be assigned to a hash). 
+               The keys of the hash are the port names. The values of the
+               hash is everything (except comments) that appeared in the 
+               brackets in the verilog.
+
+  Example:    %port_con = $vdata->get_current_instantiations_port_con();
+	      foreach $port (keys %port_con) { ...
+
+=cut
+sub get_current_instantiations_port_con{
+    my ($self) = @_;
+    my ($module,$i);
+
+    $module = $self->{current_instantiation_module};
+    $i      = $self->{current_instantiation} -  1;
+
+    if (@{$self->{modules}{$module}{instances}} > $i ) {
+	return (%{$self->{modules}{$module}{instances}[$i]{connections}});
+    }
+    else {
+	return {};
+    }
+}
+
+###########################################################################
+
+=head1 get_current_instantiations_parameters
+
+Gets the parameters for the current instantiations (which is set using
+get_first_instantiation and get_next_instantiation).  If the
+instantiation parameters does not use the verilog 2001 .name(...)
+syntax and rvp does not have the access to the source of the module
+then the parameter names will be returned as numbers reflecting the
+order (starting at 0).
+
+
+  Returns:    - A hash (well, really a list that can be assigned to a hash). 
+               The keys of the hash are the parameters names. The values of the
+               hash is everything (except comments) in the value.
+
+  Example:    %parameters = $vdata->get_current_instantiations_parameters();
+	      foreach my $p (keys %parameters) { ...
+
+=cut
+sub get_current_instantiations_parameters{
+    my ($self) = @_;
+    my ($module,$i);
+
+    $module = $self->{current_instantiation_module};
+    $i      = $self->{current_instantiation} -  1;
+
+    my %r;
+    if (@{$self->{modules}{$module}{instances}} > $i ) {
+	foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
+	    $r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
+	}
+    }
+
+    return %r;
+}
+
+###########################################################################
+
+=head1 get_modules_parameters
+
+Gets the parameters for a module.
+
+  Arguments:  - module name
+
+  Returns:    - A hash (well, really a list that can be assigned to a hash). 
+               The keys of the hash are the parameters names. The values of the
+               hash is everything (except comments) in the value.
+
+  Example:    %parameters = $vdata->get_modules_parameters();
+	      foreach my $p (keys %parameters) { ...
+
+=cut
+sub get_modules_parameters{
+    my ($self,$module) = @_;
+
+    my %r;
+    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
+	$r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
+    }
+    return %r;
+}
+
+
+###########################################################################
+
+=head1 get_define
+
+Find out where a define is defined and what the value is
+
+  Arguments:  - name of the define
+             Optional arguments where a you want the correct location and
+               value for a particular use of a multiplely defined define:
+              - file where define is used 
+              - line where define is used
+
+  Returns:    - list with three elements: file, line, value
+                 or if the define does not exist it returns a empty list.
+                 if the define was defined on the command line it sets file=""
+                  and line=0
+
+
+  Example:    ($f,$l,$v) = $vdata->get_define($word,$file,$line);
+
+=cut
+sub get_define {
+    my ($self,$define,$file,$line) = @_;
+
+    if ( !defined($self) || !defined($define) ||
+	 ( defined($file) && !defined($line) ) ) {
+	die "Get define takes either two or four arguments";
+    }
+
+    $define =~ s/^\`// ; # remove the ` if any
+
+    if (!exists( $self->{defines}{$define} )) {
+	return ();
+    }
+    my $index = 0;
+    my $dh = $self->{defines}{$define};
+
+    if (defined($file) &&
+	exists($dh->{used}{$file}) &&
+	exists($dh->{used}{$file}{$line})) {
+	$index = $dh->{used}{$file}{$line};
+    }
+
+
+    if ($index eq "XX") {   # define has been undefed
+	return ();
+    }
+
+    return ( $dh->{defined}[$index]{file},
+	     $dh->{defined}[$index]{line},
+	     $dh->{defined}[$index]{value});
+}
+
+###########################################################################
+
+=head1 get_context
+
+Get the context (if any) for a line in a file.
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - line number if there is a context, zero if there is none.
+
+  Example:    	$l = $vdata->get_context($filename,$line);
+
+=cut
+sub get_context{
+    my ($self,$file,$line) = @_;
+
+    if ( exists( $self->{files}{$file}{contexts}{$line} )) {
+	return $line;
+    }
+    else {
+	return 0;
+    }
+}
+
+###########################################################################
+
+=head1 get_module_start_by_context
+
+Test if the context is a module definition start.
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - module name if it is a module start, 0 otherwise
+
+  Example:     if($vdata->get_module_start_by_context($filename,$line))..
+
+=cut
+# return true if the context for this line is a module start
+sub get_module_start_by_context{
+    my ($self,$file,$line) = @_;
+
+    if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
+	return $self->{files}{$file}{contexts}{$line}{module_start};
+    }
+    else {
+	return 0;
+    }
+}
+
+###########################################################################
+
+=head1 get_has_value_by_context
+
+Check if the context has a value (ie a new module or something). Contexts
+that just turn on and off preprocessor ignoring do not have values.
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - 1 if there is a value, 0 otherwise
+
+  Example:    if ($vdata->get_has_value_by_context($file,$line))..
+
+=cut
+sub get_has_value_by_context{
+    my ($self,$file,$line) = @_;
+
+    return exists( $self->{files}{$file}{contexts}{$line}{value});
+}
+
+###########################################################################
+
+=head1 get_context_name_type
+
+Find the reason for a new context - is it a module / function or task.
+Contexts that just turn on and off preprocessor ignoring do not have values.
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - name
+              - type [ module | function | task ]
+
+  Example:    ($n,$t)=$vdata->get_context_name_type($file,$line);
+
+=cut
+sub get_context_name_type{
+    my ($self,$file,$line) = @_;
+    my ($name,$type);
+
+    $type='';
+    if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
+	$name= $self->{files}{$file}{contexts}{$line}{value}{name};
+	if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
+	    $type=$self->{files}{$file}{contexts}{$line}{value}{type};
+	    $type='module' if ($type eq 'primitive' || $type eq 'macromodule');
+	}
+	return ($name,$type);
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 get_pre_ignore_by_context
+
+Test if the context is preprocessor ignore.
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - 1 if it is, 0 otherwise
+
+  Example:    if ($vdata->get_pre_ignore_by_context($file,$line))..
+
+=cut
+sub get_pre_ignore_by_context{
+    my ($self,$file,$line) = @_;
+    
+    if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
+	return $self->{files}{$file}{contexts}{$line}{pre_ignore};
+    }
+    else {
+	return 0;
+    }
+
+}
+
+###########################################################################
+
+=head1 get_first_instantiator_by_context
+
+Get the first thing that instantiates this module using the context. The
+context must be a module_start.
+
+  Arguments:  - file name (for context) 
+              - line name (for context)
+
+  Returns:    - a 4 element list: instantiating module, file, instance name, line
+
+  Example:    
+	      @i=$vdata->get_first_instantiator_by_context($f,$l );
+
+=cut
+sub get_first_instantiator_by_context{
+    my ($self,$file,$line) = @_;
+
+    # note: the second exists() checks that the module still exists as
+    #  it could have been deleted because a duplicate was found
+    if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
+	exists($self->{modules}
+	       {$self->{files}{$file}{contexts}{$line}{module_start}}) &&
+	exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
+	$self->{current_instantiator}       =0;
+	$self->{current_instantiator_module}=
+	    $self->{files}{$file}{contexts}{$line}{module_start};
+	return $self->get_next_instantiator();
+    }
+    else {
+	return ();
+    }
+
+}
+
+###########################################################################
+
+=head1 get_inst_on_line
+
+Gets the instance name of a line in a file
+
+  Arguments:  - file name
+              - line number
+
+  Returns:    - name if the line has an instance name, 0 otherwise
+
+  Example:    if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
+
+=cut
+sub get_inst_on_line{
+    my ($self,$file,$line) = @_;
+
+    if ( exists( $self->{files}{$file}{instance_lines}{$line})){
+	return $self->{files}{$file}{instance_lines}{$line};
+    }
+    else {
+	return 0;
+    }
+}
+
+###########################################################################
+
+=head1 get_signal_by_context
+
+Same as get_module_signal but works by specifying a context.
+
+  Arguments:  - context file name
+              - context line number
+              - signal name
+
+  Returns:    same as get_module_signal
+
+  Example:    
+
+=cut
+# get a signal by context - returns: line, a_line, i_line, type, file
+sub get_signal_by_context{
+    my ($self,$file,$cline,$sig) = @_;
+
+    my $sigp;
+
+    # in tasks and functions signals can come from module (m_signals)
+    #  or from the task or function itself (which gets precedence).
+    if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
+	print " found signal $sig\n" if $debug;
+	$sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
+    }
+    elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
+	print " found m_signal $sig\n" if $debug;
+	$sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
+    }
+    else {
+	return ();
+    }
+
+    return ($sigp->{line},
+	    $sigp->{a_line},
+	    $sigp->{i_line},
+	    $sigp->{type},
+	    $sigp->{file},
+	    $sigp->{posedge},
+	    $sigp->{negedge},
+	    $sigp->{type2},
+	    $sigp->{source}{file},
+	    $sigp->{source}{line},
+	    $sigp->{range},
+	    $sigp->{a_file},
+	    $sigp->{i_file},
+	    $sigp->{dimensions});
+}
+
+###########################################################################
+
+=head1 get_t_or_f_by_context
+
+Same as get_modules_t_or_f but works by specifying a context.
+
+  Arguments:  - context file name
+              - context line number
+              - task name
+
+  Returns:    - same as get_modules_t_or_f
+
+  Example:    
+
+=cut
+sub get_t_or_f_by_context{
+    my ($self,$cfile,$cline,$t_or_f) = @_;
+
+    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f})) {
+	return($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{type},
+	       $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{line},
+	       $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{file},
+	       $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
+    }
+    else {
+	return ();
+    }
+}
+###########################################################################
+
+=head1 get_parameter_by_context
+
+Return the file and line for a named parameter using context
+
+  Arguments:  - context file name
+              - context line number
+              - parameter name
+
+  Returns:    - file and line of definition
+
+  Example:    
+
+=cut
+sub get_parameter_by_context{
+    my ($self,$cfile,$cline,$parameter) = @_;
+
+    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
+	return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
+	       $self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
+    }
+    else {
+	return ();
+    }
+}
+###########################################################################
+
+=head1 get_anchors
+
+Get the anchors for a line in a file.
+
+
+  Returns:    - a list of anchors
+
+  Example:   foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
+
+=cut
+sub get_anchors{
+    my ($self,$file,$line) = @_;
+
+    if (exists($self->{files}{$file}{anchors}{$line})) {
+	return @{$self->{files}{$file}{anchors}{$line}};
+    }
+    else {
+	return ();
+    }
+}
+
+###########################################################################
+
+=head1 expand_defines
+
+Expand the defines in a line of verilog code.  for best use this
+should be called line by line, so that the defines get the correct
+values when defines are defined multiple times
+
+  Arguments:  - a pointer to the string to expand the defines in
+              - the file the line is from
+              - the line number of the line
+
+  Returns:    - nothing
+
+  Example:   $vdata->expand_defines(\$line_to_expand,$file,$line);
+
+=cut
+###############################################################################
+#
+sub expand_defines {
+    my ($self,$bufp,$file,$line) = @_;
+
+    if (exists($self->{files}{$file}{define_lines}{$line})) {
+	# do not expand on a `define line - it doesn't make sense to do so
+	#  as the substitution of defines in the value only occurs at the
+	#  time of use when they could have different values!
+	return;
+    }
+
+
+    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) { 
+	my $b = $1;
+	my $d = $2;
+	my $dq = quotemeta($d);
+	my $v;
+        if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
+	    $$bufp =~ s/\`$dq/$v/;
+	}
+	else {
+	    $$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
+	}
+
+    }
+    $$bufp =~ s/_BaCkQuOtE_/\`/g;
+}
+
+
+###########################################################################
+
+=head1 verilog_gatetype_keywords
+
+
+  Returns:    - a list of verilog gatetype keywords
+
+  Example:   @keywords = rvp->verilog_gatetype_keywords();
+
+=cut
+sub verilog_gatetype_keywords {
+    return (@verilog_gatetype_keywords);
+}
+###########################################################################
+
+=head1 verilog_compiler_keywords
+
+  Returns:    - a list of verilog compiler keywords
+
+  Example:   @keywords = rvp->verilog_compiler_keywords();
+
+=cut
+sub verilog_compiler_keywords {
+    return (@verilog_compiler_keywords);
+}
+###########################################################################
+
+=head1 verilog_signal_keywords
+
+  Returns:    - a list of verilog signal keywords
+
+  Example:   @keywords = rvp->verilog_signal_keywords();
+
+=cut
+sub verilog_signal_keywords {
+    return (@verilog_signal_keywords);
+}
+
+
+###########################################################################
+
+=head1 chunk_read_init
+
+Initialise a file for chunk reading (see chunk_read for more
+details). It actually reads the whole file into a string, which
+chunk_read then reads a chunk at a time. The file is closed before
+chuck_read_init returns.
+
+  Arguments:  - the file to read (with path if needed)
+              - tabstop: 0 = leave tabs alone
+                         N = turn tabs spaces with each tabstop=N
+  Returns:    - a handle to pass to chunk_read or 0 if file open fails
+
+  Example:    
+            my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
+
+=cut
+sub chunk_read_init {
+
+    my ($class,$f,$tabstop) = @_;
+    local (*F);
+
+    open(F,"<$f") || return 0;
+
+    my $chunk = { type => "", 
+		  text => "", 
+		  isANewLine => 0, 
+		  isStart => 0, 
+		  isEnd => 1 ,
+		  line => 0 };
+
+    my $this = { chunk => $chunk , 
+		 tabstop => $tabstop ,
+	         linebuf => "" ,
+	         state => 0 ,
+		 fh => *F };
+    return $this;
+}
+
+###########################################################################
+
+=head1 chunk_read
+
+Reads verilog a chunk at a time. The file is opened using
+chunk_read_init. Then chunk_read is used to read the file a chunk at a
+time.  A chunk is a line or part of a line that is all the same type.
+
+  The types are: 
+              comment   - either // or /* */ comment
+              attribute - verilog 2001 (* *) atribute
+              include   - a line containing `include "file"
+              string    - a string
+              code      - anything else (verilog code, defines, compliler keywords)
+
+Nothing is removed from the file, so if each chunk is printed after being read
+you will end up with exactly the same file as you put in.
+
+  Arguments:  - handle (from chunk_read_init)
+
+  Returns:    - 0 at the end of file, or a hash ref with the following keys:
+              type       - one of the types (see above)
+              text       - the text read from the file
+	      line       - the line number the text is on
+              isANewLine - true if chunk is the first chunk of the line
+              isStart    - true if the chunk is the start (eg "/*..." for 
+                             a comment )
+              isEnd      - true if the chunk is the end ( eg "*/" )
+                      NOTE: isEnd is set to undefined for a
+                       type="code" that ends in a newline. This is
+                       because chunk_read doesn't know if the code is
+                       ending or not. If you need to know in this case
+                       you can read the next chunk and see what type it is.
+
+  Example:    
+            my $chunkRead = rvp->chunk_read_init($f,0);
+            while ($chunk = rvp->chunk_read($chunkRead)) {
+                    print $chunk->{text} unless $chunk->{type} eq "comment";
+            }
+
+=cut
+sub chunk_read {
+   my ($class,$this) = @_;
+
+   my $chunk = $this->{chunk};
+   $chunk->{isStart} = $chunk->{isEnd};
+   $chunk->{isEnd}  = 0;
+   $chunk->{isANewLine} = 0;
+
+   if ( $this->{linebuf} eq "" ) {
+       if (!defined($this->{linebuf} = readline($this->{fh}))) {
+	   close($this->{fh});
+	   return 0;
+       }
+       $chunk->{isANewLine} = 1;
+       $chunk->{line}++;
+       if ($this->{tabstop}!=0) {
+	   # 1 while is some stupid perl thing meaning while (cond) {} may be a bit faster?
+	   1 while ($this->{linebuf} =~ s/(^|\n)([^\t\n]*)(\t+)/
+		    $1. $2 . (" " x ($this->{tabstop} * length($3) - 
+				     (length($2) % $this->{tabstop})))
+		    /gsex);
+       }
+   }
+       
+ STATE_SWITCH:
+   if ( $this->{state} == 0 ) {
+       $chunk->{type} = "code";
+       if ( $this->{linebuf} =~ 
+	    s%^(.*?)((/\*)|           # anything followed by /* comment
+		     (//)|            #    or // comment
+		     (\(\*(?!\s*\)))| #    or (* attribute (but not (*)
+		     (\`include\s)|   #    or `include
+		     (\"))            #    or start of string   
+	    %$2%ox ) {
+	   $chunk->{isEnd} = 1;
+	   $chunk->{text} = $1;
+	   if (defined($3)) {
+	       $this->{state} = 1;  # long comment
+	   }
+	   elsif (defined($4)) {
+	       $this->{state} = 2;  # short comment
+	   }
+	   elsif (defined($5)) {
+	       $this->{state} = 3;  # attribute
+	   }
+	   elsif (defined($6)) {
+	       $this->{state} = 4;  # include
+	   }
+	   elsif (defined($7)) {
+	       $this->{state} = 5;  # string
+	   }
+	   else {
+	       die "chunk_read internal error!";
+	   }
+	   if (!$chunk->{text}) { 
+	       # this happens if we are in state code and a new line
+	       #  starts with something that isn't code. So we change
+	       #  and go back to the top.
+	       $chunk->{isStart} = 1; 
+	       $chunk->{isEnd}  = 0;
+	       goto STATE_SWITCH;
+	   }
+       }
+       else {
+	   $chunk->{text} = $this->{linebuf};
+	   $this->{linebuf} = "";
+	   # in this case we might be at end, but we don't really know!
+	   $chunk->{isEnd}  = undef;
+       }
+   }
+   elsif ( $this->{state} == 1 ) {
+       $chunk->{type} = "comment";
+       # this first test is needed to work so /*/  */ works
+       if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
+	   $chunk->{text} = "/*";
+       }
+       else {
+	   $chunk->{text} = "";
+       }
+       if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) {          # anything followed by */
+	   $chunk->{text} .= $1;
+	   $this->{state} = 0;
+	   $chunk->{isEnd} = 1;
+       }
+       else {
+	   $chunk->{text} .= $this->{linebuf};
+	   $this->{linebuf} = "";
+       }
+   }
+   elsif ( $this->{state} == 2 ) {
+       $chunk->{type} = "comment";
+       $chunk->{text} = $this->{linebuf};
+       $chunk->{isEnd} = 1;
+       $this->{linebuf} = "";
+       if ( $chunk->{text} =~ s/\n$// ) {
+	   $this->{linebuf} = "\n";
+       }
+       $this->{state} = 0;
+   }
+   elsif ( $this->{state} == 3 ) {
+       $chunk->{type} = "attribute";
+       if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) {          # anything followed by *)
+	   $chunk->{text} = $1;
+	   $this->{state} = 0;
+	   $chunk->{isEnd} = 1;
+       }
+       else {
+	   $chunk->{text} = $this->{linebuf};
+	   $this->{linebuf} = "";
+       }
+   }
+   elsif ( $this->{state} == 4 ) {
+       $chunk->{type} = "include";
+       $chunk->{isEnd} = 1;
+       if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {  
+	   $chunk->{text} = $1;
+	   $this->{state} = 0;
+       }
+       else {
+	   # this is an error - just return the line as code - the parser will 
+	   #  report the error
+	   $chunk->{type} = 0;
+	   $chunk->{text} = $this->{linebuf};
+	   $this->{linebuf} = "";
+       }
+   }
+   elsif ( $this->{state} == 5 ) {
+       $chunk->{type} = "string";
+       # string all on one line
+       if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
+	   $chunk->{text} = $1;
+	   $this->{state} = 0;
+	   $chunk->{isEnd} = 1;
+       }
+       # end of multiline string (doesn't start with quote)
+       elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
+	   $chunk->{text} = $1;
+	   $this->{state} = 0;
+	   $chunk->{isEnd} = 1;
+       }
+       # middle of multiline string
+       else { 
+	   $chunk->{text} = $this->{linebuf};
+	   $this->{linebuf} = "";
+       }
+   }
+
+   return $chunk;
+}
+
+###############################################################################
+#  RVP internal functions from now on.... (they all start with _ to 
+#   let you know they are internal
+###############################################################################
+
+###############################################################################
+# search a file, putting the data in $self
+#   Note: be careful coding in the main loop... there are a few optimisations
+#    which result in big chunks of code being skipped if the line does not
+#    contain certain characters (eg ' " / *)
+sub _search {
+    my ($self,$f,$inc_dirs) = @_;
+
+    my $verilog_compiler_keywords_regexp = "(?:" . 
+	join("|",@verilog_compiler_keywords) . 
+	    ")";
+
+
+    my $file=_ffile($f);
+    _init_file($self->{files},$f);
+
+    print "Searching $f " unless $quiet;
+    my $chunkRead= rvp->chunk_read_init($f,0) || 
+	die "Error: can not open file $f to read: $!\n";
+    my $file_dir = dirname($f);
+
+    my $rs = {};
+    $rs->{modules}   = $self->{modules};
+    $rs->{files}     = $self->{files};
+    $rs->{unres_mod} = $self->{unresolved_modules};
+    
+    $rs->{module}   = '';
+    $rs->{function} = '';
+    $rs->{task}     = '';
+    $rs->{t}        = undef; # temp store
+    $rs->{p}        = undef;
+
+    my $printline = 1000;
+
+    my $ps = {};
+    my $nest=0;
+    my $nest_at_ignore;
+    my @ignore_from_elsif;
+    my $ignoring=0;
+    my @fileStack =();
+    my $pp_ignore;
+    my $chunk;
+    while (1) {
+	while ($chunk = rvp->chunk_read($chunkRead)) {
+	    $self->{files}{$file}{lines} = $chunk->{line};
+	    if ($chunk->{line}>$printline && !$quiet) {
+		$printline+=1000;
+		$|=1; # turn on autoflush
+		print ".";
+		$|=0 unless $debug; # turn off autoflush
+	    }
+	    
+	    # deal quickly with blank lines
+	    if ( $chunk->{text} =~ m/^\s*\n/ ) {
+		next;
+	    }
+
+
+	    if ( $chunk->{type} eq "code" ) {
+
+		
+		####################################################
+		# Optimisation: if there are no ` 
+		#  we can parse the line now
+		if ( $chunk->{text} !~ m|[\`]| ) { 
+		    if ($nest && $ignoring) {
+			next;
+		    }
+		    $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
+		    next;
+		}
+
+		# handle ifdefs
+		if ($nest && $ignoring) {
+		    if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
+			print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
+			$nest++;
+		    }
+		    elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
+			print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
+			if ($1 eq 'else' || 
+			    _parsing_is_defined($self->{defines},$2,
+						$file,$chunk->{line})) {
+			    # true elsif or plain else
+			    if ($nest == $nest_at_ignore && 
+				!$ignore_from_elsif[$nest]) {
+				$ignoring=0;
+				$$pp_ignore = $chunk->{line};
+			    }
+			}
+		    }
+		    elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
+			print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
+			if ($nest == $nest_at_ignore) {
+			    $ignoring=0;
+			    $$pp_ignore = $chunk->{line};
+			}
+			$nest--;
+		    }
+		    next;
+		}
+		# handle the case where the endif is on the same line as the ifdef
+		#  (note: generally I only accept endif at the start of a line)
+		if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
+		    print "$file: ifdef and endif on same line\n" if $debug;
+		    my $is_defined = _parsing_is_defined($self->{defines},$2,
+							 $file,$chunk->{line});
+		    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
+			 (($1 eq 'ifndef') &&  $is_defined)) {
+			# replace ifdef with nothing
+			$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
+		    }
+		    else {
+			# replace ifdef with what is between the ifdef and endif
+			$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
+		    }
+		}
+		if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
+		    $nest++;
+		    print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
+		    my $is_defined = _parsing_is_defined($self->{defines},$2,
+							 $file,$chunk->{line});
+		    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
+			 (($1 eq 'ifndef') &&  $is_defined)) {
+			$ignoring=1;
+			$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
+			$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
+			$nest_at_ignore=$nest;
+			$ignore_from_elsif[$nest]=0;
+		    }
+		    next;
+		}
+		if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
+		    print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
+		    if ($nest) {
+			$ignoring=1;
+			$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
+			$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
+			$nest_at_ignore=$nest;
+			# an ignore from an elsif means you will never stop ignoring
+			#   at this nest level
+			$ignore_from_elsif[$nest]=($1 ne 'else');
+		    }
+		    else {
+			$self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
+		    }
+		    next;
+		}
+		if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
+		    print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
+		    if ($nest) {
+			$nest--;
+		    }
+		    else {
+			$self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
+		    }
+		    next;
+		}
+		
+		# match define. Note: /s makes the .* match the \n too
+		if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
+		    my $def = $1;
+		    my $rest = defined($2)?$2:'';
+		    my $defLine = $chunk->{line};
+		    $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
+
+		    # _parsing_expand_defines is called to register the use 
+		    #  of any multiplely defined defines in the value part of 
+		    #  the define
+		    my $tmpValue=$rest;
+		    $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
+
+		    # handle multiline defines: read more stuff if line ends in backslash
+		    #  (revisit: verilog spec says leave the newline in the value)
+		    # also keep adding stuff to value until it ends in a newline or comment
+		    #  because strings are seperated out, `define T $display("test")
+		    #  is delivered as chunks '`define T $display(' ,'"test"', ')\n'
+		    while ( (($rest =~ s|\\\n|| ) ||  ($rest !~ m/\n$/) )
+			    && ($chunk = rvp->chunk_read($chunkRead))) {
+			last if $chunk->{type} eq "comment";
+			$rest .= $chunk->{text};
+			$self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
+			# _parsing_expand_defines call: see comment ~15 lines back
+			my $tmpValue=$chunk->{text};
+			$self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
+		    }
+		    my $value = $rest;
+		    $value =~ s/^\s+(.*)(\n)?/$1/;
+
+		    print " Found in $file line $defLine : define $def = $value\n"
+			if $debug;
+		    _add_define($self->{defines}, $def , $value , $file, $defLine );
+		    _add_anchor($self->{files}{$file}{anchors},$defLine,"");  
+		    # Don't substitute now: [defines] shall be substituted after the 
+		    # original macro is substituted, not when it is defined(1364-2001 pg353)
+		    next;
+		}
+		
+		if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
+		    _undef_define($self->{defines},$1);
+		    print " Found at line $chunk->{line} : undef $1\n" if $debug;
+		    next;
+		}
+		
+		if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
+		    next;
+		}
+		$self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
+	    
+		# Note this is called from two other places (optimisations)
+		$self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
+	    }
+	    elsif ( $chunk->{type} eq "include" ) {
+		if ($nest && $ignoring) {
+		    next;
+		}
+		
+		$chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
+		# revisit - need to check for recursive includes
+		print " Found at line $chunk->{line} : include $1\n" if $debug;
+		$self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
+		my $inc_file = $1;
+		my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
+		if ($inc_file_and_path) {
+		    push(@fileStack,$chunkRead,$f);
+		    $f = $inc_file_and_path;
+		    $file=_ffile($f);
+		    $file_dir = dirname($f);
+		    
+		    if (!exists($self->{files}{$file})) {
+			_init_file($self->{files},$f);
+			if (exists($rs->{modules}{$rs->{module}})) {
+			    $self->{files}{$file}{contexts}{"1"}{value} = 
+				$rs->{modules}{$rs->{module}};
+			}
+		    }
+		    print "\n Include: $f " unless $quiet;
+		    $chunkRead=rvp->chunk_read_init($f,0);
+		}
+		else {
+		    $self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
+		}
+		next;
+	    }
+	    
+	    if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
+		$$pp_ignore = $chunk->{line};
+	    }
+	}
+	# check if we were included from another file
+	if (0==scalar(@fileStack)) {
+	    print "Stack is empty\n" if $debug;
+	    last;
+	}
+	else {
+	    $f    = pop(@fileStack);
+	    $chunkRead = pop(@fileStack);
+	    $file = _ffile($f);
+	    $file_dir = dirname($f);
+	    print "\n Back to $f" unless $quiet;
+	}
+    }
+
+    print "\n" unless $quiet;
+
+    $self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
+    
+}
+
+sub _open_file {
+    my ($f) = @_;
+    local (*F);
+
+    print "Searching $f " unless $quiet;
+    open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
+    return *F;
+}
+
+# only for use while parsing - returns the last defined value
+#  in a multiple define case, and also sets up the {used} info
+#  for use later when querying the database
+# returns ($value,$errcode)
+#  where $errcode = 0  value ok
+#                   1  value never defined
+#                   2  value has been undefined
+sub _parsing_get_define_value {
+    my ($defines,$define,$file,$line) = @_;
+
+    if (!exists( $defines->{$define} )) {
+	return ('',1);
+    }
+    my $index = 0;
+    my $dh = $defines->{$define};
+
+    if ( 1 < @{$dh->{defined}} ) {
+	$index = $#{$dh->{defined}};
+
+	$dh->{used}{$file}{$line} = $index;
+    }
+
+    if ($dh->{defined}[$index]{undefed}) {
+	$dh->{used}{$file}{$line} = "XX";
+	return ('',2);
+    }
+	 
+    return  ( $dh->{defined}[$index]{value} , 0 );
+}
+
+sub _parsing_is_defined {
+    my ($defines,$define,$file,$line) = @_;
+
+    my $v;
+    my $errcode;
+    ($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
+    if ( ($errcode == 1)  ||   # never defined
+	 ($errcode == 2) ) {   # defined then undefed
+	return 0;
+    }
+    elsif ($errcode == 0) {
+	return 1;
+    }
+    else {
+	die "parsing_is_defined internal error code=$errcode";
+    }
+}
+
+sub _undef_define {
+    my ($defines,$define) = @_;
+
+    if (exists( $defines->{$define} )) {
+	my $index = $#{$defines->{$define}{defined}};
+	$defines->{$define}{defined}[$index]{undefed} = 1;
+    }
+}
+
+###############################################################################
+# for best use this should be called line by line, so that the
+#  defines get the correct values when defines are defined multiple
+#  times
+# - this function is only used during the initial parsing of the files
+#  (it has the error reproting code in it), use expand_defines() other times
+#  it also expands on define lines (used to register the use of multiple
+#   define defines) which expand_defines doesn't
+#
+sub _parsing_expand_defines {
+    my ($self,$bufp,$file,$line) = @_;
+    
+    my $defines = $self->{defines};
+    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) { 
+	my $b = $1;
+	my $d = $2;
+	my $dq = quotemeta($d);
+	my $v;
+	my $errCode=0;
+	($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
+
+	if ($errCode == 0) {  # no error
+	    $$bufp =~ s/\`$dq/$v/;
+	}
+	else {
+	    if ($errCode == 2) {  # defined but then undefed
+		$self->_add_warning("$file:$line: define `$d used after undef");
+		$$bufp =~ s/\`$dq//;
+	    }
+	    elsif ($b =~ m/^\s*$/) {
+		$self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
+		$$bufp='';
+	    }
+	    else {
+		$self->_add_warning("$file:$line: found undefined define `$d");
+		$$bufp =~ s/\`$dq//;
+	    }
+	}
+    }
+}
+
+###############################################################################
+# Look through all the include/library directories for an include/library file
+#  optional $file_dir is used when including - here a relative path is
+#   relative to the file doing the including, so check this it checks this
+sub _scan_dirs {
+    my ($fname,$inc_dirs,$file_dir) = @_;
+    my ($dir);
+
+    if ( $fname =~ m|^/| ) { # an absolute path
+      return "$fname" if ( -r "$fname" && ! -d "$fname");
+    }
+    if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
+	return "$file_dir/$fname";
+    }
+    else {
+      foreach $dir (@{$inc_dirs}) {
+	  $dir =~ s|/$||;
+	  return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
+      }
+    }
+    return '';
+}
+
+###############################################################################
+# Take a look through the unresolved modules , delete any that have already
+#  been found, and for the others look on the search path
+#
+sub _resolve_modules {
+    my ($self,$lib_dirs, $lib_exts)= @_;
+    my ($m,$file,@resolved,$lib_ext);
+
+    @resolved=();
+    foreach $m (&$msort (keys %{$self->{unresolved_modules}})) {
+	if ( exists( $self->{modules}{$m} )) {
+	    delete( $self->{unresolved_modules}{$m} );
+	}
+	else {
+	    foreach $lib_ext (@{$lib_exts}) {
+		if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
+		    delete( $self->{unresolved_modules}{$m} );	
+		    print "resolve_modules: found $m in $file\n" if $debug;
+		    push(@resolved,$file);
+		    last;
+		}
+	    }
+	}
+    }
+    return @resolved;
+}
+
+
+###############################################################################
+# Initialize fdata->{files}{FILE} which stores file data
+#
+sub _init_file {
+    my ($fdataf,$file) = @_;
+    my ($fb);
+    $fb = _ffile($file);
+    $fdataf->{$fb} = {};                 # set up hash for each file
+    $fdataf->{$fb}{full_name} = $file;   
+    $fdataf->{$fb}{anchors}  = {};
+    $fdataf->{$fb}{modules}  = {};
+    $fdataf->{$fb}{contexts} = {};
+    $fdataf->{$fb}{includes} = {};
+    $fdataf->{$fb}{inc_done} = 0;
+    $fdataf->{$fb}{lines}    = 0;
+    $fdataf->{$fb}{instance_lines} = {};
+    $fdataf->{$fb}{define_lines} = {};
+    $fdataf->{$fb}{included_by} = [];
+
+}
+
+###############################################################################
+# Initialize fdata->{FILE}{modules}{MODULE} which stores 
+#  module (or macromodule or primitive) data
+#
+sub _init_module {
+    my ($modules,$module,$file,$line,$type) = @_;
+
+
+    die "Error: attempt to reinit module" if (exists($modules->{$module}));
+
+    $modules->{$module}{line}     = $line;
+    $modules->{$module}{name}     = $module;
+    $modules->{$module}{type}     = $type;
+    $modules->{$module}{end}       = -1;
+    $modules->{$module}{file}      = $file;
+    $modules->{$module}{t_and_f}   = {}; # tasks and functions
+    $modules->{$module}{signals}   = {};
+    $modules->{$module}{parameter_order}= [];
+    $modules->{$module}{parameters}= {};
+    $modules->{$module}{instances} = []; # things that this module instantiates
+    $modules->{$module}{inst_by}   = []; # things that instantiated this module
+    $modules->{$module}{port_order} = []; 
+    $modules->{$module}{named_ports} = 1; # assume named ports in instantiations
+    $modules->{$module}{duplicate} = 0;   # set if another definition is found
+
+}
+
+###############################################################################
+# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
+#  stores tasks and functions' data
+#
+sub _init_t_and_f {
+    my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
+
+    if (exists($module->{t_and_f}{$tf})) {
+	$self->_add_warning("$file:$line new definition of $tf ".
+		    "(discarding previous from ".
+		    "$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
+    }
+    $module->{t_and_f}{$tf} = {};
+    $module->{t_and_f}{$tf}{type}      = $type;
+    $module->{t_and_f}{$tf}{name}      = $tf;
+    $module->{t_and_f}{$tf}{line}      = $line;
+    $module->{t_and_f}{$tf}{end}       = -1;
+    $module->{t_and_f}{$tf}{file}      = $file;
+    $module->{t_and_f}{$tf}{signals}   = {};
+    $module->{t_and_f}{$tf}{anchor}    = $anchor;
+    # point up at things to share with module:
+    #  - task and functions
+    #  - module signals
+    $module->{t_and_f}{$tf}{t_and_f}    = $module->{t_and_f}; 
+    $module->{t_and_f}{$tf}{parameters} = $module->{parameters}; 
+    $module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order}; 
+    $module->{t_and_f}{$tf}{m_signals}  = $module->{signals};
+}
+
+# note returns 1 if a signal is added (and an anchor needs to be dropped)
+sub _init_signal  { 
+    my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
+
+    if (exists( $signals->{$name} )) {
+	if ($warnDuplicate) {
+	    if (($signals->{$name}{type} eq "output")||
+		($signals->{$name}{type} eq "inout")||
+		($signals->{$name}{type} eq "input")) {
+		if (($signals->{$name}{type} eq "input")
+		    && ($type eq "reg")) {
+		    $self->_add_warning("$file:$line: ignoring definition".
+				" of input $name as reg (defined as input at". 
+				" $signals->{$name}{file}:$signals->{$name}{line})");
+		}
+		else {
+		    $signals->{$name}{type2}=$type;
+		}
+	    }
+	    elsif (($signals->{$name}{type} eq "reg")&&  # reg before output
+		   (($type eq "output") ||
+		    ($type eq "inout"))) {
+		$signals->{$name}{type}=$type;
+		$signals->{$name}{type2}="reg";
+	    }
+	    else {
+		$self->_add_warning("$file:$line: ignoring another definition".
+			    " of signal $name ($type) first seen as". 
+			    " $signals->{$name}{type} at".
+			    " $signals->{$name}{file}:$signals->{$name}{line}");
+	    }
+	}
+	return 0;
+    }
+    else {
+	$signals->{$name} = { type     => $type, 
+			      file     => $file,
+			      line     => $line,
+			      a_line   => -1,
+			      a_file   => "",
+			      i_line   => -1,
+			      i_file   => "",
+			      port_con => [],
+			      con_to   => [],
+			      posedge  => 0,
+			      negedge  => 0,
+			      type2    => $type2,
+			      source   => { checked => 0, file => "" , 
+					    line => "" },
+			      range    => $range,
+			      dimensions => $dims,
+			      };
+	return 1;
+    }
+}
+
+###############################################################################
+# Add an anchor to the list of anchors that need to be put in
+#  the file
+#
+sub _add_anchor {
+    my ($anchors,$line,$name) = @_;
+
+    my ($a,$no_name_exists);
+
+    if (! exists($anchors->{$line}) ) {
+	$anchors->{$line} = [];
+    }
+
+    if ( $name ) {
+	push( @{$anchors->{$line}} , $name );
+    }
+    else {
+	# if no name is specified then you'll get the line number
+	#  as the name, but make sure this only happens once
+	$no_name_exists = 0;
+	foreach $a ( @{$anchors->{$line}} ) {
+	    if ($a eq $line) {
+		$no_name_exists=1;
+		last;
+	    }
+	}
+	push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
+    }
+}
+
+sub _add_define {
+    my ($defines,$def_name,$def_value,$file,$line) = @_;
+
+    $def_value = '' if (!defined($def_value));
+    $def_value =~ s/\s+$//; # remove whitespace from end of define
+
+    if (!exists($defines->{$def_name})) {
+	$defines->{$def_name} = { defined => [] , used => {} };
+    }
+
+    if ( (1 == @{$defines->{$def_name}{defined}}) && 
+	 ($defines->{$def_name}{defined}[0]{file} eq $file) &&
+	 ($defines->{$def_name}{defined}[0]{line} == $line) ) {
+	# if the define is already defined once (and only once) and that 
+	#  was the same def (file & line the same - for instance in included
+	#   file) then there is no need to do anything
+    }
+    else {
+	push (@{$defines->{$def_name}{defined}},
+	      { line => $line, file => $file ,
+		value => $def_value, undefed => 0 });
+    }
+}
+
+###############################################################################
+#   Cross referencing
+###############################################################################
+
+###############################################################################
+# Cross-reference all the files:
+#  - find the modules and set up $self->{modules}
+#  - store the data about where it is instatiated with each module
+#  - check for self instantiation
+#  - check for files with modules + instances outside modules
+#  - set a_line for signals driven by output and i_line
+#
+sub _cross_reference {
+    my ($self) = @_;
+    my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
+
+    # stores the instantiation data in an 
+    #  array so that we can easily tell which modules
+    #  are disconnected and which are the tops of the
+    #  hierarchy and makes it easier to go up
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	print " Making inst_by for $m\n" if $debug;
+	foreach $m2 (&$msort (keys %{$self->{modules}})) {
+	    foreach $inst (@{$self->{modules}{$m2}{instances}}) {
+		if (($inst->{module} eq $m) &&
+		    exists($self->{modules}{$m})) {
+		    print "    inst by $m2\n" if $debug;
+		    push( @{$self->{modules}{$m}{inst_by}}, 
+			   { module => $m2,
+			     file   => $inst->{file},
+		             inst   => $inst->{inst_name} ,
+			     line   => $inst->{line} } );
+		}
+	    }
+	}
+    }
+
+    # Find any modules that appear to instantiate themselves
+    #  (to prevent getting into infinite recursions later on)
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	print " Checking  self instantiations for $m\n" if $debug;
+	foreach $inst (@{$self->{modules}{$m}{instances}}) {
+	    if ($inst->{module} eq $m) {
+		$self->_add_warning("$inst->{file}:$inst->{line}: $m ".
+			    "instantiates itself");
+		$inst->{module} = '_ERROR_SELF_INSTANTIATION_'; 
+		# remove the port con for all signals not attached
+		foreach $sig (&$msort (keys %{$self->{modules}{$m}{signals}})) {
+		    $sigp = $self->{modules}{$m}{signals}{$sig};
+		    my $port_con_ok=[];
+		    foreach $port_con (@{$sigp->{port_con}}) {
+			if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
+			else {  print " Deleting connection for $sig\n" if $debug; }
+		    }
+		    $sigp->{port_con} = $port_con_ok;
+		}
+	    }
+	}
+    }
+
+    # Go through instances without named ports (port will be a number instead) and
+    #  resolve name if you can, otherwise delete. These can appear in signal's port_con
+    #  lists and in instances connections lists.
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	if (0 == $self->{modules}{$m}{named_ports}) {
+	    $f = $self->{modules}{$m}{file}; # for error messages
+	    print " Resolving numbered port connections in $m\n" if $debug;
+	    foreach $sig (&$msort (keys %{$self->{modules}{$m}{signals}})) {
+		print "   doing $sig\n" if $debug;
+		$sigp = $self->{modules}{$m}{signals}{$sig};
+
+		foreach $port_con (@{$sigp->{port_con}}) {
+		    if ($port_con->{port} =~ m/^[0-9]/ ) {
+			if ( exists( $self->{modules}{$port_con->{module}}) ) {
+			    $m2 = $self->{modules}{$port_con->{module}};
+			    if (defined($m2->{port_order}[$port_con->{port}])) {
+				$port_con->{port}=$m2->{port_order}[$port_con->{port}];
+			    }
+			    else {
+				$self->_add_warning("$port_con->{file}:$port_con->{line}:".
+					    " could not resolve port number to name");
+			    }
+			}
+		    }
+		}
+	    }
+
+	    foreach $inst (@{$self->{modules}{$m}{instances}}) {
+		if ( exists( $self->{modules}{$inst->{module}}) ) {
+		    $m2 = $self->{modules}{$inst->{module}};
+		    foreach $port (&$msort (keys %{$inst->{connections}})) {
+			last if ($port !~ m/^[0-9]/); # if any are named, all are named
+			if (defined($m2->{port_order}[$port])) {
+			    # move old connection to named port
+			    $inst->{connections}{$m2->{port_order}[$port]} =
+				$inst->{connections}{$port};
+			    # remove old numbered port from hash
+			    delete($inst->{connections}{$port});
+			}
+			else {
+			    $self->_add_warning("$inst->{file}:$inst->{line}:".
+					"could not resolve port number $port to name)");
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    # Go through all instances with parameter lists and try to resolve names parameter
+    #  
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	foreach $inst (@{$self->{modules}{$m}{instances}}) {
+	    if ($inst->{parameters}) {
+		if ( exists( $self->{modules}{$inst->{module}}) ) {
+		    my $mp=$self->{modules}{$inst->{module}};
+		    foreach my $p (&$msort (keys %{$inst->{parameters}})){
+			last if ( $p !~ m/^[0-9]+$/ );
+			my $pn = $mp->{parameter_order}[$p];
+			if ($pn) {
+			    $inst->{parameters}{$pn} =
+				$inst->{parameters}{$p};
+			    delete($inst->{parameters}{$p});
+			    print "$inst->{parameters}{$pn}{file}:".
+				"$inst->{parameters}{$pn}{line}: ".
+			        "Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
+				  if $debug;
+			}
+			else {
+			    $self->_add_warning("$inst->{parameters}{$p}{file}:".
+					"$inst->{parameters}{$p}{line} ".
+					"could not resolve parameter number $p to name");
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    # Go through all the modules and each signal inside
+    #  looking at whether the signal is connected to any outputs
+    #   (set the a_line on the first one if it is not already set)
+    #  Also, when you see a signal connected to an input (and that
+    #   submod is only instantiated once) reach down into the submod
+    #   and set the i_line of that signal, so that clicking on the
+    #   input can pop you up to the line that input is driven in
+    #   one of the instantiations
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	print " Finding port connections in $m\n" if $debug;
+	foreach $sig (&$msort (keys %{$self->{modules}{$m}{signals}})) {
+	    print "   checking signal $sig\n" if $debug;
+	    $sigp = $self->{modules}{$m}{signals}{$sig};
+
+	    foreach $port_con (@{$sigp->{port_con}}) {
+		if ( exists( $self->{modules}{$port_con->{module}}) ) {
+		    print "    connection to $port_con->{module}\n" if $debug;
+		    $m2 = $self->{modules}{$port_con->{module}};
+		    if (exists( $m2->{signals}{$port_con->{port}})) {
+			push(@{$m2->{signals}{$port_con->{port}}{con_to}}, 
+			     { signal => $sig , module => $m , inst => $port_con->{inst}});
+			if ( ($m2->{signals}{$port_con->{port}}{type} eq 
+			      'output') &&
+			    ($sigp->{a_line} == -1)) {
+			    $sigp->{driven_by_port}=1;
+			    $sigp->{a_line} = $port_con->{line};
+			    $sigp->{a_file} = $port_con->{file};
+			    _add_anchor($self->{files}{$port_con->{file}}{anchors},
+				       $port_con->{line},'');
+			}
+			elsif ($m2->{signals}{$port_con->{port}}{type} eq 
+			       'input') {
+			    $m2->{signals}{$port_con->{port}}{driven_by_port}=1;
+			    if (scalar(@{$m2->{inst_by}}) &&
+				($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
+				$m2->{signals}{$port_con->{port}}{i_line}=
+				  $port_con->{line};
+				$m2->{signals}{$port_con->{port}}{i_file}=
+				  $port_con->{file};
+				_add_anchor($self->{files}{$port_con->{file}}{anchors},
+					   $port_con->{line},'');
+				print "    set i_line $port_con->{port} ".
+				    "$port_con->{file}:$port_con->{line}\n" if $debug;
+			    }
+			}
+		    }
+		}
+	    }
+	}
+    }
+
+    # find all signal sources
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	print " Finding signal sources in $m\n" if $debug;
+	foreach $sig (&$msort (keys %{$self->{modules}{$m}{signals}})) {
+	    $sigp = $self->{modules}{$m}{signals}{$sig};
+	    next if $sigp->{source}{checked};
+	    print "   finding signal source for $sig of $m\n" if $debug;
+	    $sigp->{source} = $self->_find_signal_source($sigp);
+	}
+    }
+    
+    # propagate the posedge, negedge stuff up the hierarchy
+    foreach $m (&$msort (keys %{$self->{modules}})) {
+	# only do the recursion for top level modules
+	if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
+	    $self->_prop_edges($m);
+	}
+    }
+    
+    # get included_by information
+    foreach $f ( &$msort (keys %{$self->{files}} )) {
+	foreach $i ($self->get_files_includes($f)) {
+	    if (exists $self->{files}{$i}) {
+		push( @{$self->{files}{$i}{included_by}} , $f );
+	    }
+	}
+    }
+}
+
+sub _find_signal_source {
+    my ($self,$sigp) = @_;
+    my ($con_to,$port_con,$ret_val);
+
+    if ($sigp->{source}{checked}) {
+	print "     source already found\n" if $debug;
+	$ret_val = $sigp->{source};
+    }
+    else {
+	$ret_val =  { checked => 1, file => '' , line => '' };
+	if (exists($sigp->{driven_by_port})) {
+	    print "     drive by port\n" if $debug;
+	    foreach $con_to (@{$sigp->{con_to}}) {
+#		if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
+		if ($sigp->{type} eq 'input') {
+		    print "       following input $con_to->{signal} $con_to->{module} $con_to->{inst}\n" if $debug;
+		    if (!exists($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{i_line})) { die "Error: $con_to->{signal} does not exist $!"; }
+		    $ret_val = $self->_find_signal_source(
+					      $self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
+		}
+	    }
+	    foreach $port_con (@{$sigp->{port_con}}) {
+		if (exists ($self->{modules}{$port_con->{module}})) {
+		    if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
+			if ($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}}{type} eq 'output') {
+			    print "       following output $port_con->{port} $port_con->{module} $port_con->{inst}\n" if $debug;
+			    $ret_val = $self->_find_signal_source(
+							  $self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
+			}
+		    }
+		    else {
+			$self->_add_warning("$port_con->{file}:$port_con->{line}:".
+				    " Connection to nonexistent port ".
+				    " $port_con->{port} of module $port_con->{module}");
+		    }
+		}
+	    }
+	}
+	else {
+	    if ($sigp->{a_line}==-1) {
+		if ($sigp->{type} eq 'input') {
+		    print "     signal is an input not driven at higher level\n" if $debug;
+		    $ret_val =  { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
+		}
+		else {
+		    print "     signal has unknown source\n" if $debug;
+		}
+	    }
+	    else {
+		print "     signal is driven in this module\n" if $debug;
+		$ret_val =  { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
+	    }
+	}
+    }
+
+    $sigp->{source} = $ret_val;
+    return $ret_val;
+}
+
+###############################################################################
+# Propagate posedge and negedge attributes of signals up the hierarchy
+#
+sub _prop_edges {
+    my ($self,$m) = @_;
+    my ($imod,@inst,$sig,$sigp,$port_con,$m2);
+
+    print "Prop_edges $m\n" if $debug;
+
+    for ( ($imod) = $self->get_first_instantiation($m) ;
+	  $imod;
+	  ($imod) = $self->get_next_instantiation()) {
+	push(@inst,$imod) if (exists( $self->{modules}{$imod}));
+    }
+    foreach $imod (@inst) { $self->_prop_edges($imod); }
+
+    # Propagate all the edges up the hierarchy
+    foreach $sig (&$msort (keys %{$self->{modules}{$m}{signals}})) {
+	print "   checking signal $sig\n" if $debug;
+	$sigp = $self->{modules}{$m}{signals}{$sig};
+	
+	foreach $port_con (@{$sigp->{port_con}}) {
+	    if ( exists( $self->{modules}{$port_con->{module}}) ) {
+		print "    connection to $port_con->{module}\n" if $debug;
+		$m2 = $self->{modules}{$port_con->{module}};
+		if (exists( $m2->{signals}{$port_con->{port}})) {
+		    print "Propagating posedge on $sig from $port_con->{module} to $m\n" 
+			if ($debug && (!$sigp->{posedge})  && $m2->{signals}{$port_con->{port}}{posedge});
+		    $sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
+		    $sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
+		}
+	    }
+	}
+    }
+}
+
+
+###############################################################################
+# given a source file name work out the file without the path
+#
+sub _ffile {
+    my ($sfile) = @_;
+
+    $sfile =~ s/^.*[\/\\]//;
+
+    return $sfile;
+}
+
+sub _add_warning {
+    my ($self,$p) = @_;
+
+    print "Warning:$p\n" if $debug;
+    push (@{$self->{problems}},"Warning:$p");
+}
+sub _add_confused {
+    my ($self,$p) = @_;
+
+    print "Confused:$p\n" if $debug;
+    push (@{$self->{problems}},"Confused:$p");
+}
+
+###############################################################################
+# 
+BEGIN {
+$baseEval = {
+  START => {
+    MODULE => '$rs->{t}={ type=>$match, line=>$line };',
+  },
+  MODULE => {
+    SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
+    # if you add to this also edit {AFTER_INST}{COMMA}
+    INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 , 
+                        params=>{}, param_number=>0 , portName=>"" , vids=>[]};', 
+  },
+  MODULE_NAME => {
+    NAME => 'my $nState="MODULE_PPL"; 
+             my $type = $rs->{t}{type};  $rs->{t}=undef;',
+  },
+  IN_CONCAT => {
+    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
+  },
+  IN_BRACKET => {
+    VID => 'IN_CONCAT:VID',
+  },
+  SCALARED_OR_VECTORED => {
+    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
+  },
+  SIGNAL_NAME => {
+    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
+  },
+  SIGNAL_AFTER_EQUALS => {
+    END => '$rs->{t}=undef;',
+  },
+  INST_PARAM_BRACKET => {
+    NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
+  },
+  INST_NAME => {
+    VID => '$rs->{t}{name}=$match;',
+  },
+  INST_PORTS => {
+    COMMA => '$rs->{t}{port}++;',
+  },
+  INST_PORT_NAME => {
+    NAME => '$rs->{t}{portName}=$match;
+             $rs->{t}{vids} = [];', # throw away any instance parameters picked up
+  },
+  INST_NAMED_PORT_CON => {
+    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
+  },
+  INST_NAMED_PORT_CON_AFTER => {
+    COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
+                 my @vids = @{$rs->{t}{vids}};
+                 my $portName = $rs->{t}{portName};
+                 $rs->{t}{portName}=""; 
+                 $rs->{t}{vids}=[];',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+  },
+  INST_NUMBERED_PORT => {
+    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
+  },
+  AFTER_INST => {
+    SEMICOLON => '$rs->{t}=undef;',
+    COMMA     => '$rs->{t}{line}=$line;
+                  $rs->{t}{name}="";
+                  $rs->{t}{port}=0;
+                  $rs->{t}{portName}="";
+                  $rs->{t}{vids}=[];',
+  },
+  SIGNAL_AFTER_NAME => {
+    SEMICOLON => '$rs->{t}=undef;',
+  },
+  IN_EVENT_BRACKET => {
+    EDGE => '$rs->{t}={ type=>$match };',
+  },
+  IN_EVENT_BRACKET_EDGE => {
+    VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
+  },
+  STMNT => {
+    ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};', 
+    HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};', 
+    CONCAT             => '$rs->{t}={ vids=>[]};', 
+  },
+  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
+    EQUALS    => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;', 
+# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
+#    SEMICOLON => '$rs->{t}=undef;', 
+    BRACKET   => '$rs->{t}=undef;', 
+  },
+  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
+    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
+  },
+  IN_SIG_RANGE => {
+    END => '$rs->{t}{range}=$fromLastPos;',
+  },
+  IN_MEM_RANGE => {
+    END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
+  },
+  ANSI_PORTS_TYPE => { # V2001 ansi ports
+    TYPE =>  '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
+  },
+  ANSI_PORTS_TYPE2 => { # V2001 ansi ports
+    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
+  },
+  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
+    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
+  },
+};
+
+############################################################
+# debugEval
+############################################################
+$debugEval = {
+  ANSI_PORTS_SIGNAL_NAME => {
+    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
+  },
+  SIGNAL_NAME => {
+    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
+  },
+  INST_BRACKET => {
+    PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
+  },
+  INST_NAMED_PORT_CON_AFTER => {
+    COMMA => 'my @vidnames; 
+            foreach my $vid (@vids) {push @vidnames,$vid->{name};}
+            print " Port $portName connected to ".join(",",@vidnames)."\n";',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+  },
+  INST_NUMBERED_PORT => {
+    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+  },
+};
+
+
+############################################################
+# rvpEval
+############################################################
+
+$rvpEval = {
+  MODULE => {
+    ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
+                         (($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
+		     $self->_add_warning("$file:$line: module of type".
+                                 " $rs->{p}{type} ended by $match");
+	          }
+	          $rs->{modules}{$rs->{module}}{end} = $line;
+	          $rs->{module}   = "";
+	          $rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
+                  $rs->{p}= undef;',
+    PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
+  },
+  MODULE_NAME => {
+    NAME => 'if (exists($rs->{modules}{$match})) {
+                 $nState = "IGNORE_MODULE";
+	         $rs->{modules}{$match}{duplicate} = 1;
+	         $self->_add_warning("$file:$line ignoring new definition of ".
+                          "module $match, previous was at ".
+		          "$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
+             }
+             else {
+               $rs->{module}=$match;
+               _init_module($rs->{modules},$rs->{module},$file,$line,$type);
+	       $rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
+  	       _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module});
+  	       $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};
+  	       $rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
+             }',
+  },
+  MODULE_PORTS => {
+    VID => 'push(@{$rs->{p}{port_order}},$match);',
+  },
+  FUNCTION => {
+    NAME => '$rs->{function}=$match;
+                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
+		      $rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
+	              _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}."_".$rs->{function});
+                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}};',
+  },
+  TASK => {
+    NAME => '$rs->{task}=$match;
+  	              $self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
+		                   $rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
+ 	              _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}. "_" . $rs->{task});
+                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}};',
+  },
+  ENDTASK => {
+    ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
+                $rs->{task}="";
+	        $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
+  },
+  T_SIGNAL => {
+     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
+     ENDTASK => 'ENDTASK:ENDTASK',
+     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
+  },
+  ENDFUNCTION => {
+      ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
+                     $rs->{function}="";
+	             $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
+  },
+  F_SIGNAL => {
+     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
+     ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
+     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
+  },
+  BLOCK_SIGNAL => {
+     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
+  },
+  PARAM_NAME => {
+    NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions 
+              $rs->{t}= { file => $file, line => $line , value => "" ,
+                          ptype => $rs->{t}{ptype}}; # ptype is same as the last one
+              push(@{$rs->{p}{parameter_order}}, $match) 
+                    unless ($rs->{t}{ptype} eq "localparam");
+              $rs->{p}{parameters}{$match}=$rs->{t};
+	      _add_anchor($rs->{files}{$file}{anchors},$line,""); }',
+  },
+  PPL_PARAM => {
+     PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
+  },
+  PPL_NAME => {
+     NAME => 'PARAM_NAME:NAME',
+  },
+  PARAM_AFTER_EQUALS => {
+    COMMA     => '$rs->{t}{value} = $fromLastPos;',
+    SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
+  },
+  PPL_AFTER_EQUALS => {
+     COMMA   => 'PARAM_AFTER_EQUALS:COMMA',
+     END     => 'PARAM_AFTER_EQUALS:COMMA',
+  },
+  ASSIGN => {
+    VID => 'if ( exists($rs->{p}{signals}{$match}) &&
+		              ($rs->{p}{signals}{$match}{a_line} == -1)) {
+	       $rs->{p}{signals}{$match}{a_line} = $line;
+	       $rs->{p}{signals}{$match}{a_file} = $file;
+               _add_anchor($rs->{files}{$file}{anchors},$line,"");
+	    }',
+  },
+  SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
+    VID => 'if ($rs->{t}{block} != 1) {
+              $self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
+                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
+               && _add_anchor($rs->{files}{$file}{anchors},$line,"");
+            }',
+  },
+  SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is 
+                         #   only the initial value
+    ASSIGN => 'if ($rs->{t}{block} != 1) {
+                if ( $rs->{p}{signals}{$rs->{t}{name}}{type} ne "reg" ) {
+                  $rs->{p}{signals}{$rs->{t}{name}}{a_line}=$rs->{t}{line};
+                  $rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
+	          _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
+                }
+               }',
+  },
+  INST_PARAM_VALUE => {
+    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
+    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
+    #   and the second uses $match to capture the parameter value
+    COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
+              $rs->{t}{params}{$rs->{t}{param_number}} = 
+                     { file => $file , line => $line , value => $fromLastPos };
+              $rs->{t}{param_number}++;',
+    END   => 'INST_PARAM_VALUE:COMMA',
+  },
+  INST_PARAM_BRACKET => {
+    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
+    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
+    #   and the second uses $match to capture the parameter value
+    NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
+              $rs->{t}{params}{$rs->{t}{param_number}} = 
+                     { file => $file , line => $line , value => $match };
+              $rs->{t}{param_number}++;',
+  },
+  INST_BRACKET => {
+    PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
+	      $rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
+	      push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} , 
+					       inst_name => $rs->{t}{name} ,
+					       file => $file,
+					       line => $rs->{t}{line},
+                                               parameters => $rs->{t}{params},
+					       connections => {} });
+	      _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
+                         $rs->{module}."_".$rs->{t}{name});',
+  },
+  INST_NAMED_PORT_CON_AFTER => {
+    COMMA =>   'my $inst_num= $#{$rs->{p}{instances}};
+              $rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
+	      if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
+                 $rs->{p}{named_ports} = 0;
+              }
+              else { # remove the bracket from the end if a named port
+                 $rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
+              }
+	      foreach my $s (@vids) {
+                $self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
+                    && _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
+		 push( @{$rs->{p}{signals}{$s->{name}}{port_con}}, 
+		        { port   => $portName ,
+                          line   => $s->{line},
+                          file   => $file,
+		          module => $rs->{t}{mod} ,
+		          inst   => $rs->{t}{name} });
+              }',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+  },
+  INST_NUMBERED_PORT => {
+    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
+  },
+  IN_EVENT_BRACKET_EDGE => {
+    VID => 'if (exists($rs->{p}{signals}{$match})) { 
+               $rs->{p}{signals}{$match}{$edgeType}=1; };',
+  },
+
+  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
+    EQUALS => 'foreach my $s (@vids) {
+                 my $sigp = undef;
+	         if ( exists($rs->{p}{signals}{$s->{name}} )) {
+                      $sigp = $rs->{p}{signals}{$s->{name}};
+                 }
+	         elsif ( exists($rs->{p}{m_signals}) &&
+                         exists($rs->{p}{m_signals}{$s->{name}}) ) {
+                      $sigp = $rs->{p}{m_signals}{$s->{name}};
+                 }
+                 if (defined($sigp) && ($sigp->{a_line}==-1)) {
+		      $sigp->{a_line}=$s->{line};
+		      $sigp->{a_file}=$file;
+		      _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
+	         }
+               }',
+  },
+  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
+    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
+  },
+  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
+    VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
+                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
+            push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
+            _add_anchor($rs->{files}{$file}{anchors},$line,"");',
+  },
+};
+
+############################################################
+# language definition
+############################################################
+
+$vid_vnum_or_string = 
+[ { arcName=> 'HVID',   regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
+  { arcName=> 'VID',    regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
+  { arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
+  { arcName=> 'STRING', regexp=> '\\"',   nextState=> ['IN_STRING','$ps->{curState}'],},
+];
+
+$languageDef =
+[
+ { 
+ stateName =>     'START',
+ confusedNextState => 'START',
+ search => 
+  [
+   { arcName   => 'MODULE' ,        regexp => '\b(?:module|macromodule|primitive)\b',
+     nextState => ['MODULE_NAME'] ,},
+   { arcName   => 'CONFIG',        regexp => '\bconfig\b', # V2001
+     nextState => ['CONFIG'] , },
+   { arcName   => 'LIBRARY',        regexp => '\blibrary\b', # V2001
+     nextState => ['LIBRARY'] , },
+  ],
+ },
+ { 
+ stateName =>     'MODULE',
+ confusedNextState => 'MODULE',
+ search => 
+  [
+   { arcName   => 'ENDMODULE' ,     regexp => '\b(?:end(?:module|primitive))\b',
+     nextState => ['START'] ,  },
+   { arcName   => 'FUNCTION',       regexp => '\bfunction\b',
+     nextState => ['FUNCTION'] , },
+   { arcName   => 'TASK',           regexp => '\btask\b',
+     nextState => ['TASK'] ,  },
+   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
+     nextState => ['PARAM_TYPE','MODULE'] ,  },
+   { arcName   => 'SPECIFY',        regexp => '\bspecify\b',
+     nextState => ['SPECIFY'] , },
+   { arcName   => 'TABLE',          regexp => '\btable\b',
+     nextState => ['TABLE'] ,  },
+   { arcName   => 'EVENT_DECLARATION' ,    regexp => '\bevent\b' ,
+     nextState => ['EVENT_DECLARATION'] ,  },
+   { arcName   => 'DEFPARAM' ,       regexp => '\bdefparam\b' ,
+     nextState => ['DEFPARAM'] , },
+   { arcName   => 'GATE' ,           regexp => "$verilog_gatetype_regexp" ,
+     nextState => ['GATE'] ,   },
+   { arcName   => 'ASSIGN' ,         regexp => '\bassign\b' ,
+     nextState => ['ASSIGN'] , },
+   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
+     nextState => ['DRIVE_STRENGTH','MODULE'] , },
+   { arcName   => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
+     nextState => ['STMNT','MODULE'] , },
+   { arcName   => 'GENERATE',       regexp => '\bgenerate\b', # V2001
+     nextState => ['GENERATE'] , },
+
+
+   { arcName   => 'INST',          regexp    => '$VID' ,
+     nextState => ['INST_PARAM'] , },
+   # don't put any more states here because $VID matches almost anything
+   ],
+ },################ END OF MODULE STATE
+ {
+ stateName =>     'MODULE_NAME',
+ search =>   # $nState is usually MODULE_PPL, but is set to
+             #   IGNORE_MODULE when a duplicate module is found
+  [ { arcName   => 'NAME',  regexp => '$VID' , nextState => ['$nState'] , }, ],
+ },
+ {
+ stateName =>     'IGNORE_MODULE' ,  # just look for endmodule
+ allowAnything => 1, 
+ search => [ 
+   { arcName   => 'ENDMODULE' , regexp    => '\bendmodule\b',
+     nextState => ['START'], }, 
+   @$vid_vnum_or_string, 
+  ],
+ },
+ {
+ stateName =>     'MODULE_PPL' ,  # v2001 module_parameter_port_list (A.1.3)
+ failNextState => ['MODULE_PORTS'],
+ search => [ { regexp    => '#',  nextState => ['PPL_BRACKET'], }, ],
+ },
+ {
+ stateName =>     'MODULE_PORTS' ,  # just look for signals until ;
+ allowAnything => 1, 
+ search => [ 
+   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',  # V2001 ansi ports
+     nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, }, 
+   { arcName   => 'END', regexp    => ';' , nextState => ['MODULE'] , },
+   @$vid_vnum_or_string, 
+  ],
+ },
+ {
+ stateName =>     'FUNCTION' , 
+ search => [
+    { arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
+    { arcName => 'TYPE',  regexp => '\b(?:real|integer|time|realtime)\b',
+      nextState => ['FUNCTION'] ,  },
+    { arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] ,  }, # V2001
+    { arcName => 'AUTO',   regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] ,  }, # V2001
+    { arcName => 'NAME',  regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] , 
+    },
+   ],
+ },
+ {
+ stateName =>     'FUNCTION_AFTER_NAME' , 
+ search => [
+    { arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
+    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
+      nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] ,  },
+  ],
+ },
+ {
+ stateName =>     'TASK' , 
+ search => [
+   { arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
+   { arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
+ },
+ {
+ stateName =>     'TASK_AFTER_NAME' , 
+ search => [
+    { arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
+    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
+      nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] ,  },
+  ],
+ },
+ { 
+ stateName =>     'T_SIGNAL' , 
+ failNextState => ['STMNT','ENDTASK'],
+ search => [
+   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
+     nextState => ['MODULE'] , },
+   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
+     nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
+   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
+     nextState => ['PARAM_TYPE','T_SIGNAL'] ,  },
+   ],
+ },
+ {
+ stateName =>     'ENDTASK',
+ search => [
+   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
+     nextState => ['MODULE'] , },
+   ],
+ },
+ { 
+ stateName =>     'F_SIGNAL' , 
+ failNextState => ['STMNT','ENDFUNCTION'],
+ search => [
+   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
+     nextState => ['MODULE'] , },
+   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
+     nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
+   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
+     nextState => ['PARAM_TYPE','F_SIGNAL'] ,  },
+   ],
+ },
+ {
+ stateName =>     'ENDFUNCTION',
+ search => [
+   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
+     nextState => ['MODULE'] , },
+   ],
+ },
+ {
+ stateName =>     'PARAM_TYPE',
+ failNextState => ['PARAM_NAME'],
+ search => [
+    { arcName   => 'RANGE', regexp    => '\[' ,
+      nextState => ['IN_RANGE','PARAM_NAME'] , },
+    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
+      nextState => ['PARAM_TYPE'] , },  # may be followed by a range
+    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
+      nextState => ['PARAM_NAME'] , },
+   ],
+ },
+ {
+ stateName =>     'PARAM_NAME',
+ search => [
+    { arcName   => 'NAME',  regexp    => '$VID' , 
+      nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
+   ],
+ },
+ {
+ stateName =>     'PARAMETER_EQUAL',
+  search => [ { regexp    => '=' , storePos => 1, }, ]
+ },
+ {
+ stateName =>     'PARAM_AFTER_EQUALS',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'CONCAT',      regexp    => '{' ,
+     nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] ,  },
+   { arcName   => 'COMMA',       regexp    => ',' ,
+     nextState => ['PARAM_NAME'] ,    },
+   { arcName   => 'SEMICOLON', 	 regexp    => ';' , },
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'IN_CONCAT',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'CONCAT' ,   regexp    => '{' ,
+     nextState => ['IN_CONCAT','IN_CONCAT'] ,     },
+   { arcName   => 'END' ,      regexp    => '}' , }, # pop up
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'IN_RANGE',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'RANGE' , regexp    => '\[' ,
+     nextState => ['IN_RANGE','IN_RANGE'] , },
+   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'IN_SIG_RANGE', # just like in range, but stores
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'RANGE' , regexp    => '\[' ,
+     nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
+   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'IN_MEM_RANGE', # just like in range, but stores
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'RANGE' , regexp    => '\[' ,
+     nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
+   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'IN_BRACKET',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'BRACKET' ,  regexp    => '\(' ,
+     nextState => ['IN_BRACKET','IN_BRACKET'] ,   },
+   { arcName   => 'END' ,      regexp    => '\)' ,  }, # pop up
+   @$vid_vnum_or_string,
+  ]
+ },
+ { 
+ stateName =>     'IN_STRING',
+ allowAnything => 1, 
+ search => 
+  [ # note: put \" in regexp so that emacs colouring doesn't get confused
+   { arcName   => 'ESCAPED_QUOTE' ,  regexp => '\\\\\\"' , # match \"
+     nextState => ['IN_STRING'] , },
+   # match \\ (to make sure that \\" does not match \"
+   { arcName   => 'ESCAPE' ,  	     regexp => '\\\\\\\\' ,  
+     nextState => ['IN_STRING'] , },
+   { arcName   => 'END' ,  	     regexp => '\\"' , }, # match " and pop up
+  ]
+ },
+ {
+ stateName =>     'SPECIFY',
+ allowAnything => 1, 
+ search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,}, 
+	       @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'TABLE',
+ allowAnything => 1, 
+ search => [ { regexp => '\bendtable\b'   , nextState => ['MODULE'] ,},
+	     @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'EVENT_DECLARATION' ,  # just look for ;
+ allowAnything => 1,
+ search => [ {	regexp    => ';' ,    nextState => ['MODULE'] , },
+             @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'DEFPARAM' ,  # just look for ;
+ allowAnything => 1,
+ search => [ {	regexp    => ';' ,    nextState => ['MODULE'] , },
+             @$vid_vnum_or_string,],
+ },
+ {
+  # REVISIT: could find signal driven by gate here (is output always the first one??)
+ stateName =>     'GATE' , 
+ allowAnything => 1,
+ search => [ {	regexp    => ';' ,    nextState => ['MODULE'] , },
+             @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'ASSIGN',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'RANGE' ,   regexp    => '\[' ,
+     nextState => ['IN_RANGE','ASSIGN'] ,      },
+   { arcName   => 'EQUALS' ,  regexp    => '=' ,
+     nextState => ['ASSIGN_AFTER_EQUALS'] ,    },
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'ASSIGN_AFTER_EQUALS' , 
+ allowAnything => 1,
+  search => 
+   [ 
+    { arcName=>'COMMA',     regexp => ',',    
+      nextState => ['ASSIGN'],},
+    { arcName=>'CONCAT',    regexp => '{',
+      nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
+    # don't get confused by function calls (which can also contain commas)
+    {	arcName=>'BRACKET',   regexp => '\(',    
+    	nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
+    {	arcName=>'END',       regexp => ';',    
+    	nextState => ['MODULE'],},
+    @$vid_vnum_or_string,
+   ],
+ },
+ { 
+ stateName =>     'DRIVE_STRENGTH',  # signal defs - drive strength or charge strength
+ failNextState => ['SCALARED_OR_VECTORED'],
+ search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
+ },
+ { # REVISIT: V2001 - the name of this is misleading now
+ stateName =>     'SCALARED_OR_VECTORED',  # for signal defs
+ failNextState => ['SIGNAL_RANGE'],
+ search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
+	     { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
+	       nextState => ['SCALARED_OR_VECTORED'],}, 
+             { regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
+ },
+ { 
+ stateName =>     'SIGNAL_RANGE',          # for signal defs
+  failNextState => ['SIGNAL_DELAY'],
+ search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
+	       storePos => 1,}, ],
+ },
+ {   
+ stateName =>     'SIGNAL_DELAY',          # for signal defs
+ failNextState => ['SIGNAL_NAME'],
+ search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],},  ],
+ },
+ { 
+ stateName =>     'SIGNAL_NAME',           # for signal defs
+  search => [ { arcName   => 'VID' , regexp    => '$VID',  
+	       nextState => ['SIGNAL_AFTER_NAME'], }, ],
+ },
+ { # for signal defs
+ stateName =>     'SIGNAL_AFTER_NAME',
+ search => 
+  [ 
+   { regexp => ',',  nextState => ['SIGNAL_NAME'],}, 
+   { regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
+     storePos => 1 , }, # memories
+   { arcName => 'SEMICOLON' , regexp => ';',},  # pop up
+   { arcName => 'ASSIGN',     regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
+  ],
+ },
+ {
+ stateName =>     'SIGNAL_AFTER_EQUALS' , 
+ allowAnything => 1,
+ search => 
+   [ 
+    { regexp => ',',    nextState => ['SIGNAL_NAME'],},
+    { regexp => '{',    nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
+    { regexp => '\(',   nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
+    { arcName => 'END', regexp => ';', }, # pop up
+    @$vid_vnum_or_string,
+   ],
+ },
+ { 
+ stateName =>     'INST_PARAM',
+ failNextState => ['INST_NAME'],
+ search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
+ },
+ { 
+ stateName =>     'INST_PARAM_BRACKET',
+ search => [ { arcName => 'BRACKET' , 
+               regexp => '\(',   
+	       storePos => 1, 
+               nextState=> ['INST_PARAM_VALUE'],},
+	     # this is here to catch and illegal case which DC accepts
+             { arcName => 'NO_BRACKET' ,
+               regexp => '($VID|$VNUM)', 
+               nextState=> ['INST_NAME'],}, ],
+ },
+ { 
+ stateName =>     'INST_PARAM_VALUE',
+ allowAnything => 1,
+ search => [ 
+   { regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
+   { regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
+   { regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
+   { arcName => 'COMMA' ,
+     regexp => ',', 
+     storePos => 1, 
+     nextState=> ['INST_PARAM_VALUE'],}, 
+   { arcName => 'END' ,
+     regexp => '\)', 
+     nextState=> ['INST_NAME'],}, 
+  ],
+ },
+ {
+ stateName =>     'INST_NAME',
+ failNextState => ['INST_BRACKET'],
+ search => 
+  [ 
+   { arcName   => 'VID' ,       regexp => '$VID', 
+     nextState => ['INST_RANGE'],      },
+  ],
+ },
+ { 
+ stateName =>     'INST_NO_NAME' ,  
+ allowAnything => 1,
+ search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'INST_RANGE',
+ failNextState => ['INST_BRACKET'],
+ search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
+ },
+ {
+ stateName =>     'INST_BRACKET',
+ search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
+ },
+ {
+ stateName =>     'INST_PORTS',
+ failNextState => ['INST_NUMBERED_PORT'],
+ failStorePos => 1, 
+ search => 
+  [ 
+   { arcName => 'COMMA', regexp => ',',   nextState => ['INST_PORTS'], },
+   { regexp => '\.',  nextState => ['INST_PORT_NAME'],  },
+   { regexp => '\)',  nextState => ['AFTER_INST'], },
+  ],
+ },
+ {
+ stateName =>     'INST_PORT_NAME',
+ search => [ { arcName   => 'NAME' , regexp => '$VID', 
+	       nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
+		             'INST_NAMED_PORT_CON_AFTER'], }, ],
+ },
+ {
+   stateName => 'INST_NAMED_PORT_BRACKET',
+   search => [ { regexp => '\(' , storePos => 1, },] 
+ },
+ {
+ stateName =>     'INST_NAMED_PORT_CON',
+ allowAnything => 1, 
+ search => 
+  [
+   { regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
+   { regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
+   { regexp => '\(' , 
+     nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
+   { arcName => 'END', regexp    => '\)' , },   # pop up 
+   @$vid_vnum_or_string,
+  ]
+ },
+ {
+ stateName =>     'INST_NAMED_PORT_CON_AFTER',
+ search => 
+  [ 
+   { arcName => 'BRACKET', regexp => '\)' , 
+     nextState => ['AFTER_INST']}, 
+   { arcName => 'COMMA' ,  regexp => ',' ,  
+     nextState => ['INST_DOT']}, 
+  ]
+ },
+ { stateName => 'INST_DOT',     
+   search => 
+    [ 
+     { regexp => '\.' , nextState => ['INST_PORT_NAME']}, 
+     { regexp => ','  , nextState => ['INST_DOT']},   # blank port
+    ] 
+ },
+ {
+ stateName =>     'INST_NUMBERED_PORT',
+ allowAnything => 1, 
+ search => 
+  [
+   { regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
+   { regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
+   { regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
+   { arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
+   { arcName => 'COMMA' ,   regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
+     storePos => 1, },
+     @$vid_vnum_or_string,
+  ]
+ },
+ { stateName => 'AFTER_INST', 
+   search => [ 
+    { arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
+    { arcName => 'COMMA',     regexp => ',', nextState => ['INST_NAME'], },
+   ] 
+ },
+ {
+ stateName =>     'STMNT',
+ search => 
+  [
+   { arcName   => 'IF',	                    regexp => '\bif\b' ,
+     nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
+   { arcName   => 'REPEAT_WHILE_FOR_WAIT',  regexp => '\b(?:repeat|while|for|wait)\b' ,
+     nextState => ['BRACKET','IN_BRACKET','STMNT'] ,  },
+   { arcName   => 'FOREVER', 	            regexp => '\bforever\b' ,
+     nextState => ['STMNT'] , },
+   { arcName   => 'CASE',                   regexp => '\bcase[xz]?\b' ,
+     nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
+   { arcName   => 'BEGIN',	            regexp => '\bbegin\b' ,
+     nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
+   { arcName   => 'FORK',	            regexp => '\bfork\b' ,
+     nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
+   { arcName   => 'DELAY',                  regexp => '\#' ,
+     nextState => ['DELAY_VALUE','STMNT'] , },
+   { arcName   => 'EVENT_CONTROL',	    regexp => '\@' ,
+     nextState => ['EVENT_CONTROL'] , },
+   { arcName   => 'SYSTEM_TASK',  	    regexp    => '\$$VID' ,
+     nextState => ['SYSTEM_TASK'] , },
+   { arcName   => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
+     regexp    => '\b(?:disable|assign|deassign|force|release)\b',
+     nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
+   # a assignment to a hierarchical thing mustn't collect the vid
+   #  like a normal assign as hierarchical nets/signals will confuse downstream code
+   { arcName   => 'HIER_ASSIGN_OR_TASK',	   regexp => '$HVID' ,
+     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
+   { arcName   => 'ASSIGN_OR_TASK',	   regexp => '$VID' ,
+     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
+   { arcName   => 'CONCAT',	           regexp => '{' ,
+     nextState => ['IN_CONCAT','STMNT_ASSIGN'] ,  },
+   { arcName   => 'NULL',                  regexp => ';' ,
+     }, # pop up
+   { arcName   => 'POINTY_THING',	   regexp    => '->' , # not sure what this is!
+     nextState => ['POINTY_THING_NAME'] ,  },
+  ],
+ },
+ {
+ stateName =>     'MAYBE_ELSE',
+ failNextState => [] , # don't get confused, just pop the stack for the next state
+ search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
+ },
+ {
+ stateName =>     'BLOCK_NAME',
+ failNextState => [] , # don't get confused, just pop the stack for the next state
+ search => [{ arcName => 'COLON', regexp    => ':' , 
+	      nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
+ },
+ {
+ stateName =>     'BLOCK_NAME_AFTER_COLON',
+ search => [ { arcName   => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
+ },
+ { 
+ stateName =>     'BLOCK_SIGNAL' , 
+ failNextState => [], # don't get confused, just pop the stack for the next state
+ search => [
+   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
+     nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
+   ],
+ },
+
+
+ {
+ stateName =>     'IN_SEQ_BLOCK',
+ failNextState => ['STMNT','IN_SEQ_BLOCK'] , 
+ search => [{ arcName   => 'END', regexp    => '\bend\b' , }, ]
+ },
+ {
+ stateName =>     'IN_PAR_BLOCK',
+ failNextState => ['STMNT','IN_PAR_BLOCK'] , 
+ search => [{ arcName   => 'JOIN', regexp => '\bjoin\b' , }, ]
+ },
+ {
+ stateName =>     'DELAY_VALUE',
+ search => 
+  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
+   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON1'], },
+   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON1'],},]
+ },
+ {
+ stateName =>     'DELAY_COLON1',
+ failNextState => [] , # popup
+ search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
+ },
+ {
+ stateName =>     'DELAY_VALUE2',
+ search => 
+  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
+   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON2'], },
+   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON2'],},]
+ },
+ {
+ stateName =>     'DELAY_COLON2',
+ search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
+ },
+ {
+ stateName =>     'DELAY_VALUE3',
+ search => 
+  [{ arcName => 'NUMBER',  regexp => '$VNUM', },
+   { arcName => 'ID',      regexp => '$VID',  },
+   { arcName => 'BRACKET', regexp => '\(',  nextState => ['IN_BRACKET'],}, ]
+ },
+ {
+ stateName =>     'EVENT_CONTROL',
+ search => 
+  [
+   { arcName => 'ID',      regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
+   { arcName => 'STAR',    regexp => '\*', nextState => ['STMNT'], }, # V2001
+   { arcName => 'BRACKET', regexp => '\(', 
+     nextState => ['IN_EVENT_BRACKET','STMNT'], },
+  ]
+ },
+ {
+ stateName =>     'IN_EVENT_BRACKET',
+ allowAnything => 1, 
+ search => 
+  [ 
+   # must go before vid_vnum_or_string as posedge and negedge look like VIDs
+   { arcName => 'EDGE' ,	   regexp    => '\b(?:posedge|negedge)\b' ,
+     nextState => ['IN_EVENT_BRACKET_EDGE'] , },
+   { arcName   => 'BRACKET' ,	   regexp    => '\(' ,
+     nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
+   { arcName => 'STAR',    regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
+   { arcName   => 'END' ,          regexp    => '\)' , }, # popup
+   @$vid_vnum_or_string,
+  ]
+ },
+ { # in theory there could be an expression here, I just take the first VID
+ stateName =>     'IN_EVENT_BRACKET_EDGE',
+ failNextState => ['IN_EVENT_BRACKET'] ,
+ search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
+ },
+ {
+ stateName =>     'STMNT_ASSIGN_OR_TASK',
+ failNextState => ['STMNT_SEMICOLON'],
+ search => 
+  [
+   { arcName => 'EQUALS',      	   regexp => '[<]?=',  
+     nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
+   { arcName => 'RANGE',	   regexp => '\[',  
+     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
+   { arcName => 'BRACKET',         regexp => '\(',     # task with params
+     nextState => ['IN_BRACKET','STMNT_SEMICOLON'],  },
+  ]
+ },
+ {
+ stateName =>     'STMNT_ASSIGN',
+ search => 
+  [
+   { arcName => 'EQUALS', regexp => '[<]?=', 
+     nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
+   { arcName => 'RANGE',	   regexp => '\[',  
+     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
+  ],
+ },
+ {
+ stateName =>     'SYSTEM_TASK',
+ failNextState => ['STMNT_SEMICOLON'],
+ search => 
+  [
+   { arcName => 'BRACKET',   	     regexp => '\(',  
+     nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },    ],
+ },
+ {
+ stateName =>     'POINTY_THING_NAME',
+ search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
+ },
+ {
+ stateName =>     'CASE_ITEM',
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName => 'END',      	   regexp => '\bendcase\b',  },
+   { arcName => 'COLON',	   regexp => ':',  
+     nextState => ['STMNT','CASE_ITEM'], },
+   { arcName => 'DEFAULT',	   regexp => '\bdefault\b',  
+     nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
+   # don't get confused by colons in ranges
+   { arcName => 'RANGE',	   regexp => '\[',  
+     nextState => ['IN_RANGE','CASE_ITEM'], },
+    @$vid_vnum_or_string,
+  ],
+ },
+ {
+ stateName =>     'MAYBE_COLON',
+ failNextState => [],
+ search => [ { regexp    => ':' , }, ]
+ },
+ { # look for ;  but also allow the ending of a statement with an end 
+   #   even though it is not really legal (verilog seems to accept it, so I do too)
+ stateName =>     'STMNT_JUNK_TO_SEMICOLON' ,  
+ allowAnything => 1,
+ search => [ 
+	     { regexp => ';' , }, 
+	     # popup and reset pos to  before the end/join cope with nosemicolon case
+	     { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, }, 
+	     @$vid_vnum_or_string,                              
+	   ],
+ },
+ { 
+ stateName => 'STMNT_SEMICOLON', 
+ search => [ { regexp => ';'  , },
+	     # popup and reset pos to  before the end/join cope with nosemicolon case
+	     { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, }, 
+	   ],
+ },
+ { stateName => 'BRACKET',   search => [ { regexp => '\(' , },] },
+ { stateName => 'SEMICOLON', search => [ { regexp => ';'  , },] },
+ # V2001
+ {
+ stateName =>     'CONFIG',
+ allowAnything => 1, 
+ search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,}, 
+	       @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'LIBRARY' ,  # just look for ;
+ allowAnything => 1,
+ search => [ {	regexp    => ';' ,    nextState => ['START'] , },
+             @$vid_vnum_or_string,],
+ },
+ {
+ stateName =>     'GENERATE',
+ allowAnything => 1, 
+ search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,}, 
+	       @$vid_vnum_or_string,],
+ },
+
+
+
+ { # V2001 ansi module ports
+ stateName =>     'ANSI_PORTS_TYPE',  
+ failNextState => ['ANSI_PORTS_TYPE2'],
+ search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b', 
+	       nextState => ['ANSI_PORTS_TYPE2'],},
+	     # a null list. note this is only possible for a task or function
+	     #  (a null module port list can't look like an ansi port list)
+	     #  but it is not legal acording to the BNF. I allow it any way.
+	     { regexp => '\)', nextState => ['SEMICOLON'], }, 
+	     ],
+ },
+ { # V2001 ansi module ports
+ stateName =>     'ANSI_PORTS_TYPE2',  
+ failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
+ search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", 
+	       nextState => ['ANSI_PORTS_TYPE2'],}, 
+             { regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
+ },
+ { # V2001 ansi module ports
+ stateName =>     'ANSI_PORTS_SIGNAL_RANGE',          # for signal defs
+  failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
+ search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
+  	       storePos => 1,}, ],
+ },
+ { # V2001 ansi module ports
+ stateName =>     'ANSI_PORTS_SIGNAL_NAME',
+  search => [ 
+   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',  
+     nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, }, 
+   { arcName   => 'VID' , regexp    => '$VID',  
+     nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], }, 
+  ],
+ },
+ { # V2001 ansi module ports
+ stateName =>     'ANSI_PORTS_SIGNAL_AFTER_NAME',
+ search => 
+  [ 
+   { regexp => ',',  nextState => ['ANSI_PORTS_SIGNAL_NAME'],}, 
+   { regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
+   { regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
+  ],
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_BRACKET' ,  
+ search => [ { regexp    => '\(',  nextState => ['PPL_PARAM'], }, ],
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_PARAM' ,  
+ search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_TYPE',    
+ failNextState => ['PPL_NAME'],
+ search => [
+    { arcName   => 'RANGE', regexp    => '\[' ,
+      nextState => ['IN_RANGE','PPL_NAME'] , },
+    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
+      nextState => ['PPL_TYPE'] , },  # may be followed by a range
+    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
+      nextState => ['PPL_NAME'] , },
+   ],
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_NAME', 
+ search => [
+    { arcName   => 'NAME',  regexp    => '$VID' , 
+      nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
+   ],
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_AFTER_EQUALS', 
+ allowAnything => 1, 
+ search => 
+  [
+   { arcName   => 'CONCAT',      regexp    => '{' ,
+     nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] ,  },
+   { arcName   => 'BRACKET',      regexp    => '\(' ,
+     nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] ,  },
+   { arcName   => 'COMMA',       regexp    => ',' ,
+     nextState => ['PPL_PARAM_OR_NAME'] ,    },
+   { arcName   => 'END',       regexp    => '\)' ,
+     nextState => ['MODULE_PORTS'] ,    },
+   @$vid_vnum_or_string,
+  ]
+ },
+ { # v2001 module_parameter_port_list (A.1.3)
+ stateName =>     'PPL_PARAM_OR_NAME' ,  
+ failNextState => ['PPL_NAME'],
+ search => [ { regexp    => '\bparameter\b',  nextState => ['PPL_TYPE'], }, ],
+ },
+];
+}
+
+
+############################################################
+# make the parser, and return it as a string
+############################################################
+
+
+sub _make_parser {
+    my ($evalDefs,$genDebugCode) = @_;
+
+    _check_data_structures($evalDefs);
+    
+    my $perlCode; # the perl code we are making
+
+    my $debugPrint =  $genDebugCode ? 'print "---- $ps->{curState} $file:$line (".pos($code).")\\n" if defined $ps->{curState} && defined pos($code);':'';
+#    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
+    $perlCode .= <<EOF;
+sub _parse_line {
+
+  my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
+
+  if (!exists(\$ps->{curState})){
+      \$ps->{curState} = undef;
+      \$ps->{prevState}= undef;
+      \$ps->{nextStateStack}= ["START"];
+      \$ps->{storing}= 0;
+      \$ps->{stored}= "";
+      \$ps->{confusedNextState}= "START";
+  }
+
+  my \$storePos = -1;
+  my \$lastPos = 0;
+  my \$posMark;
+  my \$fromLastPos;
+  PARSE_LINE_LOOP: while (1) {
+
+    \$lastPos = pos(\$code) if (defined(pos(\$code)));
+
+    if ( \$code =~ m/\\G\\s*\\Z/gs ) {
+	last PARSE_LINE_LOOP;
+    }
+    else {
+	pos(\$code) = \$lastPos;
+    }
+    
+    \$code =~ m/\\G\\s*/gs ; # skip any whitespace
+
+    \$ps->{prevState} = \$ps->{curState};
+    \$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
+	die "Error: No next state after \$ps->{prevState} ".
+	    "\$file line \$line :\n \$code";
+    $debugPrint
+
+    goto \$ps->{curState};
+    die \"Confused: Bad state \$ps->{curState}\";
+
+    CONFUSED:
+	\$posMark = '';
+	# make the position marker: tricky because code can contain tabs
+	#  which we want to match in the blank space before the ^
+	\$posMark = substr(\$code,0,\$lastPos);
+	\$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
+	\$posMark .= "^" ;
+	if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
+	\$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
+		    "\$code".\$posMark);
+	\@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
+       return; # ignore the rest of the line
+EOF
+#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+
+  foreach my $state (@$languageDef) {
+      my $stateName = $state->{stateName};
+      my $allowAnything    = exists($state->{allowAnything}) && $state->{allowAnything};
+      my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match 
+      #  where we left off last time
+      $perlCode.= "    $stateName:\n";
+      
+      if (exists($state->{confusedNextState})) {
+	  $perlCode.= "      \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
+      }
+	  
+      if (exists($state->{search})) {
+	  my @searchTerms=();
+	  foreach my $search (@{$state->{search}}) { 
+	      push @searchTerms, $search->{regexp}; 
+	  }
+	  $re .= "(?:(". join(")|(",@searchTerms)."))";
+	  
+	  my $failNextState='';
+	  
+	  if (exists($state->{failNextState})) {
+	      if (scalar(@{$state->{failNextState}}) != 0) {
+		  $failNextState="\"".
+		      join('","',reverse(@{$state->{failNextState}})).
+			  "\"";
+	      }
+	      # else leave it set at nothing - means just popup
+	  }
+	  else {
+	      $failNextState='"CONFUSED"';
+	  }
+	  $perlCode.= "        if (\$code =~ m/$re/gos) {\n";
+	  
+	  my $elsif2="if";
+	  my $i=0;
+	  foreach my $search (@{$state->{search}}) {
+	      $i++;
+	      
+	      my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
+	      
+	      $perlCode.= "          $elsif2 (defined(\$$i)) {\n";
+	      if ($genDebugCode) {
+		  $perlCode.="           print \"----  -$arcName (\$$i)->\\n\";\n";
+		  $perlCode.="           \$takenArcs->{'$stateName'}{$i}++;\n";
+	      }
+	      $elsif2="elsif";
+	      if (exists($search->{resetPos}) && $search->{resetPos}) {
+		  $perlCode.="           pos(\$code)=pos(\$code)-length(\$$i);\n";
+	      }
+	      if (exists($search->{arcName})) {
+		  $perlCode.=  # "	      " . 
+		      _make_eval_code($evalDefs,$stateName,
+				   $search->{arcName},$i,$genDebugCode);
+	      }
+	      if (exists $search->{nextState}) {
+		  $perlCode.= "	      push (\@{\$ps->{nextStateStack}}, \"".
+		      join('","',reverse(@{$search->{nextState}}))."\");\n";
+	      }
+	      if (exists($search->{storePos}) && $search->{storePos}) {
+		  $perlCode.= "       \$ps->{storing} == 0 or\n";
+		  $perlCode.= "            die \"Setting storing ".
+		      "flag when it is already set: $stateName:$arcName\";\n";
+		  $perlCode.= "       \$storePos       = pos(\$code);\n";
+		  $perlCode.= "       \$ps->{storing}  = 1;\n";
+		  $perlCode.= "       \$ps->{stored}   = '';\n";
+	      }
+	      $perlCode.= "	  }\n";
+	  }
+	  $perlCode.= "      }\n";
+	  
+	  if ($allowAnything) {
+	      $perlCode.= "      else { ".
+		  "push(\@{\$ps->{nextStateStack}},\"$stateName\"); last  PARSE_LINE_LOOP; }\n";
+	  }
+	  else {
+	      $perlCode.= "      else {\n";
+	      if (exists($state->{failStorePos}) && $state->{failStorePos}) {
+		  $perlCode.= "       \$ps->{storing} == 0 or\n";
+		  $perlCode.= "            die \"Setting storing ".
+		      "flag when it is already set: $stateName:fail\";\n";
+                  #NB:uses lastPos here because there was no match, so can't 
+		  #  use pos(code)
+		  $perlCode.= "       \$storePos       = \$lastPos;\n"; 
+		  $perlCode.= "       \$ps->{storing}  = 1;\n";
+		  $perlCode.= "       \$ps->{stored}   = '';\n";
+	      }
+	      if ($failNextState) {
+		  $perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
+	      }
+	      $perlCode.= " pos(\$code)=\$lastPos; }\n";
+	  }
+      }
+      $perlCode.= "    next PARSE_LINE_LOOP;\n";
+  }
+  $perlCode.= "  }\n";
+  $perlCode.= "  if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
+  $perlCode.= "  elsif ( \$ps->{storing} ) {   \$ps->{stored} .= \$code; }\n";
+  $perlCode.= "}\n";
+
+  return $perlCode;
+}
+
+sub _make_eval_code {
+    my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
+
+    my $eval='';
+
+    foreach my $evalDef (@$evalDefs) {
+
+	if (exists($evalDef->{$stateName}{$arcName})) {
+	    if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
+		$eval.=$evalDef->{$1}{$2};
+	    }
+	    else {
+		$eval.=$evalDef->{$stateName}{$arcName};
+	    }
+	    $eval.="\n";
+	}
+    }
+    # replace $match variable with the actual number of the match
+    $eval=~ s/\$match/\$$matchNo/g;
+
+    # if fromLastPos is used then generate the code to work it out
+    if ($eval =~ /\$fromLastPos/) {
+	my $e;
+	$e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
+	$e .= "if (\$storePos==-1) {\n"; # on another line
+	$e .= "   \$fromLastPos=\$ps->{stored}."; # what was before
+	$e .= "       substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
+	$e .= "}\n";
+	$e .= "else {\n";
+	$e .= "   \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
+	    "-\$storePos-length(\$$matchNo));\n";
+	$e .= "}\n";
+	$e .= "\$ps->{storing}=0;\n";
+	$e .= "\$ps->{stored}='';\n";
+	$eval = $e . $eval;
+
+    }
+    return $eval;
+}
+
+sub _check_end_state {
+  my ($self,$file,$line,$ps) = @_;
+
+  if (!exists($ps->{curState})){ 
+      # parse_line was never called, file only contained comments, defines etc
+      return;
+  } 
+  $ps->{prevState} = $ps->{curState};
+  $ps->{curState} = pop(@{$ps->{nextStateStack}}) or
+      $self->_add_confused("$file:$line:".
+			  "No next state after $ps->{prevState} at EOF");
+  
+  if ($ps->{curState} ne 'START') {
+      $self->_add_confused("$file:$line:".
+			  " at EOF in state $ps->{curState}".
+			  (($ps->{curState} eq 'CONFUSED')?
+					   ",prevState was $ps->{prevState}":""));
+  }
+  if (@{$ps->{nextStateStack}}) {
+      $self->_add_confused("$file:$line:".
+			  " at EOF, state stack not empty: ".
+			  join(" ",@{$ps->{nextStateStack}}));
+  }
+
+  # at the moment I don't check these:
+  # $ps->{storing}= 0;  
+  # $ps->{stored}= "";
+
+}
+
+sub _check_data_structures {
+    my ($evalDefs) = @_;
+
+    my %stateNames;
+    my %statesUnused;
+
+    foreach my $sp (@$languageDef) {
+	die "Not hash!" unless ref($sp) eq "HASH";
+	if (!exists($sp->{stateName})) {  die "State without name!"; }
+	die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
+	$stateNames{$sp->{stateName}} = $sp;
+    }
+
+    %statesUnused = %stateNames;
+    # check language def first
+    foreach my $sp (@$languageDef) {
+	my %t = %$sp;
+	if (!exists($sp->{search})) {  die "State without search!"; }
+	die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
+	my %arcNames;
+	foreach my $arc (@{$sp->{search}}) {
+	    my %a = %$arc;
+	    die "arc without regexp in $sp->{stateName}" unless exists $a{regexp}; 
+	    delete $a{regexp};
+	    if (exists($a{nextState})) {
+		die "nextState not array"  unless ref($a{nextState}) eq "ARRAY";
+		foreach my $n (@{$a{nextState}}) {
+		    next if ($n =~ m/^\$/); #can't check variable ones
+		    die "Bad Next state $n" 
+			unless exists $stateNames{$n};
+		    delete($statesUnused{$n}) if exists $statesUnused{$n};
+		}
+		delete $a{nextState};
+	    }
+	    if (exists($a{arcName})) {
+		die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
+		$arcNames{$a{arcName}} = 1;
+		delete $a{arcName};
+	    }
+  	    delete $a{resetPos};
+  	    delete $a{storePos};
+	    foreach my $k (&$msort (keys %a)) {
+		die "Bad key $k in arc of state $t{stateName}";
+	    }
+	}
+	delete $t{stateName};
+	delete $t{search};
+	delete $t{allowAnything} if exists $t{allowAnything};
+
+	if (exists($t{confusedNextState})) {
+	    die "Bad Next confused state $t{confusedNextState}" 
+		unless exists $stateNames{$t{confusedNextState}};
+	    delete $t{confusedNextState};
+	}
+	
+	foreach my $n (@{$t{failNextState}}) {
+	    next if ($n =~ m/^\$/); #can't check variable ones
+	    die "Bad Next fail state $n" 
+		unless exists $stateNames{$n};
+	    delete($statesUnused{$n}) if exists $statesUnused{$n};
+	}
+	delete $t{failNextState} if exists $t{failNextState};
+	delete $t{failStorePos}  if exists $t{failStorePos};
+	foreach my $k (&$msort (keys %t)) {
+	    die "Bad key $k in languageDef state $sp->{stateName}";
+	}
+    }
+
+    # REVISIT: MODULE PORTS looks like it is unused because it is got to
+    #  by setting $nState - should have a flag in language def that turns
+    #  off this check on a per state basis.
+    foreach my $state (&$msort (keys %statesUnused)) { 
+	#die "State $state was not used";
+	print "Warning: State $state looks like it was not used\n" if $debug;
+    }
+
+    foreach my $evalDef (@$evalDefs) {
+	foreach my $state (&$msort (keys %$evalDef)) { 
+	    if (!exists($stateNames{$state})) {
+		die "Couldn't find state $state";
+	    }
+	    my $statep = $stateNames{$state};
+	    
+	    foreach my $arc (&$msort (keys %{$evalDef->{$state}})) {
+		my $found = 0;
+		foreach my $s (@{$statep->{search}}) {
+		    if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
+			$found=1;
+			last;
+		    }
+		}
+		if ($found == 0) {
+		    die "No arc $arc in state $state";
+		}
+		if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
+		    die "No code found for $evalDef->{$state}{$arc}" 
+			unless exists $evalDef->{$1}{$2};
+		}
+	    }
+	}
+    }
+}
+
+
+sub _check_coverage {
+
+    print "\n\nCoverage Information:\n";
+    foreach my $sp (@$languageDef) {
+	if (!exists($takenArcs->{$sp->{stateName}})) {
+	    print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
+	}
+	else {
+	    my $i=0;
+	    foreach my $arc (@{$sp->{search}}) {
+		$i++;
+		if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
+		    my $arcName = $i;
+		    $arcName = $arc->{arcName} if exists $arc->{arcName};
+		    print " Arc $arcName of $sp->{stateName} was never taken\n";
+		}
+	    }
+	}
+    }
+}
+
+
+###########################################################################
+
+# when doing require or use we must return 1
+1;
+
diff --git a/bin/htmlgen/v2html/v2html-cgi b/bin/htmlgen/v2html/v2html-cgi
new file mode 100755
index 0000000000000000000000000000000000000000..9fb68e95bdcefa46b29301d55e246c02ce69a6d6
--- /dev/null
+++ b/bin/htmlgen/v2html/v2html-cgi
@@ -0,0 +1,311 @@
+#!/usr/local/bin/perl -w
+###############################################################################
+# 
+# File:         v2html-cgi
+# RCS:          $Header: v2html-cgi,v 3.1 1999/09/21 18:38:43 cc Exp $
+# Description:  CGI script for helping v2html generated html
+# Author:       Costas Calamvokis
+# Created:      Wed Sep  3 08:52:08 1997
+# Modified:     Tue Sep 21 11:34:21 1999 (Costas Calamvokis) v2html@burbleland.com
+# Language:     Perl
+#
+# Copyright 1998 Costas Calamvokis
+# Copyright 1997 Hewlett-Packard Company
+#
+#  This file nay be copied, modified and distributed only in accordance
+#  with the terms of the limited licence contained in the accompanying
+#  file LICENCE.TXT.
+#
+###############################################################################
+
+#
+# Currently does:
+#  Expanding/compressing hierarchies:
+#   - Takes a query like ?k=9437645&x=XXXXCCXC&in=hierarchy.html
+#    and generates html of the hierarchy in in accoring to the string
+#    x, each character in the string x represents one list in the .html
+#    file which can either be eXpanded or Compressed.
+#   - After each module it also generates a [X] or [C] link which when
+#      clicked causes this script to be called again with a new string
+#      which results in that module being expanded or compressed.
+#   - This is made much easier by v2html which marks each list that is
+#       with a candidate for expansion/compression with a 
+#       number when it generates the html code.
+#
+
+# only have one file error message to avoid leaking information
+#  through errors (uncomment the helpful error during debugging)
+$file_error_message= "v2html-cgi error.<P>\n";
+
+print "Content-Type: text/html\n\n";
+
+# environment variables that should be set by the web server
+&check_input('QUERY_STRING',%ENV);
+&check_input('SCRIPT_NAME',%ENV);
+&check_input('PATH_INFO',%ENV);
+&check_input('PATH_TRANSLATED',%ENV);
+
+# Get the arguements specified in the URL
+%args= getcgivars();
+
+# query variables that should be set in the URL 
+#  (eg .. ?k=9999x=CXCX&in=hierarchy.html
+&check_input('x',%args);
+&check_input('f',%args);
+&check_input('in',%args);
+&check_input('k',%args);
+
+$k             = $args{'k'};
+$expand_string =$args{'x'};
+$infile        = $args{'in'};
+$framed        = $args{'f'};
+
+# remove the / from script name if it is there
+$ENV{'SCRIPT_NAME'} =~ s#^/## ; 
+
+# set up the cgi script and path info that we'll put in the expand/compress
+#  links
+$cgi_script_and_path_info= "/" . $ENV{'SCRIPT_NAME'} . $ENV{'PATH_INFO'};
+
+
+$marker = "  <!-- v2html_handle --> ";
+$printing=1; # start out printing the file
+$ul_id=0;
+
+# Work out the hierarchy file to read
+$file=$ENV{'PATH_TRANSLATED'} . $infile;
+
+# Remove any .. in the file name so people can't look at files
+#  that are not under the web root
+$file=~ s/\.\.//g;
+
+# open the hierarchy file
+unless (open(F,"<$file")) { 
+    print $file_error_message;
+    # this less cryptic message could give intruders clues about your files
+    #print "Couldn't open $ENV{'PATH_TRANSLATED'}$infile\n";
+    exit;
+}
+
+
+# check that the hierarchy file starts with "<!- v2html hierarchy" comment
+#  and that the key is correct
+$_ = <F>;
+&security_check_hierarchy($_);
+
+
+# Have a look for the briefcase icons - if they don't exist
+#  use [C] and [X]
+&find_icons;
+
+# set up the extra infomation needed to do framed output
+if ($framed eq "1") {     $target='target="upper"'; }
+else                {     $target='';               }
+
+#
+# main loop
+#
+while (<F>) {
+    # print the place to find the .v.html files at the bottom of the
+    #  header - if we don't do this then it'll look for them under
+    #  the cgi-bin directory
+    if (m&</head>&) {
+	print "<base href=\"http://$ENV{'SERVER_NAME'}" .
+	    ":$ENV{'SERVER_PORT'}$ENV{'PATH_INFO'}\">\n";    
+    }
+
+    if ($printing) {
+	if (m&<ul> <!-- ul_id=([0-9]+) -->&) {
+	    if (&check_expand_string($1)) {
+		# This is expanded now, so print compressor
+		print $marker .
+		    "<A name=\"ul_id_$1\"></A>\n";
+		print $marker .
+		    "<A $target href=\"$cgi_script_and_path_info?k=$k&x=" . 
+			&new_expand_string($1,"C") . 
+			    "&in=$infile&f=$framed#ul_id_$1\"> $icon_c</A>\n";
+		# keep printing
+		print $_;
+	    }
+	    else {
+		$ul_id=$1;
+		# This is compressed now, so print expander
+		print $marker .
+		    "<A name=\"ul_id_$ul_id\"></A>\n";
+		print $marker .
+		    "<A $target href=\"$cgi_script_and_path_info?k=$k&x=" . 
+			&new_expand_string($ul_id,"X") . 
+			    "&in=$infile&f=$framed#ul_id_$1\"> $icon_x</A>\n";
+		# stop printing
+		$printing=0;
+	    }
+	}
+	else {
+	    # print everything else except compressors and expanders
+	    #  which are generated fresh each time
+	    if (! m/$marker/) {
+		print $_;
+	    }
+	}
+    }
+    else {
+	# not printing, look for the end of the ul_id which stopped the
+	#  print.
+	if (m&</ul> <!-- ul_id=$ul_id -->&) {
+	    $printing=1;
+	}
+    }
+
+    
+
+}
+
+exit;
+
+###########################################################################
+# Subroutines
+###########################################################################
+
+#
+# Takes one arguement - the number in the character string to
+#  look at.
+# Returns 1 if the list is expanded and 0 if it is compressed
+#  if the number is off the end of the expand string then it
+#  returns 1
+#
+sub check_expand_string {
+    local($u) = @_;
+    local($c);
+
+    if ($expand_string eq 'A') {
+	return 1;
+    }
+    elsif (length($expand_string)>$u) {
+	$c = substr($expand_string,$u,1);
+	if ($c eq 'X'){ 
+	    return 1;
+	}
+	else {
+	    return 0;
+	}
+    }
+    else {
+	return 0;
+    }
+
+}
+
+#
+# Generate a new expand_string for a compressor or an expander link
+#  Takes two arguments, the number of the list and the new character
+#  to put in ('C' for compressor, 'X' for expander)
+#
+sub new_expand_string {
+    local($u,$c) = @_;
+    local($new_string,$l);
+
+    $l = length($expand_string);
+    if ($l > $u) {
+	$new_string = $expand_string;
+	substr($new_string,$u,1) = $c;
+    }
+    else {
+	if ($expand_string eq "A") {
+	    $new_string = "X" . "X" x ($u-$l) . $c;
+	}
+	else {
+	    $new_string = $expand_string . "C" x ($u-$l) . $c;
+	}
+    }
+
+    return $new_string;
+}
+
+#
+# check that the input array %a has an element $s
+#
+sub check_input {
+    local($s,%a) = @_;
+    if (!exists($a{$s})) {
+	print "v2html-cgi: fatal error, didn't get required parameter $s.<P>\n";
+	if ($s eq 'k') {
+	    print " This may be because the hierarchy was generated\n" .
+	     " by v2html 2.0. If so regenerate using a newer version<P>\n";
+	}
+	exit;
+    }
+}
+
+#
+# Read all CGI vars into an associative array.
+# If multiple input fields have the same name, they are concatenated into
+#   one array element and delimited with the \0 character.
+# This is a simple version, that assumes a request method of GET.
+#
+sub getcgivars {
+    local(%in) ;
+    local($name, $value) ;
+
+    # Resolve and unencode name/value pairs into %in
+    foreach (split('&', $ENV{'QUERY_STRING'})) {
+        s/\+/ /g ;
+        ($name, $value)= split('=', $_, 2) ;
+        $name=~ s/%(..)/sprintf("%c",hex($1))/ge ;
+        $value=~ s/%(..)/sprintf("%c",hex($1))/ge ;
+        $in{$name}.= "\0" if defined($in{$name}) ;  # concatenate multiple vars
+        $in{$name}.= $value ;
+    }
+
+    return %in ;
+
+}
+
+#
+# Do security checks on the hierarchy file
+#  make sure we don't:
+#   serve files that are not v2html hierarchies
+#   serve files that users can't get access to through the http demon
+#    (by checking that the key is right)
+#
+sub security_check_hierarchy {
+    my ($first_line) = @_;
+
+    if ($first_line =~ /^<!-- v2html hierarchy/) {
+	if ($first_line =~ /^<!-- v2html hierarchy K=$k /) {
+	    print $first_line;
+	}
+	else {
+	    print $file_error_message;
+	    # this less cryptic message could give intruders clues about your files
+	    #print "$ENV{'PATH_TRANSLATED'}$infile: bad key<P>\n";
+	    exit;
+	}
+    }
+    else {
+	print $file_error_message;
+	# this less cryptic message could give intruders clues about your files
+	#print "$ENV{'PATH_TRANSLATED'}$infile is not a v2html hierarchy file\n";
+	exit;
+    }
+}
+
+#
+# Look for the briefcase icons - if they don't exist use [C] and [X]
+#
+sub find_icons {
+    
+ if (( -r "$ENV{'PATH_TRANSLATED'}/v2html-c.gif" ) &&
+     ( -r "$ENV{'PATH_TRANSLATED'}/v2html-x.gif" )) {
+     $icon_c = "<IMG align=bottom border=0 SRC=\"v2html-c.gif\">";
+     $icon_x = "<IMG align=bottom border=0 SRC=\"v2html-x.gif\">";
+ }
+ else {
+     $icon_c = " [C]";
+     $icon_x = " [X]";
+ }
+
+
+}
+
+
+
diff --git a/bin/htmlgen/v2html/v2html.1 b/bin/htmlgen/v2html/v2html.1
new file mode 100644
index 0000000000000000000000000000000000000000..ea1b36051668c6179270cd3293c5f65a7f556772
--- /dev/null
+++ b/bin/htmlgen/v2html/v2html.1
@@ -0,0 +1,553 @@
+.\" Automatically generated by Pod::Man v1.37, Pod::Parser v1.32
+.\"
+.\" Standard preamble:
+.\" ========================================================================
+.de Sh \" Subsection heading
+.br
+.if t .Sp
+.ne 5
+.PP
+\fB\\$1\fR
+.PP
+..
+.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\}
+.\"
+.\" If the F register is turned on, we'll generate index entries on stderr for
+.\" titles (.TH), headers (.SH), subsections (.Sh), items (.Ip), and index
+.\" entries marked with X<> in POD.  Of course, you'll have to process the
+.\" output yourself in some meaningful fashion.
+.if \nF \{\
+.    de IX
+.    tm Index:\\$1\t\\n%\t"\\$2"
+..
+.    nr % 0
+.    rr F
+.\}
+.\"
+.\" For nroff, turn off justification.  Always turn off hyphenation; it makes
+.\" way too many mistakes in technical documents.
+.hy 0
+.if n .na
+.\"
+.\" 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 "V2HTML 1"
+.TH V2HTML 1 "January 2009" "v2html 7.30.1.3" "v2html"
+.SH "NAME"
+v2html \- Verilog to HTML converter
+.SH "SYNOPSIS"
+.IX Header "SYNOPSIS"
+\&\fBv2html\fR [options] file1 [file2] ...
+.PP
+\&\fBv2html\fR is a perl 5 script that converts a bunch of verilog files to
+html, linking various things to their definitions. At the moment
+it handles:
+.IP "\- modules" 5
+.IX Item "- modules"
+.PD 0
+.IP "\- tasks" 5
+.IX Item "- tasks"
+.IP "\- functions" 5
+.IX Item "- functions"
+.IP "\- includes" 5
+.IX Item "- includes"
+.IP "\- defines" 5
+.IX Item "- defines"
+.IP "\- parameters" 5
+.IX Item "- parameters"
+.IP "\- inputs,outputs,inouts" 5
+.IX Item "- inputs,outputs,inouts"
+.IP "\- signals: wire, reg etc." 5
+.IX Item "- signals: wire, reg etc."
+.IP "\- mail addresses in comments" 5
+.IX Item "- mail addresses in comments"
+.IP "\- http \s-1URLS\s0 (http://....) in comments" 5
+.IX Item "- http URLS (http://....) in comments"
+.PD
+.PP
+It also generates a page containing all the modules it found arranged
+hierarchically and separate index pages for all of the files, modules,
+signals, tasks and functions.
+.PP
+Once you have the html files they can be installed on a web\-server, or
+simply viewed using \*(L"Open File...\*(R" in your web browser.
+.PP
+Details on navigating around the converted files, and many examples
+can be found at http://www.burbleland.com/v2html/v2html.html .
+.PP
+Note that as of version 5.0 \fBv2html\fR uses \fIcascading style sheets\fR
+to colour the display. This means that pages viewed with old browsers
+that do not support \fIcascading style sheets\fR (for instance Netscape
+3) will not be coloured.
+.SH "DESCRIPTION"
+.IX Header "DESCRIPTION"
+In addition to the switches detailed below \fBv2html\fR also accepts and
+ignores most VCS/VerilogXL options and all other options starting with a
+plus. This means that you should be able to run it with the same
+command file you use for running simulations.
+.PP
+Switches:
+.IP "\fB\-q\fR" 5
+.IX Item "-q"
+Be quiet \- so don't print all those informative messages about what
+it is doing.
+.IP "\fB+define+NAME[=VALUE]\fR" 5
+.IX Item "+define+NAME[=VALUE]"
+Pre-define a value. This is just the same as putting:
+.Sp
+.Vb 1
+\&        \(aqdefine NAME [VALUE]
+.Ve
+.Sp
+at the top of each of your input files. The rather strange syntax is the
+same as VerilogXL's. This option is useful for controlling which ifdefs appear
+true to \fBv2html\fR.
+.IP "\fB+incdir+DIR\fR" 5
+.IX Item "+incdir+DIR"
+Specify a directory to search for include files (just like VerilogXL).
+.IP "\fB\-y\fR\ \s-1DIR\s0" 5
+.IX Item "-yDIR"
+Specify a directory to search for modules (just like VerilogXL). Note that
+\&\fBv2html\fR doesn't do any fancy search orders like VerilogXL \- it just searches
+the directories in the order that you specify them on the command line.
+.IP "\fB+libext+EXT\fR" 5
+.IX Item "+libext+EXT"
+Specify an extension use when searching for modules (just like
+VerilogXL). You can specify multiple extensions using
+\&\fB+libext+EXT1+EXT2+EXT2\fR or by specifying multiple \fB+libext+EXT\fR
+options.
+.IP "\fB\-v\fR\ \s-1LIBFILE\s0" 5
+.IX Item "-vLIBFILE"
+Specify a library file to use (just like VerilogXL).
+.IP "\fB\-f\fR\ command_lines_options_file" 5
+.IX Item "-fcommand_lines_options_file"
+Specify a file to get more command line options from. For instance you
+could put a list of all your files in src_files and then use \fB\-f\fR\ src_file.  You can also put in just about anything that you can put
+on the command line.  Comments can be included using # or // at the
+start of the line. Wildcards are not allowed in the file names. Use
+single or double quotes to quote arguments that have spaces in them
+for example:
+.Sp
+.Vb 3
+\&          # v2html \-f file \- turn on gzip compression
+\&          \-z \-ze .gz
+\&          \-zc \(aqgzip  \-f\(aq
+.Ve
+.Sp
+You can have as many \-f options as you want and you can probably put
+\&\-f options in the file too.
+.IP "\fB\-m\fR\ mail_addr" 5
+.IX Item "-mmail_addr"
+A mail address of the site maintainer. This is placed in a field at
+the bottom of each file like this:
+.Sp
+.Vb 4
+\& This page:
+\&         Maintained by:         Joe_Bloggs@barking.com
+\&         Created:               Thu Nov 6 08:53:37 1997
+\&         From:                  test2.v
+.Ve
+.IP "\fB\-i\fR" 5
+.IX Item "-i"
+Incremental mode. At the moment this isn't very incremental! \fBv2html\fR
+checks the dates on all of the files that it read last time it ran and
+all of the output files it generated.  If any of the input files are
+newer than the output files, or if the command line options have
+changed it \fBdeletes\fR all of the files it made last time and rebuilds
+everything. The delete is done to stop old files accumulating in the
+output directory.
+.Sp
+\&\fBv2html\fR keeps track of all the information it needs to do this in
+a file called .v2html_incr .
+.IP "\fB\-o\fR\ output_dir" 5
+.IX Item "-ooutput_dir"
+Set the output directory for the html files. The default is the current
+directory.
+.IP "\fB\-css\fR\ cascading_style_sheet" 5
+.IX Item "-csscascading_style_sheet"
+The appearance of all the different elements of the html page can be altered
+using a \fIcascading style sheet\fR. By default \fBv2html\fR uses a file called
+\&\fIv2html.css\fR in the same directory as the html files. You can customize the
+appearance of the html files by editing this file (\fBv2html\fR will create one
+if it does not exist, but will not overwrite an existing one). 
+.Sp
+If you have many different html directories which you want to use the
+one central cascading style sheet then you can use the \fB\-css\fR option
+to specify one. For example:
+.Sp
+.Vb 1
+\&        \-css http://www.barking.com/joes_style.css
+.Ve
+.IP "\fB\-h\fR\ hier_file" 5
+.IX Item "-hhier_file"
+Set the name of the file that the hierarchy is written to. The default
+is hierarchy.html. This is also used as a base for the index file
+names.  These file names are formed put appending \f(CW\*(C`\-f\*(C'\fR, \f(CW\*(C`\-m\*(C'\fR,
+\&\f(CW\*(C`\-s\*(C'\fR, \f(CW\*(C`\-t\*(C'\fR and \f(CW\*(C`\-fn\*(C'\fR to the part of the hierarchy file name
+before the first dot (so hier.htm will put the files index in
+hier\-f.htm).
+.IP "\fB\-ht\fR\ top_module" 5
+.IX Item "-httop_module"
+Set the name of a top module you want in the hierarchy. You can specify
+multiple \fB\-ht\fR options to specify multiple top modules. 
+.Sp
+If you don't specify any \fB\-ht\fR options then \fBv2html\fR will inspect
+the hierarchy and find all the top modules in the verilog files and
+print these out. The 'top modules' are modules that are not
+instantiated but instantiate other modules that \fBv2html\fR has found
+the definition of.
+.IP "\fB\-hc\fR\ hierarchy_comment" 5
+.IX Item "-hchierarchy_comment"
+Specifies some text to put at the top of the hierarchy. For instance:
+.Sp
+.Vb 1
+\&   v2html \-hc "This is our ASIC" *.v
+.Ve
+.IP "\fB\-htf\fR" 5
+.IX Item "-htf"
+Turns on printing of tasks and functions in the hierarchy. By default they
+are not printed.
+.IP "\fB\-lines\fR\ max_lines_per_file" 5
+.IX Item "-linesmax_lines_per_file"
+In order to speed up viewing \fBv2html\fR splits large verilog files across multiple
+html pages. This option lets you specify how many lines you want on a page. The 
+default is 1000.
+.IP "\fB\-nnm\fR" 5
+.IX Item "-nnm"
+No \*(L"No modules\*(R". By default the hierarchy contains three sections, the
+hierarchies of the top modules, a list of files containing no modules
+and a list of unconnected modules (modules that are not instantiated
+but also  do not qualify as top modules). The \fB\-nnm\fR makes
+\&\fBv2html\fR skip printing the list of files containing no modules.
+See \fB\-nu\fR.
+.IP "\fB\-nu\fR" 5
+.IX Item "-nu"
+No unconnected. See \fB\-nnm\fR. Makes \fBv2html\fR skip writing the list
+of unconnected modules in the hierarchy file.
+.IP "\fB\-nh\fR" 5
+.IX Item "-nh"
+No hierarchy. Don't print out the hierarchy.
+.IP "\fB\-nindex\fR" 5
+.IX Item "-nindex"
+No indexes. Don't print out the indexes.
+.IP "\fB\-ni\fR" 5
+.IX Item "-ni"
+By default \fBv2html\fR 'greys out' any code that is ifdefed out. The \fB\-ni\fR
+turns this greying out off. Note that v2html always ignores code that is
+ifdefed out when it is parsing.
+.IP "\fB\-z\fR" 5
+.IX Item "-z"
+Compress the html files generated (and make sure the links point to
+the compressed versions). This can be useful if you convert machine
+generated code, like \s-1ASIC\s0 \s-1RAM\s0 macros which are huge before they are
+converted and even bigger afterwards.
+.IP "\fB\-zc\fR\ compresser" 5
+.IX Item "-zccompresser"
+The executable to use to compress the html files if \fB\-z\fR is used. The
+Default is 'compress \f(CW\*(C`\-f\*(C'\fR'. For instance to use gzip use \fB\-zc\fR 'gzip \f(CW\*(C`\-f\*(C'\fR'
+(the \f(CW\*(C`\-f\*(C'\fR stops gzip prompting you about overwriting files).
+.IP "\fB\-ze\fR\ compressed_extension" 5
+.IX Item "-zecompressed_extension"
+The extension that your compress executable uses. The default is '.Z'. If you
+were using gzip then you'd want \fB\-ze\fR .gz
+.IP "\fB\-F\fR\ [frame_file.html]" 5
+.IX Item "-F[frame_file.html]"
+Frame mode. Using \fB\-F\fR turns on the generation of framed output
+where a top level frame file is generated that creates three
+frames in your browser, the top one for the hierarchy the middle
+one for the code and the bottom one for any definitions to appear 
+in.
+.Sp
+The default name for the frame file is frame.html. This default
+can be overridden by specifying a file name after the \fB\-F\fR option.
+.IP "\fB\-VF\fR\ [frame_file.html]" 5
+.IX Item "-VF[frame_file.html]"
+Same as \fB\-F\fR but arranges the frames vertically so that the hierarchy is
+down the side.
+.IP "\fB\-s\fR" 5
+.IX Item "-s"
+Link to the source. This causes the file name in From field of
+the page footer to become a link to the unconverted verilog 
+file:
+.Sp
+.Vb 4
+\& This page:
+\&         Maintained by:         Joe_Bloggs@barking.com
+\&         Created:               Thu Nov 6 08:53:37 1997
+\&         From:                  /asic/verilog/test2.v
+.Ve
+.Sp
+For this to work your web server must have access to the source code.
+Also, you must either run v2html in the output directory or use
+absolute path names for the verilog files.
+.Sp
+For example, if the source is in /home/asic/verilog and the html files
+want to end up in /home/www/verilog then there are two ways to run it
+to get \fB\-s\fR to work:
+.Sp
+.Vb 3
+\&  1) In the output directory with verilog files specified by relative paths:
+\&        cd /home/www/verilog
+\&        v2html \-s ../../asic/verilog/*.v
+.Ve
+.Sp
+.Vb 3
+\& 2) In any directory with verilog files specified by absolute paths:
+\&        cd /anywhere
+\&        v2html \-s \-o /home/www/verilog   /home/asic/verilog/*.v
+.Ve
+.IP "\fB\-c\fR\ /cgi_script\ /path_to_html_files" 5
+.IX Item "-c/cgi_script/path_to_html_files"
+Activate \s-1CGI\s0 features which allow the user to hide and show
+regions of the hierarchy in a similar way to the old file manager
+on windows 3.1. This method only works if you put the files on
+a web server.
+.Sp
+To use this you must have installed the v2html \s-1CGI\s0 script on your
+web\-server. The /cgi_script is the name of the \s-1CGI\s0 script (with path).
+The /path_to_v_files is the directory you are putting your html files.
+.Sp
+These paths are the paths your web server sees (not the full paths on
+the system) so is the same path that appears after \fIhttp://server\fR when 
+accessing the files.
+.Sp
+Here's an example:
+.Sp
+.Vb 2
+\&  cp v2html\-cgi /opt/CERNhttpd/cgi\-bin/ 
+\&  chmod 755 /opt/CERNhttpd/cgi\-bin/v2html\-cgi
+.Ve
+.Sp
+.Vb 2
+\&  cd /home/web/v2html/example/ex1
+\&  v2html \-c /cgi\-bin/v2html\-cgi /v2html/example/ex1 ../verilog/*.v
+.Ve
+.Sp
+Note that \fBv2html\fR can't check the parameters to \fB\-c\fR while
+converting the files. You'll have to do it yourself by viewing the
+hierarchy in your web browser and clicking on \fB[Hide\ All]\fR at the
+top of the hierarchy. Make sure you view the file using the web server
+(use \fIhttp://server/v2html/example/ex1/hierarchy.html\fR rather than
+\&\fIfile:/home/web/v2html/example/ex1/hierarchy.html\fR).
+.Sp
+Depending on your webserver you may also need to use the \-css to
+specify the full \s-1URL\s0 to your cascading stylesheet eg:
+.Sp
+.Vb 3
+\& v2html \-c /cgi\-bin/v2html\-cgi /v2html/examples/millennium_clock/hier_cgi
+\&  \-css http://www.burbleland.com/v2html/examples/millennium_clock/hier_cgi/v2html.css
+\&  *.v
+.Ve
+.Sp
+If you get a message like this when you click on \fB[Hide\ All]\fR:
+.Sp
+.Vb 2
+\&  Bad script request \-\- neither \(aq/opt/CERNhttpd/cgi\-bin/v2html\-cg\(aq 
+\&        nor \(aq/opt/CERNhttpd/cgi\-bin/v2html\-cg.pp\(aq is executable
+.Ve
+.Sp
+Then either there is either a problem with the installation of the cgi
+script or you have incorrectly specified the first parameter to \fB\-c\fR.
+.Sp
+If you get a message like this:
+.Sp
+.Vb 1
+\&  v2html error.
+.Ve
+.Sp
+then you have probably got the second parameter to \fB\-c\fR wrong.
+.IP "\fB\-k\fR\ key_string" 5
+.IX Item "-kkey_string"
+Specify the key to use for to stop people looking at hierarchy files
+that are protected by web-server security. The default is to use a
+random key, but this means that you can't have bookmarks of the
+hierarchy in various states (because the bookmark will contain the
+key, and the key will change each time you run \fBv2html\fR). To get
+round this problem you can use \fB\-k\fR and always have the same
+key string. The key can be any string of digits and letters.
+.IP "\fB\-njshier\fR" 5
+.IX Item "-njshier"
+Deactivate Javascript features that allow the user to hide and
+collapse regions of the hierarchy.
+.IP "\fB\-ncookies\fR" 5
+.IX Item "-ncookies"
+The Javascript version of the hierarchy uses cookies to remember the state
+you left the hierarchy in, so when you next visit the hierarchy page it will
+be in the same state. If you hate cookies then use the \fB\-ncookies\fR option
+to turn them off.
+.IP "\fB\-nsigpopup\fR" 5
+.IX Item "-nsigpopup"
+Turn off the generation of javascript that does the signal popup window.
+Specifying this option also turns off \*(L"Quick Search\*(R".
+.IP "\fB\-tab\fR\ value" 5
+.IX Item "-tabvalue"
+Expand tabs to the specified value.
+.IP "\fB\-debug\fR" 5
+.IX Item "-debug"
+Turn on lots of debugging information.
+.SH "AUTHOR"
+.IX Header "AUTHOR"
+Costas Calamvokis <\fIv2html730@burbleland.com\fR>.
+.SH "EXAMPLES"
+.IX Header "EXAMPLES"
+Here is an example where \fBv2html\fR is run in the directory containing
+the verilog files (note the \fB\-o\fR option):
+.PP
+.Vb 3
+\&  cd /users/jb/verilog_files/
+\&  v2html \-F my_frame.html \-h my_hier.html \-ht chip_top \-htf \-nu
+\&    \-o /users/www/project/verilog \-m Joe_Blogs@barking.com \-s *.v
+.Ve
+.PP
+As the verilog files don't have absolute paths and we aren't running
+in the destination directory can't use \fB\-s\fR (link to source) as the
+links \fBv2html\fR will create wouldn't allow the web server to find the
+files.
+.PP
+Here is an example where \fBv2html\fR is run in the directory where
+we want the html files (no \fB\-o\fR option):
+.PP
+.Vb 4
+\&  cd  /users/www/project/verilog
+\&  v2html \-F my_frame.html \-h my_hier.html \-ht chip_top \-nu \-htf
+\&    \-m Joe_Blogs@barking.com \-s  
+\&    \-c /cgi\-bin/v2html\-cgi /project/verilog ../../../jb/verilog_files/*.v
+.Ve
+.PP
+Here we can use the \fB\-s\fR option because we are running the the destination
+directory, so the links \fBv2html\fR creates to the source will work
+(providing the web server is allowed to server files from
+/users/jb/verilog_files).
+.SH "DIAGNOSTICS"
+.IX Header "DIAGNOSTICS"
+By default \fBv2html\fR tells you a lot about what it is doing (this is
+because it is slow and if it didn't you'd think it had crashed!). These
+messages can get in the way of the warnings \fBv2html\fR produces, so if
+you have a problem first try \fB\-q\fR (quiet) to see if there are any warnings
+you missed in the deluge of messages.
+.PP
+Most of the Error messages concern failures to open files, I guess these
+will be caused by bad permissions, or you pointing \fBv2html\fR at files
+or directories that don't exist.
+.PP
+The errors that say things like:
+.PP
+.Vb 5
+\&   Warning: Confused in t.v line 2 (state=SIGNAL_AFTER_NAME):
+\&   wire g  xx;
+\&           ^
+\&mean that you have written some verilog that I wasn\(aqt expecting \- send
+\&it to me and I\(aqll see what I can do.
+.Ve
+.PP
+Most of the warnings concern things that \fBv2html\fR will ignore because
+it found more than one of them. The most common is a duplicate module
+being found because an old copy of one of the files is lurking in
+your source directory. The easiest way around this is to use the
+\&\fB\-f\fR option something like this:
+.PP
+.Vb 2
+\&  ls /path/*.v | grep \-v old_module_file.v > src_files
+\&  v2html \-f src_files
+.Ve
+.PP
+Generally \fBv2html\fR will ignore duplicate things (so for example
+modules won't appear in the hierarchy), but sometimes it will just pick
+one of them, so watch those warnings.
diff --git a/bin/htmlgen/v2html/v2html.man.html b/bin/htmlgen/v2html/v2html.man.html
new file mode 100644
index 0000000000000000000000000000000000000000..f50978af0b88a7995106eff72c4e804acc20636f
--- /dev/null
+++ b/bin/htmlgen/v2html/v2html.man.html
@@ -0,0 +1,471 @@
+<?xml version="1.0" ?>
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<title>v2html - Verilog to HTML converter</title>
+<meta http-equiv="content-type" content="text/html; charset=utf-8" />
+<link rev="made" href="mailto:root@localhost" />
+</head>
+
+<body style="background-color: white">
+
+<p><a name="__index__"></a></p>
+<!-- INDEX BEGIN -->
+
+<ul>
+
+	<li><a href="#name">NAME</a></li>
+	<li><a href="#synopsis">SYNOPSIS</a></li>
+	<li><a href="#description">DESCRIPTION</a></li>
+	<li><a href="#author">AUTHOR</a></li>
+	<li><a href="#examples">EXAMPLES</a></li>
+	<li><a href="#diagnostics">DIAGNOSTICS</a></li>
+</ul>
+<!-- INDEX END -->
+
+<hr />
+<p>
+</p>
+<h1><a name="name">NAME</a></h1>
+<p>v2html - Verilog to HTML converter</p>
+<p>
+</p>
+<hr />
+<h1><a name="synopsis">SYNOPSIS</a></h1>
+<p><strong>v2html</strong> [options] file1 [file2] ...</p>
+<p><strong>v2html</strong> is a perl 5 script that converts a bunch of verilog files to
+html, linking various things to their definitions. At the moment
+it handles:</p>
+<dl>
+<dt><strong><a name="item__2d_modules">- modules</a></strong></dt>
+
+<dt><strong><a name="item__2d_tasks">- tasks</a></strong></dt>
+
+<dt><strong><a name="item__2d_functions">- functions</a></strong></dt>
+
+<dt><strong><a name="item__2d_includes">- includes</a></strong></dt>
+
+<dt><strong><a name="item__2d_defines">- defines</a></strong></dt>
+
+<dt><strong><a name="item__2d_parameters">- parameters</a></strong></dt>
+
+<dt><strong><a name="item__2d_inputs_2coutputs_2cinouts">- inputs,outputs,inouts</a></strong></dt>
+
+<dt><strong><a name="item__2d_signals_3a_wire_2c_reg_etc_2e">- signals: wire, reg etc.</a></strong></dt>
+
+<dt><strong><a name="item__2d_mail_addresses_in_comments">- mail addresses in comments</a></strong></dt>
+
+<dt><strong><a name="item_urls">- http URLS (http://....) in comments</a></strong></dt>
+
+</dl>
+<p>It also generates a page containing all the modules it found arranged
+hierarchically and separate index pages for all of the files, modules,
+signals, tasks and functions.</p>
+<p>Once you have the html files they can be installed on a web-server, or
+simply viewed using ``Open File...'' in your web browser.</p>
+<p>Details on navigating around the converted files, and many examples
+can be found at <a href="http://www.burbleland.com/v2html/v2html.html">http://www.burbleland.com/v2html/v2html.html</a> .</p>
+<p>Note that as of version 5.0 <strong>v2html</strong> uses <em>cascading style sheets</em>
+to colour the display. This means that pages viewed with old browsers
+that do not support <em>cascading style sheets</em> (for instance Netscape
+3) will not be coloured.</p>
+<p>
+</p>
+<hr />
+<h1><a name="description">DESCRIPTION</a></h1>
+<p>In addition to the switches detailed below <strong>v2html</strong> also accepts and
+ignores most VCS/VerilogXL options and all other options starting with a
+plus. This means that you should be able to run it with the same
+command file you use for running simulations.</p>
+<p>Switches:</p>
+<dl>
+<dt><strong><a name="item__2dq"><strong>-q</strong></a></strong></dt>
+
+<dd>
+<p>Be quiet - so don't print all those informative messages about what
+it is doing.</p>
+</dd>
+<dt><strong><a name="item__2bdefine_2bname_5b_3dvalue_5d"><strong>+define+NAME[=VALUE]</strong></a></strong></dt>
+
+<dd>
+<p>Pre-define a value. This is just the same as putting:</p>
+<pre>
+        'define NAME [VALUE]</pre>
+<p>at the top of each of your input files. The rather strange syntax is the
+same as VerilogXL's. This option is useful for controlling which ifdefs appear
+true to <strong>v2html</strong>.</p>
+</dd>
+<dt><strong><a name="item__2bincdir_2bdir"><strong>+incdir+DIR</strong></a></strong></dt>
+
+<dd>
+<p>Specify a directory to search for include files (just like VerilogXL).</p>
+</dd>
+<dt><strong><a name="item__2dy_dir"><strong>-y</strong>&nbsp;DIR</a></strong></dt>
+
+<dd>
+<p>Specify a directory to search for modules (just like VerilogXL). Note that
+<strong>v2html</strong> doesn't do any fancy search orders like VerilogXL - it just searches
+the directories in the order that you specify them on the command line.</p>
+</dd>
+<dt><strong><a name="item__2blibext_2bext"><strong>+libext+EXT</strong></a></strong></dt>
+
+<dd>
+<p>Specify an extension use when searching for modules (just like
+VerilogXL). You can specify multiple extensions using
+<strong>+libext+EXT1+EXT2+EXT2</strong> or by specifying multiple <strong>+libext+EXT</strong>
+options.</p>
+</dd>
+<dt><strong><a name="item__2dv_libfile"><strong>-v</strong>&nbsp;LIBFILE</a></strong></dt>
+
+<dd>
+<p>Specify a library file to use (just like VerilogXL).</p>
+</dd>
+<dt><strong><a name="item__2df_command_lines_options_file"><strong>-f</strong>&nbsp;command_lines_options_file</a></strong></dt>
+
+<dd>
+<p>Specify a file to get more command line options from. For instance you
+could put a list of all your files in src_files and then use <strong>-f</strong>
+src_file.  You can also put in just about anything that you can put
+on the command line.  Comments can be included using # or // at the
+start of the line. Wildcards are not allowed in the file names. Use
+single or double quotes to quote arguments that have spaces in them
+for example:</p>
+<pre>
+          # v2html -f file - turn on gzip compression
+          -z -ze .gz
+          -zc 'gzip  -f'
+           
+You can have as many -f options as you want and you can probably put
+-f options in the file too.</pre>
+</dd>
+<dt><strong><a name="item__2dm_mail_addr"><strong>-m</strong>&nbsp;mail_addr</a></strong></dt>
+
+<dd>
+<p>A mail address of the site maintainer. This is placed in a field at
+the bottom of each file like this:</p>
+<pre>
+ This page:
+         Maintained by:         Joe_Bloggs@barking.com
+         Created:               Thu Nov 6 08:53:37 1997
+         From:                  test2.v</pre>
+</dd>
+<dt><strong><a name="item__2di"><strong>-i</strong></a></strong></dt>
+
+<dd>
+<p>Incremental mode. At the moment this isn't very incremental! <strong>v2html</strong>
+checks the dates on all of the files that it read last time it ran and
+all of the output files it generated.  If any of the input files are
+newer than the output files, or if the command line options have
+changed it <strong>deletes</strong> all of the files it made last time and rebuilds
+everything. The delete is done to stop old files accumulating in the
+output directory.</p>
+<p><strong>v2html</strong> keeps track of all the information it needs to do this in
+a file called .v2html_incr .</p>
+</dd>
+<dt><strong><a name="item__2do_output_dir"><strong>-o</strong>&nbsp;output_dir</a></strong></dt>
+
+<dd>
+<p>Set the output directory for the html files. The default is the current
+directory.</p>
+</dd>
+<dt><strong><a name="item__2dcss_cascading_style_sheet"><strong>-css</strong>&nbsp;cascading_style_sheet</a></strong></dt>
+
+<dd>
+<p>The appearance of all the different elements of the html page can be altered
+using a <em>cascading style sheet</em>. By default <strong>v2html</strong> uses a file called
+<em>v2html.css</em> in the same directory as the html files. You can customize the
+appearance of the html files by editing this file (<strong>v2html</strong> will create one
+if it does not exist, but will not overwrite an existing one).</p>
+<p>If you have many different html directories which you want to use the
+one central cascading style sheet then you can use the <strong>-css</strong> option
+to specify one. For example:</p>
+<pre>
+        -css <a href="http://www.barking.com/joes_style.css">http://www.barking.com/joes_style.css</a></pre>
+</dd>
+<dt><strong><a name="item__2dh_hier_file"><strong>-h</strong>&nbsp;hier_file</a></strong></dt>
+
+<dd>
+<p>Set the name of the file that the hierarchy is written to. The default
+is hierarchy.html. This is also used as a base for the index file
+names.  These file names are formed put appending <code>-f</code>, <code>-m</code>,
+<a href="#item__2ds"><code>-s</code></a>, <code>-t</code> and <code>-fn</code> to the part of the hierarchy file name
+before the first dot (so hier.htm will put the files index in
+hier-f.htm).</p>
+</dd>
+<dt><strong><a name="item__2dht_top_module"><strong>-ht</strong>&nbsp;top_module</a></strong></dt>
+
+<dd>
+<p>Set the name of a top module you want in the hierarchy. You can specify
+multiple <strong>-ht</strong> options to specify multiple top modules.</p>
+<p>If you don't specify any <strong>-ht</strong> options then <strong>v2html</strong> will inspect
+the hierarchy and find all the top modules in the verilog files and
+print these out. The 'top modules' are modules that are not
+instantiated but instantiate other modules that <strong>v2html</strong> has found
+the definition of.</p>
+</dd>
+<dt><strong><a name="item__2dhc_hierarchy_comment"><strong>-hc</strong>&nbsp;hierarchy_comment</a></strong></dt>
+
+<dd>
+<p>Specifies some text to put at the top of the hierarchy. For instance:</p>
+<pre>
+   v2html -hc &quot;This is our ASIC&quot; *.v</pre>
+</dd>
+<dt><strong><a name="item__2dhtf"><strong>-htf</strong></a></strong></dt>
+
+<dd>
+<p>Turns on printing of tasks and functions in the hierarchy. By default they
+are not printed.</p>
+</dd>
+<dt><strong><a name="item__2dlines_max_lines_per_file"><strong>-lines</strong>&nbsp;max_lines_per_file</a></strong></dt>
+
+<dd>
+<p>In order to speed up viewing <strong>v2html</strong> splits large verilog files across multiple
+html pages. This option lets you specify how many lines you want on a page. The 
+default is 1000.</p>
+</dd>
+<dt><strong><a name="item__2dnnm"><strong>-nnm</strong></a></strong></dt>
+
+<dd>
+<p>No ``No modules''. By default the hierarchy contains three sections, the
+hierarchies of the top modules, a list of files containing no modules
+and a list of unconnected modules (modules that are not instantiated
+but also  do not qualify as top modules). The <strong>-nnm</strong> makes
+<strong>v2html</strong> skip printing the list of files containing no modules.
+See <strong>-nu</strong>.</p>
+</dd>
+<dt><strong><a name="item__2dnu"><strong>-nu</strong></a></strong></dt>
+
+<dd>
+<p>No unconnected. See <strong>-nnm</strong>. Makes <strong>v2html</strong> skip writing the list
+of unconnected modules in the hierarchy file.</p>
+</dd>
+<dt><strong><a name="item__2dnh"><strong>-nh</strong></a></strong></dt>
+
+<dd>
+<p>No hierarchy. Don't print out the hierarchy.</p>
+</dd>
+<dt><strong><a name="item__2dnindex"><strong>-nindex</strong></a></strong></dt>
+
+<dd>
+<p>No indexes. Don't print out the indexes.</p>
+</dd>
+<dt><strong><a name="item__2dni"><strong>-ni</strong></a></strong></dt>
+
+<dd>
+<p>By default <strong>v2html</strong> 'greys out' any code that is ifdefed out. The <strong>-ni</strong>
+turns this greying out off. Note that v2html always ignores code that is
+ifdefed out when it is parsing.</p>
+</dd>
+<dt><strong><a name="item__2dz"><strong>-z</strong></a></strong></dt>
+
+<dd>
+<p>Compress the html files generated (and make sure the links point to
+the compressed versions). This can be useful if you convert machine
+generated code, like ASIC RAM macros which are huge before they are
+converted and even bigger afterwards.</p>
+</dd>
+<dt><strong><a name="item__2dzc_compresser"><strong>-zc</strong>&nbsp;compresser</a></strong></dt>
+
+<dd>
+<p>The executable to use to compress the html files if <strong>-z</strong> is used. The
+Default is 'compress <code>-f</code>'. For instance to use gzip use <strong>-zc</strong> 'gzip <code>-f</code>'
+(the <code>-f</code> stops gzip prompting you about overwriting files).</p>
+</dd>
+<dt><strong><a name="item__2dze_compressed_extension"><strong>-ze</strong>&nbsp;compressed_extension</a></strong></dt>
+
+<dd>
+<p>The extension that your compress executable uses. The default is '.Z'. If you
+were using gzip then you'd want <strong>-ze</strong> .gz</p>
+</dd>
+<dt><strong><a name="item__2df__5bframe_file_2ehtml_5d"><strong>-F</strong>&nbsp;[frame_file.html]</a></strong></dt>
+
+<dd>
+<p>Frame mode. Using <strong>-F</strong> turns on the generation of framed output
+where a top level frame file is generated that creates three
+frames in your browser, the top one for the hierarchy the middle
+one for the code and the bottom one for any definitions to appear 
+in.</p>
+<p>The default name for the frame file is frame.html. This default
+can be overridden by specifying a file name after the <strong>-F</strong> option.</p>
+</dd>
+<dt><strong><a name="item__2dvf__5bframe_file_2ehtml_5d"><strong>-VF</strong>&nbsp;[frame_file.html]</a></strong></dt>
+
+<dd>
+<p>Same as <strong>-F</strong> but arranges the frames vertically so that the hierarchy is
+down the side.</p>
+</dd>
+<dt><strong><a name="item__2ds"><strong>-s</strong></a></strong></dt>
+
+<dd>
+<p>Link to the source. This causes the file name in From field of
+the page footer to become a link to the unconverted verilog 
+file:</p>
+<pre>
+ This page:
+         Maintained by:         Joe_Bloggs@barking.com
+         Created:               Thu Nov 6 08:53:37 1997
+         From:                  /asic/verilog/test2.v</pre>
+<p>For this to work your web server must have access to the source code.
+Also, you must either run v2html in the output directory or use
+absolute path names for the verilog files.</p>
+<p>For example, if the source is in /home/asic/verilog and the html files
+want to end up in /home/www/verilog then there are two ways to run it
+to get <strong>-s</strong> to work:</p>
+<pre>
+  1) In the output directory with verilog files specified by relative paths:
+        cd /home/www/verilog
+        v2html -s ../../asic/verilog/*.v</pre>
+<pre>
+ 2) In any directory with verilog files specified by absolute paths:
+        cd /anywhere
+        v2html -s -o /home/www/verilog   /home/asic/verilog/*.v</pre>
+</dd>
+<dt><strong><a name="item__2dc__2fcgi_script__2fpath_to_html_files"><strong>-c</strong>&nbsp;/cgi_script&nbsp;/path_to_html_files</a></strong></dt>
+
+<dd>
+<p>Activate CGI features which allow the user to hide and show
+regions of the hierarchy in a similar way to the old file manager
+on windows 3.1. This method only works if you put the files on
+a web server.</p>
+<p>To use this you must have installed the v2html CGI script on your
+web-server. The /cgi_script is the name of the CGI script (with path).
+The /path_to_v_files is the directory you are putting your html files.</p>
+<p>These paths are the paths your web server sees (not the full paths on
+the system) so is the same path that appears after <em><a href="http://server">http://server</a></em> when 
+accessing the files.</p>
+<p>Here's an example:</p>
+<pre>
+  cp v2html-cgi /opt/CERNhttpd/cgi-bin/ 
+  chmod 755 /opt/CERNhttpd/cgi-bin/v2html-cgi</pre>
+<pre>
+  cd /home/web/v2html/example/ex1
+  v2html -c /cgi-bin/v2html-cgi /v2html/example/ex1 ../verilog/*.v</pre>
+<p>Note that <strong>v2html</strong> can't check the parameters to <strong>-c</strong> while
+converting the files. You'll have to do it yourself by viewing the
+hierarchy in your web browser and clicking on <strong>[Hide&nbsp;All]</strong> at the
+top of the hierarchy. Make sure you view the file using the web server
+(use <em><a href="http://server/v2html/example/ex1/hierarchy.html">http://server/v2html/example/ex1/hierarchy.html</a></em> rather than
+<em>file:/home/web/v2html/example/ex1/hierarchy.html</em>).</p>
+<p>Depending on your webserver you may also need to use the -css to
+specify the full URL to your cascading stylesheet eg:</p>
+<pre>
+ v2html -c /cgi-bin/v2html-cgi /v2html/examples/millennium_clock/hier_cgi
+  -css <a href="http://www.burbleland.com/v2html/examples/millennium_clock/hier_cgi/v2html.css">http://www.burbleland.com/v2html/examples/millennium_clock/hier_cgi/v2html.css</a>
+  *.v</pre>
+<p>If you get a message like this when you click on <strong>[Hide&nbsp;All]</strong>:</p>
+<pre>
+  Bad script request -- neither '/opt/CERNhttpd/cgi-bin/v2html-cg' 
+        nor '/opt/CERNhttpd/cgi-bin/v2html-cg.pp' is executable</pre>
+<p>Then either there is either a problem with the installation of the cgi
+script or you have incorrectly specified the first parameter to <strong>-c</strong>.</p>
+<p>If you get a message like this:</p>
+<pre>
+  v2html error.</pre>
+<p>then you have probably got the second parameter to <strong>-c</strong> wrong.</p>
+</dd>
+<dt><strong><a name="item__2dk_key_string"><strong>-k</strong>&nbsp;key_string</a></strong></dt>
+
+<dd>
+<p>Specify the key to use for to stop people looking at hierarchy files
+that are protected by web-server security. The default is to use a
+random key, but this means that you can't have bookmarks of the
+hierarchy in various states (because the bookmark will contain the
+key, and the key will change each time you run <strong>v2html</strong>). To get
+round this problem you can use <strong>-k</strong> and always have the same
+key string. The key can be any string of digits and letters.</p>
+</dd>
+<dt><strong><a name="item__2dnjshier"><strong>-njshier</strong></a></strong></dt>
+
+<dd>
+<p>Deactivate Javascript features that allow the user to hide and
+collapse regions of the hierarchy.</p>
+</dd>
+<dt><strong><a name="item__2dncookies"><strong>-ncookies</strong></a></strong></dt>
+
+<dd>
+<p>The Javascript version of the hierarchy uses cookies to remember the state
+you left the hierarchy in, so when you next visit the hierarchy page it will
+be in the same state. If you hate cookies then use the <strong>-ncookies</strong> option
+to turn them off.</p>
+</dd>
+<dt><strong><a name="item__2dnsigpopup"><strong>-nsigpopup</strong></a></strong></dt>
+
+<dd>
+<p>Turn off the generation of javascript that does the signal popup window.
+Specifying this option also turns off ``Quick Search''.</p>
+</dd>
+<dt><strong><a name="item__2dtab_value"><strong>-tab</strong>&nbsp;value</a></strong></dt>
+
+<dd>
+<p>Expand tabs to the specified value.</p>
+</dd>
+<dt><strong><a name="item__2ddebug"><strong>-debug</strong></a></strong></dt>
+
+<dd>
+<p>Turn on lots of debugging information.</p>
+</dd>
+</dl>
+<p>
+</p>
+<hr />
+<h1><a name="author">AUTHOR</a></h1>
+<p>Costas Calamvokis &lt;<em><a href="mailto:v2html730@burbleland.com">v2html730@burbleland.com</a></em>&gt;.</p>
+<p>
+</p>
+<hr />
+<h1><a name="examples">EXAMPLES</a></h1>
+<p>Here is an example where <strong>v2html</strong> is run in the directory containing
+the verilog files (note the <strong>-o</strong> option):</p>
+<pre>
+  cd /users/jb/verilog_files/
+  v2html -F my_frame.html -h my_hier.html -ht chip_top -htf -nu
+    -o /users/www/project/verilog -m Joe_Blogs@barking.com -s *.v</pre>
+<p>As the verilog files don't have absolute paths and we aren't running
+in the destination directory can't use <strong>-s</strong> (link to source) as the
+links <strong>v2html</strong> will create wouldn't allow the web server to find the
+files.</p>
+<p>Here is an example where <strong>v2html</strong> is run in the directory where
+we want the html files (no <strong>-o</strong> option):</p>
+<pre>
+  cd  /users/www/project/verilog
+  v2html -F my_frame.html -h my_hier.html -ht chip_top -nu -htf
+    -m Joe_Blogs@barking.com -s  
+    -c /cgi-bin/v2html-cgi /project/verilog ../../../jb/verilog_files/*.v</pre>
+<p>Here we can use the <strong>-s</strong> option because we are running the the destination
+directory, so the links <strong>v2html</strong> creates to the source will work
+(providing the web server is allowed to server files from
+/users/jb/verilog_files).</p>
+<p>
+</p>
+<hr />
+<h1><a name="diagnostics">DIAGNOSTICS</a></h1>
+<p>By default <strong>v2html</strong> tells you a lot about what it is doing (this is
+because it is slow and if it didn't you'd think it had crashed!). These
+messages can get in the way of the warnings <strong>v2html</strong> produces, so if
+you have a problem first try <strong>-q</strong> (quiet) to see if there are any warnings
+you missed in the deluge of messages.</p>
+<p>Most of the Error messages concern failures to open files, I guess these
+will be caused by bad permissions, or you pointing <strong>v2html</strong> at files
+or directories that don't exist.</p>
+<p>The errors that say things like:</p>
+<pre>
+   Warning: Confused in t.v line 2 (state=SIGNAL_AFTER_NAME):
+   wire g  xx;
+           ^
+mean that you have written some verilog that I wasn't expecting - send
+it to me and I'll see what I can do.</pre>
+<p>Most of the warnings concern things that <strong>v2html</strong> will ignore because
+it found more than one of them. The most common is a duplicate module
+being found because an old copy of one of the files is lurking in
+your source directory. The easiest way around this is to use the
+<strong>-f</strong> option something like this:</p>
+<pre>
+  ls /path/*.v | grep -v old_module_file.v &gt; src_files
+  v2html -f src_files</pre>
+<p>Generally <strong>v2html</strong> will ignore duplicate things (so for example
+modules won't appear in the hierarchy), but sometimes it will just pick
+one of them, so watch those warnings.</p>
+
+</body>
+
+</html>
diff --git a/tools/htmlgen b/tools/htmlgen
new file mode 100644
index 0000000000000000000000000000000000000000..a9bf588e2f88457fdf73ac7361ef1d596fb81453
--- /dev/null
+++ b/tools/htmlgen
@@ -0,0 +1 @@
+#!/bin/bash
diff --git a/tools/socpull b/tools/socpull
new file mode 100755
index 0000000000000000000000000000000000000000..42ff6515f1c6ed566a464cc2f9cc307878b517f0
--- /dev/null
+++ b/tools/socpull
@@ -0,0 +1,10 @@
+#!/bin/bash
+
+# Update all Submodules to latest commit
+cd $DESIGN_ROOT; git submodule foreach --recursive git pull
+# for d in $DESIGN_ROOT/* ; do
+#     if [ -f "$d/.git" ]; then
+#         echo "Git Pulling $d"
+#         cd $d; git pull; cd ..
+#     fi
+# done
\ No newline at end of file
diff --git a/tools/socsim b/tools/socsim
new file mode 100755
index 0000000000000000000000000000000000000000..194c887da51b7c398a430ffb98f9f61ed7138a02
--- /dev/null
+++ b/tools/socsim
@@ -0,0 +1,47 @@
+#-----------------------------------------------------------------------------
+# SoC Labs socsim script to run required simulation
+# A joint work commissioned on behalf of SoC Labs, under Arm Academic Access license.
+#
+# Contributors
+#
+# David Mapstone (d.a.mapstone@soton.ac.uk)
+#
+# Copyright 2023, SoC Labs (www.soclabs.org)
+#-----------------------------------------------------------------------------
+
+#!/usr/bin/env bash
+
+# Check arguments passed to SoCSim
+if [ $# -eq 0 ]
+  then
+    echo "No arguments supplied"
+else 
+
+    # If clean command passed in clean a specific directory or all
+    if [ ${1} == "clean" ]; then
+        if [ $# -eq 1 ];  then
+            echo "No clean arguments supplied"
+        else
+            if [ ${2} == "all" ]; then
+                # Clean all simualation directories
+                echo "Cleaning all Project Simulation Directories"
+                rm -rf $PROJECT_DIR/simulate/sim
+                mkdir -p $PROJECT_DIR/simulate/sim
+            else
+                # Remove specific simulaiton directory
+                SIM_DIR=$PROJECT_DIR/simulate/sim/${2}
+                if [ -d "$SIM_DIR" ]; then
+                    rm -rf $SIM_DIR
+                else 
+                    echo "Simulation Directory '${2}' doesn't exist"
+                fi
+            fi
+        fi
+    fi
+
+    # Find a simulation script in the SoCSim environments of all subrepos
+    simscript=$(find ${SOCSIM_PATH//:/\ } -name "${1}.sh")
+
+    # Run Script if Found
+    $simscript $@
+fi
\ No newline at end of file