## GetInfo.pm -- Database generator for Verilog design ## $Revision: #2 $$Date: 2005/10/10 $$Author: Rohit Mishra $ ## Written by: Rohit Mishra ############################################################ package Verilog::GetInfo; require 5.6.1; use vars qw( $VERSION ); use strict; use Carp; use FileHandle; $VERSION = '1.0.1'; ################################################################## ################################################################## # Package subroutines ################################################################## ################################################################## sub new { ################################################################## @_ >= 1 or croak 'usage: $verilog_handle = Verilog::GetInfo->new(\@command_line)'; my $class = ref($_[0]) || $_[0]; my $junk = shift(@_); my $command_line = shift(@_); my $self = {}; my $command = undef; my $fh = undef; # Database Hashes $self->{'DATABASE'} = { }; $self->{'HIERARCHY'} = { }; $self->{'Handle'} = undef; @{$self->{'NULL'}} = ('None'); # Global Variables $self->{'GLOBAL'} = { }; $self->{'GLOBAL'}->{'TRUE'} = 1; $self->{'GLOBAL'}->{'FALSE'} = 0; $self->{'GLOBAL'}->{'flag'} = 0; $self->{'GLOBAL'}->{'flag1'} = 0; $self->{'GLOBAL'}->{'level'} = 0; $self->{'GLOBAL'}->{'connec_flag'} = 0; @{$self->{'GLOBAL'}->{'indent'}} = ("\t"); # bless it as a Parser object bless $self, $class; $command = $self->Parse_Command_Line( $command_line ); if( ! defined $self->{'DATABASE'}->{'LOGFILE'} ){ $self->{'DATABASE'}->{'LOGFILE'} = "verilog-shell_$VERSION\.log"; } open( LOG, ">$self->{'DATABASE'}->{'LOGFILE'}" ) || die("$!"); $self->{Handle} = *LOG; select($self->{Handle}); $| = 1; select(STDOUT); $| = 1; $self->Message($self->{Handle},"=" x 72); $self->Message($self->{Handle},"Command line: $command"); $self->Message($self->{Handle},"=" x 72); $self->Read_Verilog_Files; return $self; } ################################################################## sub Parse_Command_Line(){ ################################################################## @_ == 2 or croak 'usage: $files = $verilog_handle->Parse_Command_Line( \@ARGV )'; my $self = shift(@_); my $command_line = shift(@_); my $command = "$0\n"; my $arguments; my $macro; my $value; my $line; my $directory; my $fh = FileHandle->new(); while( $arguments = shift( @$command_line ) ){ chomp( $arguments ); $arguments =~ s/\s+//g; if( $arguments =~ m|\+define\+([A-Za-z0-9_]+)="(.*?)"| ){ $macro = $1; $value = $2; $self->{'DATABASE'}->{'DEFINES'}->{$macro} = $value; $command .= " $arguments\n"; } elsif( $arguments =~ m|\+define\+([A-Za-z0-9_]+)| ){ $macro = $1; $self->{'DATABASE'}->{'DEFINES'}->{$macro} = "junk"; $command .= " $arguments\n"; } elsif( $arguments =~ m|\+incdir\+(.*)| ){ $directory = $1; push( @{$self->{'DATABASE'}->{'INCDIR'}}, $directory ); $command .= " $arguments\n"; } elsif( $arguments =~ m|\+([A-Za-z0-9_]+)| ){ $macro = $1; $self->{'DATABASE'}->{'PLUSARGS'}->{$macro} = "junk"; $command .= " $arguments\n"; } elsif( $arguments =~ m|\-f| ){ $arguments = shift( @$command_line ); push( @{$self->{'DATABASE'}->{'FILES'}}, $arguments ); $command .= " -f $arguments\n"; } elsif( $arguments =~ m|\-v| ){ $arguments = shift( @$command_line ); push( @{$self->{'DATABASE'}->{'LIBFILES'}}, $arguments ); $command .= " -v $arguments\n"; } elsif( $arguments =~ m|\-y| ){ $arguments = shift( @$command_line ); push( @{$self->{'DATABASE'}->{'LIBDIRS'}}, $arguments ); $command .= " -y $arguments\n"; } elsif( $arguments =~ m|\-l| ){ $arguments = shift( @$command_line ); $self->{'DATABASE'}->{'LOGFILE'} = $arguments; $command .= " -l $arguments\n"; } else { push( @{$self->{'DATABASE'}->{'FILES'}}, $arguments ); $command .= " $arguments\n"; next; } } return $command; } ################################################################## sub Read_Verilog_Files(){ ################################################################## @_ == 1 or croak 'usage: $verilog_handle->Read_Verilog_Files'; my $self = shift(@_); my $file; my $top; my @files = @{$self->{'DATABASE'}->{'FILES'}}; foreach $file ( @files ){ my @data = $self->Verilog_To_Text( $file ); $self->Read_Text( $file, @data ); } $self->Generate_Module_Database; $top = $self->Get_Toplevel; foreach my $toplevel ( @$top ){ $self->{'HIERARCHY'}->{$toplevel} = $self->Hierarchy( $toplevel ); } $self->{'GLOBAL'}->{'flag'} = 0; } ################################################################## sub Verilog_To_Text(){ ################################################################## @_ == 2 or croak 'usage: $verilog_handle->Verilog_To_Text( $filename )'; my $self = shift( @_ ); my $file = shift( @_ ); my $line; my @data = (); my $fh = FileHandle->new(); if( $fh->open( $file ) ){ while( $line = $fh->getline() ){ chomp($line); if( ( $line =~ m|^\s*//| ) || ( $line =~ m|^\s*$| ) ){ next; } elsif( $line =~ m|(include\s+"\s*[A-Za-z0-9_/\.]+\s*")| ){ push( @data, "`$1" ); } elsif( $line =~ m|(.*?)//| ){ push( @data, "$1" ); } elsif( ( $line =~ m|^\s*/\*| ) && ( $line =~ m|\*/\s*$| ) ){ next; } elsif( ( $line =~ m|^\s*/\*| ) && ( $line !~ m|\*/\s*$| ) ){ while( $line = $fh->getline() ){ if( $line =~ m|\*/\s*$| ){ last; } } } elsif( $line =~ m|(.*?)/\*(.*?)\*/(.*?)| ){ push( @data, "$1"."$3" ); } else { push( @data, $line ); } } } else { $self->Error( "Open failed: $file" ); exit("1"); } return( @data ); } ################################################################## sub Read_Text(){ ################################################################## @_ >= 2 or croak 'usage: $verilog_handle->Read_Text( $file,@data )'; my $self = shift( @_ ); my $file = shift( @_ ); my @data = @_; my $line; my @data1 = (); my $level = 0; my $tag = 0; my $tag1 = 0; my %ifdef = (); my %else = (); my $i; my $line_number = 0; my $macro; my $value; my $module = undef; my @expand = (); if( $self->{'GLOBAL'}->{'level'} == 0 ){ $self->Echo($self->{Handle}, "Reading file: $file" ); } else { $self->Echo($self->{Handle}, "Reading level $self->{'GLOBAL'}->{'level'} include file: $file" ); } while( $line = shift( @data )){ $line_number++; # define ifdefs, elses and endif tags if( $line =~ m|\s*ifdef\s+(\S+)| ){ $level++; if( defined $self->{'DATABASE'}->{'DEFINES'}->{$1} ){ $ifdef{$level} = $self->{'GLOBAL'}->{'TRUE'}; $else{$level} = $self->{'GLOBAL'}->{'FALSE'}; } else { $ifdef{$level} = $self->{'GLOBAL'}->{'FALSE'}; $else{$level} = $self->{'GLOBAL'}->{'FALSE'}; } next; } if( $line =~ m|\s*else| ){ $else{$level} = $self->{'GLOBAL'}->{'TRUE'}; next; } if( $line =~ m|\s*endif| ){ undef $ifdef{$level}; if( $else{$level} == $self->{'GLOBAL'}->{'TRUE'} ){ undef $else{$level}; } $level--; next; } # ifdef conditions for which it should not move fwd if( defined $ifdef{$level} && defined $else{$level} ){ if( $ifdef{$level} == $self->{'GLOBAL'}->{'FALSE'} && $else{$level} == $self->{'GLOBAL'}->{'FALSE'} ){ next; } elsif( $ifdef{$level} == $self->{'GLOBAL'}->{'TRUE'} && $else{$level} == $self->{'GLOBAL'}->{'TRUE'} ){ next; } elsif( $ifdef{$level} == $self->{'GLOBAL'}->{'FALSE'} && $else{$level} == $self->{'GLOBAL'}->{'TRUE'} ){ # check for previous ifdefs foreach $i ( keys %ifdef ){ if( defined $ifdef{$i} && defined $else{$i} ){ if( $i < $level && $ifdef{$i} == $self->{'GLOBAL'}->{'FALSE'} && $else{$i} == $self->{'GLOBAL'}->{'FALSE'} ){ $tag = 1; last; } elsif( $i < $level && $ifdef{$i} == $self->{'GLOBAL'}->{'TRUE'} && $else{$i} == $self->{'GLOBAL'}->{'TRUE'} ){ $tag = 1; last; } } } if( $tag == 1 ){ $tag = 0; next; } } elsif( $ifdef{$level} == $self->{'GLOBAL'}->{'TRUE'} && $else{$level} == $self->{'GLOBAL'}->{'FALSE'} ){ # check for previous ifdefs foreach $i ( keys %ifdef ){ if( defined $ifdef{$i} && defined $else{$i} ){ if( $i < $level && $ifdef{$i} == $self->{'GLOBAL'}->{'FALSE'} && $else{$i} == $self->{'GLOBAL'}->{'FALSE'} ){ $tag = 1; last; } elsif( $i < $level && $ifdef{$i} == $self->{'GLOBAL'}->{'TRUE'} && $else{$i} == $self->{'GLOBAL'}->{'TRUE'} ){ $tag = 1; last; } } } if( $tag == 1 ){ $tag = 0; next; } } } # plusargs conditions for which it should not move fwd. if( ($line =~ m|\$test\$plusargs\s*\(\s*\"\s*([A-Za-z0-9_]+)\s*"\s*\)|g) ){ # TEMP rohit&& ($line =~ m|\bbegin\b|g) ){ $macro = $1; if( !defined $self->{'DATABASE'}->{'PLUSARGS'}->{$macro} ){ $self->Warning( $self->{Handle},"Plusarg ($macro) not defined. Skipping.. "); while( $line = shift( @data ) ){ if( $line =~ m|\bend\b| ){ last; } else { next; } } } else { $self->Warning( $self->{Handle},"Plusarg ($macro) defined."); } } elsif( $line =~ m|\$test\$plusargs\s*\(\s*\"\s*([A-Za-z0-9_]+)\s*"\s*\)| ){ $macro = $1; if( !defined $self->{'DATABASE'}->{'PLUSARGS'}->{$macro} ){ $self->Warning( $self->{Handle},"Plusarg ($macro) not defined. Skipping.. "); $line = shift( @data ); if( $line =~ m|\bbegin\b| ){ while( $line = shift( @data ) ){ if( $line =~ m|\bend\b| ){ last; } else { next; } } } else { unshift( @data, $line ); next; } } else { $self->Warning( $self->{Handle},"Plusarg ($macro) defined."); } } if( $line =~ m|\s*define\s+([a-zA-Z0-9_]+)\s+"([\s\S]+)"| ){ $macro = $1; $value = $2; @expand = ( $value =~ m|([A-Za-z0-9_]+)|g ); while( @expand ){ foreach ( @expand ){ if( defined $self->{'DATABASE'}->{'DEFINES'}->{$_} ){ $value =~ s/\`$_/$self->{'DATABASE'}->{'DEFINES'}->{$_}/g; } else { $value =~ s/\`$_//g; } } @expand = ( $value =~ m|([A-Za-z0-9_]+)|g ); } $value =~ s/[\s\{\}\"]+//g; $value = join( "", split( /\,/, $value ) ); if( defined $self->{'DATABASE'}->{'DEFINES'}->{$macro} ){ $self->Warning( $self->{Handle},"Text macro ($macro) re-defined. Replaced with new definition.\n$file: $line_number"); } $self->{'DATABASE'}->{'DEFINES'}->{$macro} = $value; } elsif( $line =~ m|\s*`define\s+([a-zA-Z0-9_]+)\s+(\S+)| ){ $macro = $1; $value = $2; @expand = ( $value =~ m|\`([A-Za-z0-9_]+)|g ); while( @expand ){ foreach ( @expand ){ if( defined $self->{'DATABASE'}->{'DEFINES'}->{$_} ){ $value =~ s/\`$_/$self->{'DATABASE'}->{'DEFINES'}->{$_}/g; } else { $value =~ s/\`$_//g; } } @expand = ( $value =~ m|\`([A-Za-z0-9_]+)|g ); } $value =~ s/[\s\{\}\"]+//g; $value = join( "", split( /\,/, $value ) ); if( defined $self->{'DATABASE'}->{'DEFINES'}->{$macro} ){ $self->Warning( $self->{Handle},"Text macro ($macro) re-defined. Replaced with new definition.\n$file: $line_number"); } $self->{'DATABASE'}->{'DEFINES'}->{$macro} = $value; } elsif( $line =~ m|\s*`define\s+([a-zA-Z0-9_]+)| ){ $macro = $1; if( defined $self->{'DATABASE'}->{'DEFINES'}->{$macro} ){ $self->Warning( $self->{Handle},"Text macro ($macro) re-defined. Replaced with new definition.\n$file: $line_number"); } $self->{'DATABASE'}->{'DEFINES'}->{$macro} = "junk"; } elsif( $line =~ m|\s*`include(.*)|g ){ $value = $1; @expand = ( $value =~ m|`([A-Za-z0-9_]+)|g ); while( @expand ){ foreach ( @expand ){ if( defined $self->{'DATABASE'}->{'DEFINES'}->{$_} ){ $value =~ s/\`$_/$self->{'DATABASE'}->{'DEFINES'}->{$_}/g; } else { $value =~ s/\`$_//g; } } @expand = ( $value =~ m|`([A-Za-z0-9_]+)|g ); } $value =~ s/[\s\{\}\"]+//g; $value = join( "", split( /\,/, $value ) ); push( @data1, "`include \"$value\"" ); } elsif( $line =~ m|`[A-Za-z0-9_]+|g ){ # Temporarily removed ` include expansions #@expand = ( $line =~ m|`([A-Za-z0-9_]+)|g ); #while( @expand ){ # foreach ( @expand ){ # if( defined $self->{'DATABASE'}->{'DEFINES'}->{$_} ){ # $line =~ s/\`$_/$self->{'DATABASE'}->{'DEFINES'}->{$_}/g; # } else { # $line =~ s/\`$_//g; # } # } # @expand = ( $line =~ m|([A-Za-z0-9_]+)|g ); #} #$line =~ s/[\s\{\}\"]+//g; #$line = join( "", split( /\,/, $line ) ); #push( @data1, "\"$line\"" ); } else { push( @data1, $line ); next; } } $line_number = 0; while( $line = shift( @data1 )){ if( $line =~ m|\s*include\s+"(\S+)"| ){ my $incl_file = $1; $self->{'GLOBAL'}->{'level'}++; if( ! -f $incl_file ){ foreach my $tmpvar ( @{$self->{'DATABASE'}->{'INCDIR'}} ){ if( -f "$tmpvar/$incl_file" ){ $incl_file = "$tmpvar/$incl_file"; last; } } } push( @{$self->{'DATABASE'}->{'FILES'}},$incl_file); my @data1 = $self->Verilog_To_Text( $incl_file ); $self->Read_Text( $incl_file, @data1 ); $self->{'GLOBAL'}->{'level'}--; } elsif( $line =~ m|^\s*\-y\s+(\S+)| ){ my $libdir = $1; push( @{$self->{'DATABASE'}->{'LIBDIRS'}}, $libdir ); $self->Cache_Libdir( $libdir ); } elsif( $line =~ m|^\s*\-v\s+(\S+)| ){ my $libfile = $1; push( @{$self->{'DATABASE'}->{'LIBFILES'}}, $libfile ); $self->Cache_Libfile( $libfile ); } elsif( $line =~ m|\+define\+(\S+)| ){ $macro = $1; $self->{'DATABASE'}->{'DEFINES'}->{$macro} = "junk"; } elsif( $line =~ m|\+libext\+(\S+)| ){ my $libext = $1; @{$self->{'DATABASE'}->{'LIBEXT'}} = split(/\+/, $libext ); } elsif( $line =~ m|^\s*\+([A-Za-z0-9_]+)| ){ $macro = $1; $self->{'DATABASE'}->{'PLUSARGS'}->{$macro} = "junk"; } elsif( -f $line ){ push( @{$self->{'DATABASE'}->{'FILES'}},$line); my @data1 = $self->Verilog_To_Text( $line ); $self->Read_Text( $line, @data1 ); } else { push( @{$self->{'DATABASE'}->{'FULLVIEW'}}, $line ); $self->{'DATABASE'}->{'FULL'}->{'CONTENTS'} .= "$line\n"; next; } } return; } ################################################################## sub Cache_Libdir(){ ################################################################## @_ == 2 or croak 'usage: $verilog_handle->Cache_Libdir( $libdir )'; my $self = shift(@_); my $libdir = shift(@_); my $line; my $libext; my $file; my @data = (); $self->Message($self->{Handle},"Scanning library directory: $libdir\n"); opendir( DIR, $libdir ) || $self->Warning( $self->{Handle},"Could not open library directory:\n$libdir\n"); while( $file = readdir( DIR ) ){ foreach $libext ( @{$self->{'DATABASE'}->{'LIBEXT'}} ){ $libext =~ s/\s+//g; if( $file =~ m|$libext$| ){ @data = $self->Verilog_To_Text( "$libdir/$file" ); while( $line = shift( @data )){ $self->{'DATABASE'}->{'LIBRARY'} .= "$line\n"; } } else { next; } } } closedir( DIR ); } ################################################################## sub Cache_Libfile(){ ################################################################## @_ == 2 or croak 'usage: $verilog_handle->Cache_Libfile( $libfile )'; my $self = shift(@_); my $libfile = shift(@_); my $line; my @data = $self->Verilog_To_Text( $libfile ); $self->Message($self->{Handle},"Scanning library file: $libfile\n"); while( $line = shift( @data )){ $self->{'DATABASE'}->{'LIBRARY_FILE'} .= "$line\n"; } } ################################################################## sub Generate_Module_Database(){ ################################################################## @_ == 1 or croak 'usage: $verilog_handle->Generate_Module_Database'; my $self = shift(@_); my @database = @{$self->{'DATABASE'}->{'FULLVIEW'}}; my $line; my $module; my $i = 0; while( $line = shift( @database ) ){ if ( $line =~ /\s*module\s+([A-Za-z0-9_]+)/ ){ $module = $1; $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'} .= "$line\n"; push( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'ARRAY'}}, $line ); while( $line = shift( @database )){ $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'} .= "$line\n"; push( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'ARRAY'}}, $line ); if( $line =~ /\s*endmodule/ ){ last; } else { next; } } unshift( @database, $line ); $i++; } } $self->{'DATABASE'}->{'MODCNT'} = $i; } ################################################################## sub Get_Inputs(){ ################################################################## @_ == 2 or croak 'usage: @inputs = $verilog_handle->Get_Inputs( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my @inputs = (); if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; if( $data =~ m|module$module;| ){ return( @{$self->{'NULL'}} ); } my @data = split(/;/,$data ); while( $line = shift( @data )){ if( $line =~ /^input(.*)/ ){ $line = $1; if( $line =~ /\,/ ){ push( @inputs, split(/,/,$line )); } else { push( @inputs, $line ); } } } @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'INPUTS'}} = @inputs; return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'INPUTS'}} ); } ################################################################## sub Get_Outputs(){ ################################################################## @_ == 2 or croak 'usage: @outputs = $verilog_handle->Get_Outputs( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my @outputs = (); if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; if( $data =~ m|module$module;| ){ return( @{$self->{'NULL'}} ); } my @data = split(/;/,$data ); while( $line = shift( @data )){ if( $line =~ /^output(.*)/ ){ $line = $1; if( $line =~ /\,/ ){ push( @outputs, split(/,/,$line )); } else { push( @outputs, $line ); } } } @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'OUTPUTS'}} = @outputs; return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'OUTPUTS'}} ); } ################################################################## sub Get_Ports(){ ################################################################## @_ == 2 or croak 'usage: @ports = $verilog_handle->Get_Ports( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my $portlist; if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; if( $data =~ m|module$module;| ){ return( @{$self->{'NULL'}} ); } if( $data =~ m|module$module\((.*?)\);| ){ $portlist = $1; } my @ports = split(/,/, $portlist ); @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'PORTS'}} = @ports; return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'PORTS'}} ); } ################################################################## sub GetLoads(){ ################################################################## @_ == 2 or croak 'usage: @loads = $verilog_handle->GetLoads( $signal )'; my $self = shift(@_); my $signal = shift(@_); my @loads = (); my $line = undef; } ################################################################## sub Get_Regs(){ ################################################################## @_ == 2 or croak 'usage: @regs = $verilog_handle->Get_Regs( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my @regs = (); if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; my @data = split(/;/,$data ); while( $line = shift( @data )){ if( $line =~ /^reg(.*)/ ){ $line = $1; if( $line =~ /\,/ ){ push( @regs, split(/,/,$line )); } else { push( @regs, $line ); } } } @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'REGS'}} = @regs; if( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'REGS'}} ){ return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'REGS'}} ); } else { return( @{$self->{'NULL'}} ); } } ################################################################## sub Get_Wires(){ ################################################################## @_ == 2 or croak 'usage: @wires = $verilog_handle->Get_Wires( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my @wires = (); if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; my @data = split(/;/,$data ); while( $line = shift( @data )){ if( $line =~ /^wire(.*)/ ){ $line = $1; if( $line =~ /\,/ ){ push( @wires, split(/,/,$line )); } else { push( @wires, $line ); } } } @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'WIRES'}} = @wires; if( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'WIRES'}} ){ return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'WIRES'}} ); } else { return( @{$self->{'NULL'}} ); } } ################################################################## sub Get_Inouts(){ ################################################################## @_ == 2 or croak 'usage: @inouts = $verilog_handle->Get_Inouts( $module )'; my $self = shift(@_); my $module = shift(@_); my $line; my @inouts = (); if( !defined $self->{'DATABASE'}->{'MODULES'}->{$module} ){ $self->Error("Module ($module) not present in the design.\n"); return; } my $data = $self->{'DATABASE'}->{'MODULES'}->{$module}->{'CONTENTS'}; $data =~ s/\n//g; $data =~ s/\s+//g; if( $data =~ m|module$module;| ){ return( @{$self->{'NULL'}} ); } my @data = split(/;/,$data ); while( $line = shift( @data )){ if( $line =~ /^inout(.*)/ ){ $line = $1; if( $line =~ /\,/ ){ push( @inouts, split(/,/,$line )); } else { push( @inouts, $line ); } } } @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'INOUTS'}} = @inouts; return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'INOUTS'}} ); } ################################################################## sub Get_Toplevel(){ ################################################################## @_ == 1 or croak 'usage: $toplevel = $verilog_handle->Get_Toplevel'; my $self = shift(@_); my $module; my @toplevel = (); my @top = (); my %found = (); my $data = $self->{'DATABASE'}->{'FULL'}->{'CONTENTS'}; $data =~ s/\n+/ /g; %found = ( $data =~ m|[^\.]([A-Za-z0-9_]+)\s+([\#\(\)A-Za-z0-9_]+)\s*\(|g ); foreach $module ( sort keys %{$self->{'DATABASE'}->{'MODULES'}} ){ if( !defined $found{$module} ){ push( @toplevel, $module ); push( @top, "$module\n" ); } } $self->Message($self->{Handle}, "Highest level modules:\n @top" ); $self->{'DATABASE'}->{'TOPLEVEL'} = \@toplevel; return( $self->{'DATABASE'}->{'TOPLEVEL'} ); } ################################################################## sub Hierarchy(){ ################################################################## @_ == 2 or croak 'usage: $verilog_handle->Hierarchy( $top )'; my $self = shift(@_); my $toplevel = shift(@_); my $module; my $data; my $hierarchy = { }; my @found = (); my @mod_inst = (); if( ! defined $self->{'DATABASE'}->{'MODULES'}->{$toplevel} ){ $self->Error("Module ($toplevel) is not present in the design.\n"); return undef; } if( $self->{'GLOBAL'}->{'flag'} == 0 ){ $self->Message($self->{Handle},"\tBuilding module hierarchy hashes ..\n"); $self->{'GLOBAL'}->{'flag'} = 1; } $data = $self->{'DATABASE'}->{'MODULES'}->{$toplevel}->{'CONTENTS'}; $data =~ s/\n+/ /g; @found = ( $data =~ m|([A-Za-z0-9_]+\s+[A-Za-z0-9_]+)\s*\(\s*[\.\\A-Za-z0-9_\[\]]+\s*\(|g ); foreach $module ( @found ){ @mod_inst = split( /\s+/, $module ); $mod_inst[0] =~ s/\s+//g; $mod_inst[1] =~ s/\s+//g; if( defined $self->{'DATABASE'}->{'MODULES'}->{$mod_inst[0]} ){ $self->{'DATABASE'}->{'INSTANCES'}->{$mod_inst[1]} = $mod_inst[0]; $hierarchy->{$mod_inst[1]} = $self->Hierarchy( $mod_inst[0] ); } else { push( @{$self->{'DATABASE'}->{'MODULES'}->{'NODEFINITION'}}, $mod_inst[0] ); next; } } return( $hierarchy ); } ################################################################## sub Print_Hierarchy(){ ################################################################## @_ == 2 or croak 'usage: $verilog_handle->Print_Hierarchy( $hierarchy )'; my $self = shift(@_); my $hierarchy = shift(@_); my $module; if( ! defined $hierarchy ){ $self->Error("No hierarchy to display.\n"); return undef; } foreach $module ( keys %{$hierarchy} ){ $self->Message($self->{Handle},"@{$self->{'GLOBAL'}->{'indent'}} $module\n"); push( @{$self->{'GLOBAL'}->{'indent'}},"\t"); $self->Print_Hierarchy( $hierarchy->{$module} ); pop( @{$self->{'GLOBAL'}->{'indent'}}); } return; } ################################################################## sub Get_Define(){ ################################################################## @_ >= 1 or croak 'usage: $verilog_handle->Get_Define or $verilog_handle->Get_Define( $define )'; my $self = shift(@_); my $define; if( @_ ){ $define = shift(@_); if( defined $self->{'DATABASE'}->{'DEFINES'}->{$define} ){ if( $self->{'DATABASE'}->{'DEFINES'}->{$define} eq "junk" ){ $self->Message($self->{Handle},"Text Macro $define set."); return; } else { $self->Message($self->{Handle},"Text Macro $define set to $self->{'DATABASE'}->{'DEFINES'}->{$define}\n"); return; } } else { $self->Message($self->{Handle},"Text Macro $define not defined.\n"); return; } } else { foreach $define ( sort keys %{$self->{'DATABASE'}->{'DEFINES'}} ){ if( $self->{'DATABASE'}->{'DEFINES'}->{$define} eq "junk" ){ $self->Message($self->{Handle},"Text macro $define set.\n"); } else { $self->Message($self->{Handle},"Text macro $define set to $self->{'DATABASE'}->{'DEFINES'}->{$define}\n"); } } return; } return; } ################################################################## sub Get_Files{ ################################################################## @_ == 1 or croak 'usage: @verilog_files = $verilog_handle->Get_Files'; if( @_ ){ return ( @{$_[0]->{'DATABASE'}->{'FILES'}} ); } else { return undef; } } ################################################################## sub Get_Module_Count{ ################################################################## @_ == 1 or croak 'usage: $no_of_modules = $verilog_handle->Get_Module_Count'; if( @_ ){ return ( $_[0]->{'DATABASE'}->{'MODCNT'}); } else { return undef; } } ################################################################## sub Get_Modules{ ################################################################## @_ == 1 or croak 'usage: @modules = $verilog_handle->Get_Modules'; my $self = $_[0]; my @modules = (); if( @_ ){ foreach ( keys ( %{$self->{'DATABASE'}->{'MODULES'}} ) ){ push( @modules,$_); } return( @modules ); } else { return undef; } } ################################################################## sub Get_Full_Design{ ################################################################## @_ == 1 or croak 'usage: @design = $verilog_handle->Get_Full_Design'; if( @_ ){ return( @{$_[0]->{'DATABASE'}->{'FULLVIEW'}} ); } else { return undef; } } ################################################################## sub Get_Module_Contents(){ ################################################################## @_ == 2 or croak 'usage: $module_content = $verilog_handle->Get_Module_Contents( $module )'; my $self = shift(@_); my $module = shift(@_); if( defined $module ){ return( @{$self->{'DATABASE'}->{'MODULES'}->{$module}->{'ARRAY'}} ); } else { return undef; } } ################################################################## sub Message(){ ################################################################## @_ <= 3 or croak 'usage: $verilog_handle->Message( ); or $verilog_handle->Message( , );'; my $self = shift; my $fh = undef; my $msg = undef; if( @_ == 2 ){ $fh = shift; $msg = shift; } else { $msg = shift; } $msg =~ s/(.{72,72})/$1\n/g; if( defined $fh ){ print $fh "$msg\n"; print "$msg\n"; } else { print "$msg\n"; } } ################################################################## sub Warning(){ ################################################################## @_ <= 3 or croak 'usage: $verilog_handle->Warning( ); or $verilog_handle->Warning( , );'; my $self = shift; my $fh = undef; my $msg = undef; if( @_ == 2 ){ $fh = shift; $msg = shift; } else { $msg = shift; } $msg =~ s|\n+|\n |g; $msg =~ s/(.{72,72})/$1\n /g; if( defined $fh ){ print $fh "Warning! $msg\n"; print "Warning! $msg\n"; } else { print "Warning! $msg\n"; } } ################################################################## sub Echo(){ ################################################################## @_ <= 3 or croak 'usage: $verilog_handle->Echo( ); or $verilog_handle->Echo( , );'; my $self = shift; my $fh = undef; my $msg = undef; if( @_ == 2 ){ $fh = shift; $msg = shift; } else { $msg = shift; } if( defined $fh ){ print $fh $msg,"\n"; print $msg,"\n"; } else { print $msg,"\n"; } } ################################################################## sub Error(){ ################################################################## @_ <= 3 or croak 'usage: $verilog_handle->Error( ); or $verilog_handle->Error( , );'; my $self = shift; my $fh = undef; my $msg = undef; if( @_ == 2 ){ $fh = shift; $msg = shift; } else { $msg = shift; } $msg =~ s/(.{72,72})/$1\nError! /g; if( defined $fh ){ print $fh "-" x 80,"\n"; print $fh "Error! $msg\n"; print $fh "-" x 80,"\n"; } else { print "-" x 80,"\n"; print "Error! $msg\n"; print "-" x 80,"\n"; } } 1; __END__ =head1 NAME GetInfo.pm - Get information on a verilog HDL design =head1 SYNOPSIS Verilog::GetInfo.pm version 1.0.1 =head1 STATUS GetInfo.pm is in its beta version. Report all bugs to the author. =head1 DESCRIPTION Verilog::Getinfo.pm is a complete verilog HDL language parser. $handle = Verilog::GetInfo->new(\@command_line)'; Above command will return a handle to the new verilog design database. @command_line is the verilog command line options understood by GetInfo. Most of the standard (IEEE 1364) command line options are supported. Some of the options which are supported are: -v, -y, + ( plusargs ), +define+, -l etc. GetInfo understands most of the in-the-file options of Verilog HDL language: `ifdef...`else...`endif `include "filename.v" `define macro value `define macro Some of the functions which return information about the design are: =item Get_Inputs( module_name ) - Returns list of input ports of the module. It will return an array, with all the inputs along with their bus widths. =item Get_Outputs( module_name ) - Returns list of output ports of the module. An array with all the output ports listed along with their bus widths. =item Get_Ports( module_name ) - Returns list of ports of a module. =item Get_Regs( module_name ) - Returns list of registers defined in a module. =item Get_Wires( module_name) - Returns list of wires defined in a module. =item Get_Inouts( module_name) - Returns list of inout ports in a module. =item Get_Toplevel() - Returns list of module names, which are not instantiated inside any other modules. =item Hierarchy( module_name ) - The module_name can be any module in the design. Returns a reference to a hash containing the hierarchy information of the module. It will report all the sub-modules below the module provided as the input to the function. =item Print_Hierarchy( module_name ) - This function calls the function Hierarchy(), and prints the hierarchy in the nice human readable form. =item Get_Define() - If an input is given to this function it will check, whether it is defined. If it is defined, it will check whether its a macro definition and return the value of the macro. If no input is given, it will return all the defines that have been defined in the design, with their values. =item Get_Files() - This function returns all the design files read into the database. =item Get_Module_Count() - This function returns the total number of modules in the design. =item Get_Modules() - This functions lists all the modules in the design. =item Get_Full_Design() - This function returns a full flat netlist in an array. Note: The array will be huge. =item Get_Module_Contents() - This function returns the contents ( without comments ) of a module provided as an input to this function. =item Message(), Warning(), Echo(), Error() - Display functions. Will display lot of information when parsing the design files. =head1 BUGS No known bugs. Plz report all the bugs to the author ( see AUTHOR section below ) =head1 AUTHOR Rohit Mishra EFE =head1 COPYRIGHT Copyright (c) 2005 Rohit Mishra . All rights reserved This program is a free software; you can redistribute it and/or modify it under the same terms as Perl itself. =cut