#!/import/datools/exe/perl5.004_04 -w #!/usr/bin/perl -w ############################################################################### # # File: v2html # RCS: $Header: /home2/cc/v2html/RCS/v2html,v 5.0 1999/03/02 04:32:19 cc Exp $ # Description: Verilog to html converter # Author: Costas Calamvokis # Created: Wed Aug 20 11:24:31 1997 # Modified: Mon Mar 1 20:30:51 1999 (Costas Calamvokis) v2html@iname.com # Language: Perl # # Copyright 1999,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. # ############################################################################### # This is commented out in the distribution because it means that # v2html will work even if the perl libraries are not installed # properly #use strict; # Define the global varaibles 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 $javascript $js_file $out_dir @global_includes $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 $qs $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_compiler_keywords @verilog_gatetype_keywords $verilog_gatetype_regexp %verilog_keywords_hash %verilog_compiler_keywords_hash $version $mail_regexp $http_regexp $VID $icon_c $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; } # initialise &init; # read the arguements &process_args; # legal stuff - do not delete if (!$quiet) { print "v2html version $version. See LICENCE.TXT for licence.\n"; print " Copyright 1999,1998 Costas Calamvokis\n"; print " Copyright 1997 Hewlett-Packard Company\n"; } $style_sheet_link = "\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.abrizio.com/v2html/help_5_0.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,\@global_includes,\%cmd_line_defines, $quiet,\@inc_dirs,\@lib_dirs,\@lib_exts); if ($output_index) { print "Writing indexes\n" unless $quiet; print_indexes($verilog_db,$javascript); } # write the hieararchy (must be done after the indexes) if ($output_hier) { print "Writing hierarchy to $hier_file\n" unless $quiet; print_hier($hier_file,$javascript,\@hier_tops); } # write the frames if ($frames) { print "Writing frames to $frame_file\n" unless $quiet; if (defined(@hier_tops)) { print_frame_top($frame_file,$hier_file,join(", ",@hier_tops), $javascript); } else { print_frame_top($frame_file,$hier_file,$web_base,$javascript); } } # print out gif icons used print_gifs($out_dir, ($cgi_script || $javascript), $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)); } foreach $module (&rvp::get_ignored_modules($verilog_db)) { print "Warning: module $module ignored (more than one definition found)\n" if !$quiet; } # Write out a file list for incremental - we can't 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); } exit 0; ############################################################################### # Subroutines ############################################################################### ############################################################################### # initialise 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; $frame_bottom = ""; $frame_middle = ""; $frame_code = ""; # frame for jumping to code $frame_top = ""; $link_to_source = 0; $cgi_script = ""; $web_base = ""; $javascript = 0; $js_file = ""; $qs = ""; $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; $qs = ' onClick="return qs(event,this)"'; # for quick search $js_cookies=1; $css= 'v2html.css'; # default cascading style sheet name $out_dir='./'; @verilog_keywords = qw( always endtask or supply0 and event output supply1 assign for parameter table attribute force pmos task begin forever posedge time buf fork primitive tran bufif0 function pull0 tranif0 bufif1 highz0 pull1 tranif1 case highz1 pulldown tri casex if pullup tri0 casez initial rcmos tri1 cmos inout reg triand deassign input release trior default integer repeat real trireg defparam join rnmos use disable large rpmos vectored edge macromodule rtran wait else medium rtranif0 wand end module rtranif1 weak0 endattribute nand scalared weak1 endcase negedge small while endfunction nmos specify wire endmodule nor specparam wor endprimitive not strength xnor endspecify notif0 strong0 xor endtable notif1 strong1 ); @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 rtran if1 ); @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 ); #` $verilog_gatetype_regexp = "\\b(" . join("|",@verilog_gatetype_keywords) . ")\\b"; @verilog_keywords_hash{@verilog_keywords} = "" x @verilog_keywords; @verilog_compiler_keywords_hash{@verilog_compiler_keywords} = "" x @verilog_compiler_keywords; $version = '$Header: /home2/cc/v2html/RCS/v2html,v 5.0 1999/03/02 04:32:19 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=>'ST', signal_tri0=>'ST0', signal_tri1=>'ST1', signal_triand=>'STA', signal_trireg=>'STR', signal_supply0=>'SS0', signal_supply1=>'SS1', signal_wand=>'SWA', signal_wor=>'SWO', signal_time=>'STM', signal_real=>'SR', module=>'MM', task=>'T', function=>'F', define=>'D', parameter=>'PA', navbar=>'NB'); # 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]+)\b'; # 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 = ""; $icon_x = ""; } sub init_classes { } ############################################################################### # 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; next; } elsif ( /^-o$/ ) { $out_dir = shift(@ARGV); $out_dir =~ s/[\/]?$/\//; next; } elsif ( /^-m$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $maint = shift(@ARGV); next; } elsif ( /^-ht$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); push(@hier_tops,shift(@ARGV)); next; } elsif ( /^-h$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $hier_file = shift(@ARGV); next; } elsif ( /^-hc$/ ) { &usage("$_ needs an arguement") 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 arguements") if ($#ARGV < 1); $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$/ ) { $javascript = 1; $help_info.='js-'; next; } elsif ( /^-qs$/ ) { # quick search is now on by default next; } elsif ( /^-nqs$/ ) { $qs = ''; $help_info.='nqs-'; 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 arguement") if ($#ARGV < 0); $_ = shift(@ARGV); @compress_cmd = split ; next; } elsif ( /^-ze$/ ) { &usage("$_ needs an arguement") 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 stlye sheet (v2html.css) instead\n"; next; } elsif ( /^-f$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); add_options_from_file(shift(@ARGV)); next; } elsif ( /^-F$/ ) { $frames = 1; $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); } } $help_info.='F-'; next; } elsif ( /^-g$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $f = shift(@ARGV); $f = ffile($f); push(@global_includes,$f); } elsif ( /^-lines$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $lines_per_file = shift(@ARGV); } elsif ( /^\+define\+($VID)(?:(?:=)(.*))?$/ ) { # 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 arguement") if ($#ARGV < 0); $cgi_key = shift(@ARGV); } elsif ( /^-tab$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $tabstop = shift(@ARGV); next; } elsif ( /^-css$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); $css = shift(@ARGV); } elsif ( /^-y$/ ) { &usage("$_ needs an arguement") if ($#ARGV < 0); push(@lib_dirs,shift(@ARGV)); next; } elsif ( /^\+incdir\+(.+)$/ ) { push(@inc_dirs,$1); next; } elsif ( /^\+libext\+(.+)$/ ) { push(@lib_exts,split(/\+/,$1)); next; } else { if ( /^-v$/ ) { # -v file is exactly the same as file without -v &usage("$_ needs an arguement") if ($#ARGV < 0); $_=shift(@ARGV); } if ( -r $_ ) { # Try it as a file and see if it is readable if (exists($files_seen{$_})) { print "Warning: ignoring duplicate file on command line $_\n"; } else { push(@files,$_); } $files_seen{$_}=1; } else { # 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; } # 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; } if ( /^[-+]/ ) { &usage("Unrecognised option: $_"); } 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 ($javascript && $cgi_script); $frame_code = 'target="_top"' if ($javascript && !$frames); } ############################################################################### # show usage # sub usage { my ($msg) = @_; print "\nError: $msg\n"; print <; $/ = "\n"; close(F); while ($text_s =~ m%(//[^\n]*\n)|(#[^\n]*\n)|('[^']*')|("[^"]*")|(\S+)%gs ) { #'){ get emacs mode back in sync! $_ = $&; if ( m/\n$/ ) { # 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 "Couldn't 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't 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 () { 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 "Arguements 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 (doesn't 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 "Couldn't 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 # arguements: $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,$js) = @_; print_h_or_js($out,"
\n",$js); print_h_or_js($out,"\n
This page:<\/td>\n",$js); if ($maint ne '') { print_h_or_js($out," Maintained by:<\/td>\n",$js); print_h_or_js($out," \n",$js); print_h_or_js($out," " . $maint . "<\/A><\/tr>\n
<\/td>\n",$js); } print_h_or_js($out," Created:<\/td>" . localtime() . "<\/td><\/tr>\n",$js); if ($src ne '') { print_h_or_js($out," <\/td>From:<\/td>\n",$js); if ($link_to_source) { print_h_or_js($out," \n",$js); quote_html(\$src); print_h_or_js($out,$src . "<\/A><\/tr>\n",$js); } else { quote_html(\$src); print_h_or_js($out, $src . "<\/tr>\n",$js); } } print_h_or_js($out,"
\n
\n",$js); ################################################################## # Do not alter any of this footer information # ################################################################## print_h_or_js($out,'",$js); print_h_or_js($out,'
Verilog converted to html by ',$js); print_h_or_js($out,' ',$js); print_h_or_js($out," v2html $version<\/A> \n",$js); print_h_or_js($out," (written by",$js); print_h_or_js($out," ",$js); print_h_or_js($out,"Costas Calamvokis<\/A>).<\/i>'. 'Help
',$js); ################################################################## # End of footer information # ################################################################## } ############################################################################### # Print out a navigation bar ############################################################################### sub print_navbar { my ($out,$js,$type,$data,$prevnext,$prevnext_file) = @_; my ($elem,$col); $col = @{$data->{order}}; # skip hierarchy if frames are on - it'll always be in top frame $col-- if $frames; $col++ if $prevnext; return unless ($col); print_h_or_js($out,"
",$js); if ($prevnext) { print_h_or_js($out,"", $js); } foreach $elem (@{$data->{order}}) { # skip hierarchy if frames are on - it'll always be in top frame next if (($elem eq 'Hierarchy') && $frames); if ( $elem eq $type ) { print_h_or_js($out,"",$js); } else { print_h_or_js($out,"", $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); @{$data} = sort { uc($a) cmp uc($b) } @{$data}; # work out the indexes $first_char=""; # make sure it won't 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[$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,$i,$ofile); local (*OUT); for ($page=1;$page<=$info->{pages};$page++) { $ofile=$info->{files}[$page]{name}; open(OUT,">$out_dir$ofile") || die "Error: can't open file $out_dir$ofile to write: $!\n"; push(@output_files,"$out_dir$ofile"); print OUT "\n"; print OUT "\n"; print OUT "$type index".(($page==1)?"":" page $page")."\n"; print OUT $style_sheet_link; print OUT "\n"; print OUT "\n"; print OUT "\n"; if ($page==1) { print_navbar(*OUT,0,$type,\%navbar,'',''); } else { print_navbar(*OUT,0,$type,\%navbar,"Prev Page", $info->{files}[$page-1]{name}.'#bottom_of_page'); } print_navbar(*OUT,0,'',$info->{nb},'',''); print OUT "

$type index

\n"; print OUT "
\n"; $first_char=""; # make sure it won't 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 "\n"; print OUT "
". "$prevnext". "$elem". "{$elem}\">$elem
". "
". "$first_char". "
\n"; } &{$printfn}(*OUT,$fdata,$data->[$i]); } print OUT "\n"; print_navbar(*OUT,0,'',$info->{nb},'',''); if ($page==$info->{pages}) { print_navbar(*OUT,0,$type,\%navbar,'',''); } else { print_navbar(*OUT,0,$type,\%navbar,"Next Page", $info->{files}[$page+1]{name}); } print_footer(*OUT,'',0); print OUT "\n"; print OUT "\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 = "". "$data\n"; $ms=$comma=''; foreach $m (&rvp::get_files_modules($fdata,$data)) { $qword = $m; quote_html(\$qword); if (&rvp::module_exists($fdata,$m)) { $ms .= "$comma$qword "; } else { $ms .= "$comma$qword "; } $comma=', '; } $inc=$comma=''; foreach $i (&rvp::get_files_includes($fdata,$data)) { $qword = $i; quote_html(\$qword); if (&rvp::file_exists($fdata,$i)) { $inc .= "$comma$qword "; } else { $inc .= "$comma$qword "; } $comma=', '; } $inc_by=$comma=''; foreach $i (&rvp::get_files_included_by($fdata,$data)) { $qword = $i; quote_html(\$qword); if (&rvp::file_exists($fdata,$i)) { $inc_by .= "$comma$qword "; } else { $inc_by .= "$comma$qword "; } $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 = "". "$qword\n"; $title .= "($type)\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$m:$i "; } else { $inst.="$comma$m:$i "; } $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$m:$i "; } else { $inst_by.="$comma$m:$i "; } $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$tf<\/a> "; $fcomma=', '; } else { $tasks.="$comma$tf<\/a> "; $comma=', '; } } } print_itable( $out , $title , [ "File:" , "$file" , "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_a_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,$s_a_line,$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 = "". "$qword : $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$im:$in:$p "; } else { $port_con.="$comma$im:$in:$p "; } $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$ctm:$cti:$cts "; } else { $con_to.="$comma$ctm:$cti:$cts "; } $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 = "". "$qword"; print_itable( $out , $title , [ "File:" , "$t_file" , "Module:" , "$m" ]); } ############################################################################### # 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 "
 $title\n"; if (@{$tab}) { $empty=1; print $out "
\n"; while ($f1=shift(@{$tab})) { $f2=shift(@{$tab}); die "print_itable internal error" unless (defined($f2)); if ($f2 ne '') { $empty=0; print $out "". "\n"; } } print $out "\n" if ($empty); # NS doesn't like empty tables print $out "
$f1$f2
\n"; } } sub index_link { my ($type,$elem) = @_; # debugging checks # print "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 # arguements: output_file_name, javascript flag # sub print_hier { my ($h_file,$js,$hier_tops_p) = @_; my ($out_file,$m,$imod); local (*HIER,*JSF); $out_file = $out_dir . $h_file; open(HIER,">$out_file") || die "Error: can't open file $out_file to write: $!\n"; push(@output_files,"$out_file"); if (defined(@{$hier_tops_p})) { # check that all the hierarchy tops (specified with -ht) exist foreach $module (@{$hier_tops_p}) { die "Error: Didn't 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't open file $js_file to write: $!\n"; # do the java script version first print_js_head(*JSF,join(" ",@{$hier_tops_p})); print_hier_body(*JSF,$hier_tops_p,1); print_js_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 "\n"; print $out "\n"; print_js_include( $out , $js_file) if ($js); print $out "hierarchy: $t\n"; print $out $style_sheet_link; print $out "\n"; print $out "