#!/usr/bin/perl -w # See copyright, etc in below POD section. ###################################################################### require 5.005; use FindBin qw($RealBin); # $RealBin 保存了当前程序所在的绝对地址 use lib "$RealBin/blib/arch"; use lib "$RealBin/blib/lib"; use lib "$RealBin"; use Getopt::Long; use IO::File; # 从IO::seekable, IO::handler 派生出来 use Pod::Usage; use Verilog::Netlist; use Verilog::Getopt; use strict; use vars qw ($Debug $VERSION); $VERSION = '3.305'; ###################################################################### # main $Debug = 0; # default 为 0 my $opt_output_filename = undef; # default 为 undef my @opt_files; autoflush STDOUT 1; # IO::handler 中的函数,自动flush buffer,不必等到运行完毕才打印消息 autoflush STDERR 1; # Option parsing # 初始化各个Option变量, coding style值得学习, 前缀用Opt_ my $Opt = new Verilog::Getopt(); my $Opt_Cells; my $Opt_Modules; my $Opt_ModFiles; my $Opt_InFiles; my $Opt_Missing = 1; # default 值,缺省文件丢失报错 my $Opt_Missing_Modules; my $Opt_TopModule; my $Opt_Xml; my $Opt_ResolveFiles; @ARGV = $Opt->parameter(@ARGV); # 先分析@ARGV 中verilog的常用选项(如-v,-y,+libext,+incdir,+define+等)调用相应的子程序,并从@ARGV中remove,剩下不能识别的选项。 Getopt::Long::config ("no_auto_abbrev"); # 不允许自动缩写 if (! GetOptions ( # 分析剩下的选项 "help" => /&usage, # 直接调用usage子程序 "debug" => /&debug, # 直接调用debug子程序 "o=s" => /$opt_output_filename, "cells!" => /$Opt_Cells, "module-files!" => /$Opt_ModFiles, "modules!" => /$Opt_Modules, "input-files!" => /$Opt_InFiles, "resolve-files!" => /$Opt_ResolveFiles, "sv!" => sub { shift; Verilog::Language::language_standard("1800-2009"); }, #直接调用匿名子程序, 第一个shift是移出-sv, 实际上是shift @_; @_的内容就是选项和选项值 "language=s" => sub { shift; Verilog::Language::language_standard(shift); }, #匿名子程序中用shift,非常有效,第一个是--language 第二个是选项值,譬如 systemverilog "missing!" => /$Opt_Missing, "missing-modules!" => /$Opt_Missing_Modules, "top-module=s" => /$Opt_TopModule, "version" => sub { print "Version $VERSION/n"; exit(0); }, "xml!" => /$Opt_Xml, "<>" => /¶meter, # 用来处理非option的其他参数 )) { die "%Error: Bad usage, try 'vhier --help'/n"; } #一种很好的格式,如果GetOptions 失败,那么退出打印信息。当然也可直接调用usage if (!@opt_files) { # 为空则退出 die "%Error: vhier: No input filenames specified./n"; } my $fh = IO::File->new; if ($opt_output_filename) { $fh->open(">$opt_output_filename") or die "%Error: $! $opt_output_filename/n"; # $! 代表出错信息 } else { $fh->open(">-") or die; # >- 表示输出到STDOUT } vhier($fh, @opt_files); #IO::File支持参数传递 exit (0); ###################################################################### sub usage { print "Version $VERSION/n"; pod2usage(-verbose=>2, -exitval => 2); exit (1); } sub debug { $Debug = 1; } sub parameter { my $param = shift; if ($param =~ /^--?/) { # 不合法选项,退出 die "%Error: vhier: Unknown parameter: $param/n"; } else { # 文件,放入列表中 push @opt_files, "$param"; # Must quote to convert Getopt to string, bug298 } } ###################################################################### #### Creation sub vhier { my $fh = shift; my @files = @_; my $nl = new Verilog::Netlist (options => $Opt, #建立新的netlist类, 引入Verilog::GetOpt对象,用以定位文件 keep_comments => 0, # 去掉所有的注释 use_vars => 0, # 不需要信号,变量,pin的连接信息 link_read_nonfatal => !$Opt_Missing, # 文件丢失不报错 ); if ($Opt_ResolveFiles) { $nl->read_libraries(); # 读进library以便link,由options给出搜寻路径 foreach my $file (@files) { if (my $resolved = $nl->resolve_filename ($file, "all")) { #在-y ,incdir中寻找相应的文件 print $fh $resolved, "/n"; } } return; } foreach my $file (@files) { print " Reading $file/n" if $Debug; $nl->read_file (filename=>$file); #读入所有的verilog 文件 } # Read in any sub-modules $nl->link(); # 和library link $nl->lint(); # Simplified as use_vars => 0 # 检查网表 $nl->exit_if_error(); if ($Opt_TopModule) { # 如果指定了Topmodule,则查找有没有,找到后设为top,并且递归得到top为根的树 my $topmod = $nl->find_module($Opt_TopModule) or die "%Error: --top-module '$Opt_TopModule' was not found./n"; $topmod->is_top(1); # We could just pass this to all of the following routines, # but each would need a different edit. Instead, just edit the netlist # to contain only the specified tree. my %marked_modules; _mod_mark_recurse($nl, $topmod, /%marked_modules); foreach my $mod ($nl->modules_sorted) { if (!$marked_modules{$mod->name}) { $mod->delete; } } } if ($Opt_Cells) { foreach my $mod ($nl->modules_sorted) { if ($mod->is_top) { show_hier ($fh, $mod, " ", ""); } } } if ($Opt_Modules) { show_module_names($nl, $fh); } if ($Opt_ModFiles) { show_mod_files($nl, $fh); } if ($Opt_InFiles) { foreach my $filename ($Opt->depend_files) { printf $fh +(" %s/n",$filename); } } if ($Opt_Missing_Modules) { show_missing_module_names($nl,$fh); } } sub show_module_names { my $nl = shift; my $fh = shift; foreach my $mod ($nl->modules_sorted) { print $fh " ",$mod->name,"/n"; } } sub show_missing_module_names { my $nl = shift; my $fh = shift; my %miss_names; foreach my $mod ($nl->modules) { foreach my $cell ($mod->cells_sorted) { if (!$cell->submod && !$cell->gateprim) { #定位cell对于的module,如果没有定义且不是gate,那么就是missing module $miss_names{$cell->submodname} = 1; } } } foreach my $key (sort (keys %miss_names)) { print $fh " $key/n"; } } sub show_mod_files { my $nl = shift; my $fh = shift; # We'll attach a level attribute to each module indicating its maximum depth foreach my $mod ($nl->modules, $nl->interfaces) { $mod->attributes("_vhier_level", 0); } # Recurse the tree and determine level foreach my $mod ($nl->modules, $nl->interfaces) { if ($mod->is_top) { _mod_files_recurse($mod, 1); } } # Make sort key based on numeric level my %keys; foreach my $mod ($nl->modules) { # No interfaces, it's --module-files implying modules only my $key = sprintf("%03d_%s", $mod->attributes("_vhier_level"), $mod->name); $keys{$key} = $mod; } my @files; my %files; # Uniquify the array foreach my $key (sort {$b cmp $a} (keys %keys)) { my $mod = $keys{$key}; my $filename = $mod->filename; if (!$files{$filename}) { $files{$filename} = 1; push @files, " "x($mod->attributes("_vhier_level")) . $filename; } } foreach my $filename (reverse @files) { print $fh " $filename/n"; } } sub _mod_mark_recurse { my $nl = shift; my $mod = shift; my $marked = shift; $marked->{$mod->name} = 1; foreach my $cell ($mod->cells_sorted) { if ($cell->submod) { _mod_mark_recurse ($nl, $cell->submod, $marked); } } } sub _mod_files_recurse { my $mod = shift; my $level = shift; if ($mod->attributes("_vhier_level") < $level) { $mod->attributes("_vhier_level", $level); } foreach my $cell ($mod->cells_sorted) { if ($cell->submod) { _mod_files_recurse ($cell->submod, $level+1); } } } sub show_hier { my $fh = shift; my $mod = shift; my $indent = shift; my $hier = shift; printf $fh ("%-38s %s/n", $indent."Module ".$mod->name,$hier) if $Debug; printf $fh "%s%s/n", $indent, $mod->name; foreach my $cell ($mod->cells_sorted) { if ($cell->submod) { show_hier ($fh, $cell->submod, $indent." ", $hier.".".$cell->name); } } } ###################################################################### ###################################################################### ###################################################################### __END__ =pod =head1 NAME vhier - Return all files in a verilog hierarchy using Verilog::Netlist =head1 SYNOPSIS vhier --help vhier [verilog_options] [-o filename] [verilog_files.v...] =head1 DESCRIPTION Vhier reads the Verilog files passed on the command line and outputs a tree of all of the filenames, modules, and cells referenced by that file. =head1 VERILOG ARGUMENTS The following arguments are compatible with GCC, VCS and most Verilog programs. =over 4 =item +define+I<var>+I<value> =item -DI<var>=I<value> Defines the given preprocessor symbol. =item -F I<file> Read the specified file, and act as if all text inside it was specified as command line parameters. Any relative paths are relative to the directory containing the specified file. Unlike some tools, -y, +incdir, and -v are treated as relative, but standalone filenames in the specified file ("foo.v") are not. Use use "-y ." to work around this. =item -f I<file> Read the specified file, and act as if all text inside it was specified as command line parameters. Any relative paths are relative to the current directory. =item +incdir+I<dir> =item -II<dir> Add the directory to the list of directories that should be searched for include directories or libraries. =item +libext+I<ext>+I<ext>... Specify the extensions that should be used for finding modules. If for example module I<x> is referenced, look in I<x>.I<ext>. =item -sv Specifies SystemVerilog language features should be enabled; equivalent to "--language 1800-2009". This option is selected by default, it exists for compatibility with other simulators. =item -y I<dir> Add the directory to the list of directories that should be searched for include directories or libraries. =back =head1 VHIER ARGUMENTS =over 4 =item --help Displays this message and program version and exits. =item --o I<file> Use the given filename for output instead of stdout. =item --cells Show the module name of all cells in top-down order. =item --input-files Show all input filenames. Copying all of these files should result in only those files needed to represent the entire design. =item --language <1364-1995|1364-2001|1364-2005|1800-2005|1800-2009> Set the language standard for the files. This determines which tokens are signals versus keywords, such as the ever-common "do" (data-out signal, versus a do-while loop keyword). =item --resolve-files Show resolved filenames passed on the command line. This will convert raw module and filenames without paths to include the library search path directory. Output filenames will be in the same order as passed on the command line. Unlike --input-files or --module-files, hierarchy is not traversed. =item --module-files Show all module filenames in top-down order. Child modules will always appear as low as possible, so that reversing the list will allow bottom-up processing of modules. Unlike input-files, header files are not included. =item --modules Show all module names. =item --nomissing Do not complain about references to missing modules. =item --missing-modules With --nomissing, show all modules that are not found. =item --top-module I<module> Start the report at the specified module name, ignoring all modules that are not the one specified with --top-module or below, and report an error if the --top-module specified does not exist. Without this option vhier will report all modules, starting at the module(s) that have no children below them. Note this option will not change the result of the --input-files list, as the files needed to parse any design are independent of which modules are used. =item --version Displays program version and exits. =back =head1 DISTRIBUTION Verilog-Perl is part of the L<http://www.veripool.org/> free Verilog EDA software tool suite. The latest version is available from CPAN and from L<http://www.veripool.org/verilog-perl>. Copyright 2005-2010 by Wilson Snyder. This package is free software; you can redistribute it and/or modify it under the terms of either the GNU Lesser General Public License Version 3 or the Perl Artistic License Version 2.0. =head1 AUTHORS Wilson Snyder <wsnyder@wsnyder.org> =head1 SEE ALSO L<Verilog-Perl>, L<Verilog::Getopt>, L<Verilog::Preproc>, L<Verilog::Netlist> =cut ######################################################################