###############################################################################
|
###############################################################################
|
#
|
#
|
# File: rvp.pm
|
# File: rvp.pm
|
# RCS: $Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $
|
# RCS: $Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $
|
# Description: The Rough Verilog Parser Perl Module
|
# Description: The Rough Verilog Parser Perl Module
|
# Author: Costas Calamvokis
|
# Author: Costas Calamvokis
|
# Created: Fri Apr 10 16:59:30 1998
|
# Created: Fri Apr 10 16:59:30 1998
|
# Modified: Thu Jan 12 10:45:27 2006
|
# Modified: Thu Jan 12 10:45:27 2006
|
# Language: Perl
|
# Language: Perl
|
#
|
#
|
# Copyright 1998-2006 Costas Calamvokis
|
# Copyright 1998-2006 Costas Calamvokis
|
#
|
#
|
# This file nay be copied, modified and distributed only in accordance
|
# This file nay be copied, modified and distributed only in accordance
|
# with the terms of the limited licence contained in the accompanying
|
# with the terms of the limited licence contained in the accompanying
|
# file LICENCE.TXT.
|
# file LICENCE.TXT.
|
#
|
#
|
###############################################################################
|
###############################################################################
|
#
|
#
|
|
|
=head1 rvp - Rough Verilog Parser Perl Module
|
=head1 rvp - Rough Verilog Parser Perl Module
|
|
|
The basic idea is that first you call read_verilog will a list of all of your
|
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
|
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
|
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.
|
to the various get_ function to get information about the verilog design.
|
|
|
For Example:
|
For Example:
|
|
|
#!/usr/bin/perl -w
|
#!/usr/bin/perl -w
|
use rvp; # use the rough verilog parser
|
use rvp; # use the rough verilog parser
|
|
|
# Read in all the files specified on the command line
|
# Read in all the files specified on the command line
|
$vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
|
$vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
|
|
|
# Print out all the modules found
|
# Print out all the modules found
|
foreach $module ($vdata->get_modules()) { print "$module\n"; }
|
foreach $module ($vdata->get_modules()) { print "$module\n"; }
|
|
|
Unless you are doing something very strange, you can probably ignore all
|
Unless you are doing something very strange, you can probably ignore all
|
of the functions that have the words 'context' or 'anchors' in them!
|
of the functions that have the words 'context' or 'anchors' in them!
|
|
|
=cut
|
=cut
|
|
|
package rvp;
|
package rvp;
|
|
|
#use strict;
|
#use strict;
|
#use Tie::IxHash;
|
#use Tie::IxHash;
|
|
|
use File::Basename;
|
use File::Basename;
|
|
|
use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp
|
use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp
|
@verilog_compiler_keywords
|
@verilog_compiler_keywords
|
@verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp
|
@verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp
|
$quiet $debug $VID $HVID $VNUM
|
$quiet $debug $VID $HVID $VNUM
|
$takenArcs
|
$takenArcs
|
$baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
|
$baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
|
$version $VERSION);
|
$version $VERSION);
|
|
|
BEGIN {
|
BEGIN {
|
# $VERSION is used by 'use', but keep $version for backwards compatibility
|
# $VERSION is used by 'use', but keep $version for backwards compatibility
|
$version = '$Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $'; #'
|
$version = '$Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $'; #'
|
$version =~ s/^\S+ \S+ (\S+) .*$/$1/;
|
$version =~ s/^\S+ \S+ (\S+) .*$/$1/;
|
$VERSION = $version;
|
$VERSION = $version;
|
|
|
@verilog_signal_keywords = qw(input output inout
|
@verilog_signal_keywords = qw(input output inout
|
wire tri tri1 supply0 wand triand tri0
|
wire tri tri1 supply0 wand triand tri0
|
supply1 wor time trireg trior
|
supply1 wor time trireg trior
|
reg integer real realtime
|
reg integer real realtime
|
|
|
genvar
|
genvar
|
);
|
);
|
@verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
|
@verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
|
|
|
#V2001
|
#V2001
|
|
|
$verilog_sigs_regexp = "\\b(?:" .
|
$verilog_sigs_regexp = "\\b(?:" .
|
join("|",@verilog_signal_keywords) .
|
join("|",@verilog_signal_keywords) .
|
")\\b";
|
")\\b";
|
|
|
@verilog_gatetype_keywords = qw(and nand or nor xor xnor buf bufif0 bufif1
|
@verilog_gatetype_keywords = qw(and nand or nor xor xnor buf bufif0 bufif1
|
not notif0 notif1 pulldown pullup
|
not notif0 notif1 pulldown pullup
|
nmos rnmos pmos rpmos cmos rcmos tran rtran
|
nmos rnmos pmos rpmos cmos rcmos tran rtran
|
tranif0 rtranif0 tranif1 rtranif1
|
tranif0 rtranif0 tranif1 rtranif1
|
);
|
);
|
|
|
$verilog_gatetype_regexp = "\\b(?:" .
|
$verilog_gatetype_regexp = "\\b(?:" .
|
join("|",@verilog_gatetype_keywords) .
|
join("|",@verilog_gatetype_keywords) .
|
")\\b";
|
")\\b";
|
|
|
# Note: optimisation code in _search() assumes all of
|
# Note: optimisation code in _search() assumes all of
|
# these compiler keywords contain a `
|
# these compiler keywords contain a `
|
@verilog_compiler_keywords = qw(
|
@verilog_compiler_keywords = qw(
|
`celldefine `define
|
`celldefine `define
|
`delay_mode_path `disable_portfaults
|
`delay_mode_path `disable_portfaults
|
`else `enable_portfaults
|
`else `enable_portfaults
|
`endcelldefine `endif
|
`endcelldefine `endif
|
`ifdef `include
|
`ifdef `include
|
`nosuppress_faults `suppress_faults
|
`nosuppress_faults `suppress_faults
|
`timescale `undef
|
`timescale `undef
|
`resetall `delay_mode_distributed
|
`resetall `delay_mode_distributed
|
|
|
`default_nettype `file `line `ifndef `elsif
|
`default_nettype `file `line `ifndef `elsif
|
); #`
|
); #`
|
|
|
# a verilog identifier is this reg exp
|
# a verilog identifier is this reg exp
|
# a non-escaped identifier is A-Z a-z _ 0-9 or $
|
# a non-escaped identifier is A-Z a-z _ 0-9 or $
|
# an escaped identifier is \ followed by non-whitespace
|
# an escaped identifier is \ followed by non-whitespace
|
# why \\\\\S+ ? This gets \\\S+ in to the string then when it
|
# why \\\\\S+ ? This gets \\\S+ in to the string then when it
|
# it used we get it searching for \ followed by non-whitespace (\S+)
|
# it used we get it searching for \ followed by non-whitespace (\S+)
|
$VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
|
$VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
|
|
|
# hierarchical VID - just $VID(.$VID)+ but can't write it like this
|
# hierarchical VID - just $VID(.$VID)+ but can't write it like this
|
# because of \ escaping (and must include whitespace after esc.ids.)
|
# because of \ escaping (and must include whitespace after esc.ids.)
|
$HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
|
$HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
|
'(?:\.(?:[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
|
# V2001: added [sS] - is this correct
|
$VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
|
$VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
|
|
|
|
|
$quiet=0;
|
$quiet=0;
|
$debug=0;
|
$debug=0;
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 read_verilog
|
=head1 read_verilog
|
|
|
reads in verilog files, parses them and stores results in an internal
|
reads in verilog files, parses them and stores results in an internal
|
data structure (which I call a RVP database).
|
data structure (which I call a RVP database).
|
|
|
Arguments: - reference to array of files to read (can have paths)
|
Arguments: - reference to array of files to read (can have paths)
|
- reference to hash of defines with names as keys
|
- reference to hash of defines with names as keys
|
- reference to array of global includes - not used anymore,
|
- reference to array of global includes - not used anymore,
|
just kept for backwards compatibility
|
just kept for backwards compatibility
|
- quite flag. 1=be quiet, 0=be chatty.
|
- quite flag. 1=be quiet, 0=be chatty.
|
- reference to array of include directories
|
- reference to array of include directories
|
- reference to array of library directories
|
- reference to array of library directories
|
- library extension string (eg '.v') or reference to array of strings
|
- library extension string (eg '.v') or reference to array of strings
|
|
|
Returns: - a pointer to the internal data structure.
|
Returns: - a pointer to the internal data structure.
|
|
|
Example:
|
Example:
|
$defines{'TRUE'}=1; # same as +define+TRUE=1 on verilog cmd line
|
$defines{'TRUE'}=1; # same as +define+TRUE=1 on verilog cmd line
|
$vdata = rvp->read_verilog(\@files,[],\%defines,1,
|
$vdata = rvp->read_verilog(\@files,[],\%defines,1,
|
\@inc_dirs,\@lib_dirs,\@lib_exts);
|
\@inc_dirs,\@lib_dirs,\@lib_exts);
|
|
|
=cut
|
=cut
|
sub read_verilog {
|
sub read_verilog {
|
# be backwards compatible with non-OO call
|
# be backwards compatible with non-OO call
|
my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
|
my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
|
my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
|
my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
|
$lib_dirs,$lib_ext_arg,$exp)
|
$lib_dirs,$lib_ext_arg,$exp)
|
= @_;
|
= @_;
|
my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
|
my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
|
|
|
my $self;
|
my $self;
|
|
|
die "read_verilog needs an array ref as arg 1" unless "ARRAY" eq ref $files;
|
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 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;
|
die "read_verilog needs 0 or 1 as arg 3" unless $local_quiet==0 || $local_quiet==1;
|
|
|
# be backwards compatible
|
# be backwards compatible
|
if (!defined($inc_dirs)) { $inc_dirs=[]; }
|
if (!defined($inc_dirs)) { $inc_dirs=[]; }
|
if (!defined($lib_dirs)) { $lib_dirs=[]; }
|
if (!defined($lib_dirs)) { $lib_dirs=[]; }
|
|
|
if (!defined($lib_ext_arg)) { # no libexts given
|
if (!defined($lib_ext_arg)) { # no libexts given
|
$lib_exts=[''];
|
$lib_exts=[''];
|
}
|
}
|
elsif (!ref($lib_ext_arg)) { # a string given
|
elsif (!ref($lib_ext_arg)) { # a string given
|
$lib_exts=[$lib_ext_arg];
|
$lib_exts=[$lib_ext_arg];
|
}
|
}
|
else { # an array ref given
|
else { # an array ref given
|
$lib_exts=$lib_ext_arg;
|
$lib_exts=$lib_ext_arg;
|
}
|
}
|
|
|
|
|
# make the parser
|
# make the parser
|
if (! defined &parse_line) {
|
if (! defined &parse_line) {
|
|
|
my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
|
my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
|
[ $baseEval,$rvpEval ] ,
|
[ $baseEval,$rvpEval ] ,
|
$debug );
|
$debug );
|
if ($debug) {
|
if ($debug) {
|
open(PC,">v2html-parser.pl");
|
open(PC,">v2html-parser.pl");
|
print PC $perlCode;
|
print PC $perlCode;
|
}
|
}
|
eval($perlCode);
|
eval($perlCode);
|
print STDERR $@ if ($@);
|
print STDERR $@ if ($@);
|
}
|
}
|
|
|
if (! defined &_parse_line) { die "Parse code generation failed";}
|
if (! defined &_parse_line) { die "Parse code generation failed";}
|
|
|
$old_quiet=$quiet;
|
$old_quiet=$quiet;
|
$quiet=$local_quiet;
|
$quiet=$local_quiet;
|
# set up top of main data structure
|
# set up top of main data structure
|
$self = {};
|
$self = {};
|
$self->{files} = {}; # information on each file
|
$self->{files} = {}; # information on each file
|
$self->{modules} = {}; # pointers to module info in {files}
|
$self->{modules} = {}; # pointers to module info in {files}
|
$self->{defines} = {};
|
$self->{defines} = {};
|
$self->{ignored_modules} = {}; # list of modules were duplicates were found
|
$self->{ignored_modules} = {}; # list of modules were duplicates were found
|
$self->{unresolved_modules} = {}; # modules we have not found yet
|
$self->{unresolved_modules} = {}; # modules we have not found yet
|
$self->{problems} = []; # warning/confused messages
|
$self->{problems} = []; # warning/confused messages
|
|
|
bless($self,$class);
|
bless($self,$class);
|
|
|
foreach my $d (keys(%$cmd_line_defines)) {
|
foreach my $d (keys(%$cmd_line_defines)) {
|
_add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
|
_add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
|
}
|
}
|
|
|
# go through all the files and find information
|
# go through all the files and find information
|
@new_search_files = @{$files};
|
@new_search_files = @{$files};
|
while (@new_search_files) {
|
while (@new_search_files) {
|
@search_files = @new_search_files;
|
@search_files = @new_search_files;
|
@new_search_files = ();
|
@new_search_files = ();
|
foreach $file (@search_files) {
|
foreach $file (@search_files) {
|
$self->_search($file,$inc_dirs);
|
$self->_search($file,$inc_dirs);
|
}
|
}
|
push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
|
push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
|
}
|
}
|
|
|
|
|
if ($debug) {
|
if ($debug) {
|
_check_coverage();
|
_check_coverage();
|
}
|
}
|
|
|
# cross reference files' information
|
# cross reference files' information
|
print "Cross referencing\n" unless $quiet;
|
print "Cross referencing\n" unless $quiet;
|
$self->_cross_reference();
|
$self->_cross_reference();
|
|
|
$quiet=$old_quiet;
|
$quiet=$old_quiet;
|
|
|
foreach my $m ( sort (keys %{$self->{unresolved_modules}} )) {
|
foreach my $m ( sort (keys %{$self->{unresolved_modules}} )) {
|
# find somewhere it is instantiated for warning message
|
# find somewhere it is instantiated for warning message
|
my $file="";
|
my $file="";
|
my $line="";
|
my $line="";
|
foreach my $m2 (sort (keys %{$self->{modules}})) {
|
foreach my $m2 (sort (keys %{$self->{modules}})) {
|
foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
|
foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
|
if ($inst->{module} eq $m) {
|
if ($inst->{module} eq $m) {
|
$file = $inst->{file};
|
$file = $inst->{file};
|
$line = $inst->{line};
|
$line = $inst->{line};
|
last;
|
last;
|
}
|
}
|
}
|
}
|
}
|
}
|
$self->_add_warning("$file:$line: Could not find module $m");
|
#$self->_add_warning("$file:$line: Could not find module $m");
|
}
|
}
|
return $self;
|
return $self;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_problems
|
=head1 get_problems
|
|
|
Return any problems that happened during parsing
|
Return any problems that happened during parsing
|
|
|
Returns: - array of strings of problems. Each one is:
|
Returns: - array of strings of problems. Each one is:
|
"TYPE:FILE:LINE: description"
|
"TYPE:FILE:LINE: description"
|
|
|
=cut
|
=cut
|
sub get_problems {
|
sub get_problems {
|
my ($self) = @_;
|
my ($self) = @_;
|
|
|
return (@{$self->{problems}});
|
return (@{$self->{problems}});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 set_debug
|
=head1 set_debug
|
|
|
Turns on debug printing in the parser.
|
Turns on debug printing in the parser.
|
|
|
Returns: - nothing
|
Returns: - nothing
|
|
|
=cut
|
=cut
|
sub set_debug {
|
sub set_debug {
|
$debug=1;
|
$debug=1;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 unset_debug
|
=head1 unset_debug
|
|
|
Turns off debug printing in the parser.
|
Turns off debug printing in the parser.
|
|
|
Returns: - nothing
|
Returns: - nothing
|
|
|
=cut
|
=cut
|
sub unset_debug {
|
sub unset_debug {
|
$debug=0;
|
$debug=0;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files
|
=head1 get_files
|
|
|
Get a list of all the files in the database.
|
Get a list of all the files in the database.
|
|
|
Returns: - list of all the files
|
Returns: - list of all the files
|
|
|
Example: @all_files = $vdata->get_files();
|
Example: @all_files = $vdata->get_files();
|
|
|
=cut
|
=cut
|
sub get_files{
|
sub get_files{
|
my ($self) = @_;
|
my ($self) = @_;
|
|
|
if (wantarray) {
|
if (wantarray) {
|
return sort (keys %{$self->{files}});
|
return sort (keys %{$self->{files}});
|
}
|
}
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
return keys %{$self->{files}};
|
return keys %{$self->{files}};
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files_modules
|
=head1 get_files_modules
|
|
|
Get a list of all the modules in a particular file.
|
Get a list of all the modules in a particular file.
|
|
|
Arguments: - name of file
|
Arguments: - name of file
|
|
|
Returns: - list of module names
|
Returns: - list of module names
|
|
|
Example: @modules = $vdata->get_files_modules($file);
|
Example: @modules = $vdata->get_files_modules($file);
|
|
|
=cut
|
=cut
|
sub get_files_modules{
|
sub get_files_modules{
|
my ($self,$file) = @_;
|
my ($self,$file) = @_;
|
my (@modules,$m);
|
my (@modules,$m);
|
|
|
foreach $m (sort (keys %{$self->{files}{$file}{modules}})) {
|
foreach $m (sort (keys %{$self->{files}{$file}{modules}})) {
|
push(@modules,$m)
|
push(@modules,$m)
|
}
|
}
|
|
|
return @modules;
|
return @modules;
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files_full_name
|
=head1 get_files_full_name
|
|
|
Get the full name (including path) of a file.
|
Get the full name (including path) of a file.
|
|
|
Arguments: - name of file
|
Arguments: - name of file
|
|
|
Returns: - full path name
|
Returns: - full path name
|
|
|
Example $full_name = $vdata->get_files_full_name($file);
|
Example $full_name = $vdata->get_files_full_name($file);
|
|
|
=cut
|
=cut
|
sub get_files_full_name{
|
sub get_files_full_name{
|
my ($self,$file) = @_;
|
my ($self,$file) = @_;
|
|
|
return $self->{files}{$file}{full_name};
|
return $self->{files}{$file}{full_name};
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files_stats
|
=head1 get_files_stats
|
|
|
Get statistics about a file
|
Get statistics about a file
|
|
|
Arguments: - name of file
|
Arguments: - name of file
|
|
|
Returns: - number of lines in the file (more later...)
|
Returns: - number of lines in the file (more later...)
|
|
|
Example $full_name = $vdata->get_files_stats($file);
|
Example $full_name = $vdata->get_files_stats($file);
|
|
|
=cut
|
=cut
|
sub get_files_stats{
|
sub get_files_stats{
|
my ($self,$file) = @_;
|
my ($self,$file) = @_;
|
|
|
return $self->{files}{$file}{lines};
|
return $self->{files}{$file}{lines};
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 file_exists
|
=head1 file_exists
|
|
|
Test if a particular module file in the database.
|
Test if a particular module file in the database.
|
|
|
Arguments: - file name to test.
|
Arguments: - file name to test.
|
|
|
Returns: - 1 if exists otherwise 0
|
Returns: - 1 if exists otherwise 0
|
|
|
Example: if ($vdata->file_exists($file))....
|
Example: if ($vdata->file_exists($file))....
|
|
|
=cut
|
=cut
|
sub file_exists{
|
sub file_exists{
|
my ($self,$file) = @_;
|
my ($self,$file) = @_;
|
return exists($self->{files}{_ffile($file)});
|
return exists($self->{files}{_ffile($file)});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules
|
=head1 get_modules
|
|
|
Get a list of all the modules in the database.
|
Get a list of all the modules in the database.
|
|
|
|
|
Returns: - list of all the modules
|
Returns: - list of all the modules
|
|
|
Example: @all_modules = $vdata->get_modules();
|
Example: @all_modules = $vdata->get_modules();
|
|
|
=cut
|
=cut
|
sub get_modules{
|
sub get_modules{
|
my ($self) = @_;
|
my ($self) = @_;
|
|
|
if (wantarray) {
|
if (wantarray) {
|
return sort (keys %{$self->{modules}});
|
return sort (keys %{$self->{modules}});
|
}
|
}
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
return keys %{$self->{modules}};
|
return keys %{$self->{modules}};
|
}
|
}
|
|
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_t_and_f
|
=head1 get_modules_t_and_f
|
|
|
Get a list of all the tasks and functions in a particular module.
|
Get a list of all the tasks and functions in a particular module.
|
|
|
Arguments: - name of module
|
Arguments: - name of module
|
|
|
Returns: - list of tasks and function names
|
Returns: - list of tasks and function names
|
|
|
Example: if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
|
Example: if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
|
|
|
=cut
|
=cut
|
# return a list of all the tasks and functions in a module
|
# return a list of all the tasks and functions in a module
|
sub get_modules_t_and_f{
|
sub get_modules_t_and_f{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
if (wantarray) {
|
if (wantarray) {
|
return sort (keys %{$self->{modules}{$module}{t_and_f}});
|
return sort (keys %{$self->{modules}{$module}{t_and_f}});
|
}
|
}
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
return keys %{$self->{modules}{$module}{t_and_f}};
|
return keys %{$self->{modules}{$module}{t_and_f}};
|
}
|
}
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_t_or_f
|
=head1 get_modules_t_or_f
|
|
|
Get information on a task or function in a module.
|
Get information on a task or function in a module.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
- task or function name
|
- task or function name
|
|
|
Returns: - A 4 element list: type (task or function), definition line,
|
Returns: - A 4 element list: type (task or function), definition line,
|
file, anchor
|
file, anchor
|
|
|
Example: ($t_type,$t_line ,$t_file,$t_anchor)=
|
Example: ($t_type,$t_line ,$t_file,$t_anchor)=
|
$vdata->get_modules_t_or_f($m,$tf);
|
$vdata->get_modules_t_or_f($m,$tf);
|
|
|
=cut
|
=cut
|
sub get_modules_t_or_f{
|
sub get_modules_t_or_f{
|
my ($self,$mod,$t_or_f) = @_;
|
my ($self,$mod,$t_or_f) = @_;
|
|
|
if (exists($self->{modules}{$mod}{t_and_f}{$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},
|
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}{line},
|
$self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
|
$self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
|
$self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
|
$self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_signals
|
=head1 get_modules_signals
|
|
|
Get a list of all the signals in a particular module.
|
Get a list of all the signals in a particular module.
|
|
|
Arguments: - name of module
|
Arguments: - name of module
|
|
|
Returns: - list of signal names
|
Returns: - list of signal names
|
|
|
Example: if ( @signs = $vdata->get_modules_signals($m))...
|
Example: if ( @signs = $vdata->get_modules_signals($m))...
|
|
|
=cut
|
=cut
|
# return a list of all the tasks and functions in a module
|
# return a list of all the tasks and functions in a module
|
sub get_modules_signals{
|
sub get_modules_signals{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
if (wantarray) {
|
if (wantarray) {
|
return sort (keys %{$self->{modules}{$module}{signals}});
|
return sort (keys %{$self->{modules}{$module}{signals}});
|
}
|
}
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
else { # in a scalar context keys returns the number of elements - sort doesn't
|
return keys %{$self->{modules}{$module}{signals}};
|
return keys %{$self->{modules}{$module}{signals}};
|
}
|
}
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_file
|
=head1 get_modules_file
|
|
|
Get the file name (no path) that a module is defined in.
|
Get the file name (no path) that a module is defined in.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - file name without path, and the line number module starts on
|
Returns: - file name without path, and the line number module starts on
|
|
|
Example: ($f) = $vdata->get_modules_file($m);
|
Example: ($f) = $vdata->get_modules_file($m);
|
|
|
=cut
|
=cut
|
# get the file name that contains a module
|
# get the file name that contains a module
|
sub get_modules_file{
|
sub get_modules_file{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
|
return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_type
|
=head1 get_modules_type
|
|
|
Get the type of the module - It is one of: module, macromodule or primitive
|
Get the type of the module - It is one of: module, macromodule or primitive
|
(rvp treats these all as modules).
|
(rvp treats these all as modules).
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - type
|
Returns: - type
|
|
|
Example: $t = $vdata->get_modules_type($m);
|
Example: $t = $vdata->get_modules_type($m);
|
|
|
=cut
|
=cut
|
# get the file name that contains a module
|
# get the file name that contains a module
|
sub get_modules_type{
|
sub get_modules_type{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
return ($self->{modules}{$module}{type});
|
return ($self->{modules}{$module}{type});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files_includes
|
=head1 get_files_includes
|
|
|
Get the file names (no path) of files included in a file.
|
Get the file names (no path) of files included in a file.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
|
|
Returns: - list of file names without paths
|
Returns: - list of file names without paths
|
|
|
Example: @f = $vdata->get_files_includes($file);
|
Example: @f = $vdata->get_files_includes($file);
|
|
|
=cut
|
=cut
|
sub get_files_includes {
|
sub get_files_includes {
|
my ($self,$f) = @_;
|
my ($self,$f) = @_;
|
my @includes_found = ();
|
my @includes_found = ();
|
|
|
if (exists($self->{files}{$f})) {
|
if (exists($self->{files}{$f})) {
|
foreach my $inc ( sort ( keys %{$self->{files}{$f}{includes}} )) {
|
foreach my $inc ( sort ( keys %{$self->{files}{$f}{includes}} )) {
|
push(@includes_found,$inc);
|
push(@includes_found,$inc);
|
# do the includes for the included file
|
# do the includes for the included file
|
push(@includes_found, $self->get_files_includes($inc));
|
push(@includes_found, $self->get_files_includes($inc));
|
}
|
}
|
}
|
}
|
|
|
return @includes_found;
|
return @includes_found;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_files_included_by
|
=head1 get_files_included_by
|
|
|
Get the file names (no path) of files that included this file.
|
Get the file names (no path) of files that included this file.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
|
|
Returns: - list of file names without paths
|
Returns: - list of file names without paths
|
|
|
Example: @f = $vdata->get_files_included_by($file);
|
Example: @f = $vdata->get_files_included_by($file);
|
|
|
=cut
|
=cut
|
sub get_files_included_by {
|
sub get_files_included_by {
|
my ($self,$f) = @_;
|
my ($self,$f) = @_;
|
|
|
return @{$self->{files}{$f}{included_by}};
|
return @{$self->{files}{$f}{included_by}};
|
|
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 module_ignored
|
=head1 module_ignored
|
|
|
Test if a particular module has been ignored because of duplicates found
|
Test if a particular module has been ignored because of duplicates found
|
|
|
Arguments: - module name to test
|
Arguments: - module name to test
|
|
|
Returns: - 1 if ignored otherwise 0
|
Returns: - 1 if ignored otherwise 0
|
|
|
Example: if ($vdata->module_ignored($module))....
|
Example: if ($vdata->module_ignored($module))....
|
|
|
=cut
|
=cut
|
sub module_ignored {
|
sub module_ignored {
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
return (exists($self->{modules}{$module}) &&
|
return (exists($self->{modules}{$module}) &&
|
$self->{modules}{$module}{duplicate});
|
$self->{modules}{$module}{duplicate});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 module_exists
|
=head1 module_exists
|
|
|
Test if a particular module exists in the database.
|
Test if a particular module exists in the database.
|
|
|
Arguments: - module name to test
|
Arguments: - module name to test
|
|
|
Returns: - 1 if exists otherwise 0
|
Returns: - 1 if exists otherwise 0
|
|
|
Example: if ($vdata->module_exists($module))....
|
Example: if ($vdata->module_exists($module))....
|
|
|
=cut
|
=cut
|
sub module_exists{
|
sub module_exists{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
return exists($self->{modules}{$module});
|
return exists($self->{modules}{$module});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_ignored_modules
|
=head1 get_ignored_modules
|
|
|
Return a list of the ignored modules. These are modules where duplicates
|
Return a list of the ignored modules. These are modules where duplicates
|
have been found.
|
have been found.
|
|
|
Returns: - List of ignored modules
|
Returns: - List of ignored modules
|
|
|
Example: - foreach $module ($vdata->get_ignored_modules())....
|
Example: - foreach $module ($vdata->get_ignored_modules())....
|
|
|
=cut
|
=cut
|
sub get_ignored_modules {
|
sub get_ignored_modules {
|
my ($self) = @_;
|
my ($self) = @_;
|
my @ig =();
|
my @ig =();
|
foreach my $m (sort (keys %{$self->{modules}})) {
|
foreach my $m (sort (keys %{$self->{modules}})) {
|
push(@ig, $m) if ($self->{modules}{$m}{duplicate});
|
push(@ig, $m) if ($self->{modules}{$m}{duplicate});
|
}
|
}
|
return @ig;
|
return @ig;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_module_signal
|
=head1 get_module_signal
|
|
|
Get information about a particular signal in a particular module.
|
Get information about a particular signal in a particular module.
|
|
|
Arguments: - name of module
|
Arguments: - name of module
|
- name of signal
|
- name of signal
|
|
|
Returns: - A list containing:
|
Returns: - A list containing:
|
- the line signal is defined
|
- the line signal is defined
|
- the line signal is assigned first (or -1)
|
- the line signal is assigned first (or -1)
|
- line in instantiating module where an input
|
- line in instantiating module where an input
|
is driven from (or -1)
|
is driven from (or -1)
|
- the type of the signal (input,output,reg etc)
|
- the type of the signal (input,output,reg etc)
|
- the file the signal is in
|
- the file the signal is in
|
- posedge flag (1 if signal ever seen with posedge)
|
- posedge flag (1 if signal ever seen with posedge)
|
- negedge flag (1 if signal ever seen with negedge)
|
- negedge flag (1 if signal ever seen with negedge)
|
- second type (eg reg for a registered output)
|
- second type (eg reg for a registered output)
|
- signal real source file
|
- signal real source file
|
- signal real source line
|
- signal real source line
|
- range string if any ( not including [ and ] )
|
- range string if any ( not including [ and ] )
|
- the file signal is assigned first (or '')
|
- the file signal is assigned first (or '')
|
- file for the instantiating module where an input
|
- file for the instantiating module where an input
|
is driven from (or "")
|
is driven from (or "")
|
- a pointer to an array of dimensions for memories
|
- a pointer to an array of dimensions for memories
|
each element of the array is a dimension, array
|
each element of the array is a dimension, array
|
is empty for non-memories
|
is empty for non-memories
|
|
|
Note posedge and negedge information is propagated up the hierarchy to
|
Note posedge and negedge information is propagated up the hierarchy to
|
attached signals. It is not propagated down the hierarchy.
|
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,
|
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) =
|
$s_type2,$s_r_file,$s_r_line,$range,$s_a_file,$s_i_file) =
|
$vdata->get_module_signal($m,$sig);
|
$vdata->get_module_signal($m,$sig);
|
|
|
=cut
|
=cut
|
sub get_module_signal{
|
sub get_module_signal{
|
my ($self,$module,$sig) = @_;
|
my ($self,$module,$sig) = @_;
|
|
|
if (exists( $self->{modules}{$module}{signals}{$sig} )) {
|
if (exists( $self->{modules}{$module}{signals}{$sig} )) {
|
return ($self->{modules}{$module}{signals}{$sig}{line},
|
return ($self->{modules}{$module}{signals}{$sig}{line},
|
$self->{modules}{$module}{signals}{$sig}{a_line},
|
$self->{modules}{$module}{signals}{$sig}{a_line},
|
$self->{modules}{$module}{signals}{$sig}{i_line},
|
$self->{modules}{$module}{signals}{$sig}{i_line},
|
$self->{modules}{$module}{signals}{$sig}{type},
|
$self->{modules}{$module}{signals}{$sig}{type},
|
$self->{modules}{$module}{signals}{$sig}{file},
|
$self->{modules}{$module}{signals}{$sig}{file},
|
$self->{modules}{$module}{signals}{$sig}{posedge},
|
$self->{modules}{$module}{signals}{$sig}{posedge},
|
$self->{modules}{$module}{signals}{$sig}{negedge},
|
$self->{modules}{$module}{signals}{$sig}{negedge},
|
$self->{modules}{$module}{signals}{$sig}{type2},
|
$self->{modules}{$module}{signals}{$sig}{type2},
|
$self->{modules}{$module}{signals}{$sig}{source}{file},
|
$self->{modules}{$module}{signals}{$sig}{source}{file},
|
$self->{modules}{$module}{signals}{$sig}{source}{line},
|
$self->{modules}{$module}{signals}{$sig}{source}{line},
|
$self->{modules}{$module}{signals}{$sig}{range},
|
$self->{modules}{$module}{signals}{$sig}{range},
|
$self->{modules}{$module}{signals}{$sig}{a_file},
|
$self->{modules}{$module}{signals}{$sig}{a_file},
|
$self->{modules}{$module}{signals}{$sig}{i_file},
|
$self->{modules}{$module}{signals}{$sig}{i_file},
|
$self->{modules}{$module}{signals}{$sig}{dimensions});
|
$self->{modules}{$module}{signals}{$sig}{dimensions});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_first_signal_port_con
|
=head1 get_first_signal_port_con
|
|
|
Get the first port that this signal in this module is connected to.
|
Get the first port that this signal in this module is connected to.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
- signal name
|
- signal name
|
|
|
Returns: - a 5 element list: instantiated module name, instance name
|
Returns: - a 5 element list: instantiated module name, instance name
|
port name, line number and file
|
port name, line number and file
|
|
|
Example: ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
|
Example: ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
|
|
|
=cut
|
=cut
|
sub get_first_signal_port_con{
|
sub get_first_signal_port_con{
|
my ($self,$module,$signal) = @_;
|
my ($self,$module,$signal) = @_;
|
|
|
$self->{current_signal_port_con} =0;
|
$self->{current_signal_port_con} =0;
|
$self->{current_signal_port_con_module}=$module;
|
$self->{current_signal_port_con_module}=$module;
|
$self->{current_signal_port_con_module_signal}=$signal;
|
$self->{current_signal_port_con_module_signal}=$signal;
|
|
|
return $self->get_next_signal_port_con();
|
return $self->get_next_signal_port_con();
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_next_signal_port_con
|
=head1 get_next_signal_port_con
|
|
|
Get the next port that this signal in this module is connected to.
|
Get the next port that this signal in this module is connected to.
|
|
|
Returns: - a 5 element list: instantiated module name, instance name
|
Returns: - a 5 element list: instantiated module name, instance name
|
port name, line number and file
|
port name, line number and file
|
|
|
Example: ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
|
Example: ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
|
|
|
=cut
|
=cut
|
sub get_next_signal_port_con{
|
sub get_next_signal_port_con{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$signal,$i,$pcref);
|
my ($module,$signal,$i,$pcref);
|
|
|
$module = $self->{current_signal_port_con_module};
|
$module = $self->{current_signal_port_con_module};
|
$signal = $self->{current_signal_port_con_module_signal};
|
$signal = $self->{current_signal_port_con_module_signal};
|
$i = $self->{current_signal_port_con};
|
$i = $self->{current_signal_port_con};
|
|
|
$pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
|
$pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
|
if (@{$pcref} > $i ) {
|
if (@{$pcref} > $i ) {
|
$self->{current_signal_port_con}++;
|
$self->{current_signal_port_con}++;
|
return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
|
return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
|
$pcref->[$i]{line},$pcref->[$i]{file});
|
$pcref->[$i]{line},$pcref->[$i]{file});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_first_signal_con_to
|
=head1 get_first_signal_con_to
|
|
|
Get the first signal that is connected to this port in an
|
Get the first signal that is connected to this port in an
|
instantiation of this module. This only works for instances that use
|
instantiation of this module. This only works for instances that use
|
the .port(sig) notation.
|
the .port(sig) notation.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
- signal name
|
- signal name
|
|
|
Returns: - a 4 element list: signal connected to this port
|
Returns: - a 4 element list: signal connected to this port
|
module signal is in
|
module signal is in
|
instance (of this module) where the connection
|
instance (of this module) where the connection
|
occurs
|
occurs
|
|
|
Example: ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
|
Example: ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
|
|
|
=cut
|
=cut
|
sub get_first_signal_con_to{
|
sub get_first_signal_con_to{
|
my ($self,$module,$signal) = @_;
|
my ($self,$module,$signal) = @_;
|
|
|
$self->{current_signal_con_to} =0;
|
$self->{current_signal_con_to} =0;
|
$self->{current_signal_con_to_module}=$module;
|
$self->{current_signal_con_to_module}=$module;
|
$self->{current_signal_con_to_module_signal}=$signal;
|
$self->{current_signal_con_to_module_signal}=$signal;
|
|
|
return $self->get_next_signal_con_to();
|
return $self->get_next_signal_con_to();
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_next_signal_con_to
|
=head1 get_next_signal_con_to
|
|
|
Get the next signal that is connected to this port in an
|
Get the next signal that is connected to this port in an
|
instantiation of this module. This only works for instances that use
|
instantiation of this module. This only works for instances that use
|
the .port(sig) notation.
|
the .port(sig) notation.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
- signal name
|
- signal name
|
|
|
Returns: - a 4 element list: signal connected to this port
|
Returns: - a 4 element list: signal connected to this port
|
module signal is in
|
module signal is in
|
instance (of this module) where the connection
|
instance (of this module) where the connection
|
occurs
|
occurs
|
|
|
Example: ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
|
Example: ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
|
|
|
=cut
|
=cut
|
sub get_next_signal_con_to{
|
sub get_next_signal_con_to{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$signal,$i,$ctref);
|
my ($module,$signal,$i,$ctref);
|
|
|
$module = $self->{current_signal_con_to_module};
|
$module = $self->{current_signal_con_to_module};
|
$signal = $self->{current_signal_con_to_module_signal};
|
$signal = $self->{current_signal_con_to_module_signal};
|
$i = $self->{current_signal_con_to};
|
$i = $self->{current_signal_con_to};
|
|
|
$ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
|
$ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
|
if (@{$ctref} > $i ) {
|
if (@{$ctref} > $i ) {
|
$self->{current_signal_con_to}++;
|
$self->{current_signal_con_to}++;
|
return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
|
return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_first_instantiator
|
=head1 get_first_instantiator
|
|
|
Get the first thing that instantiates this module.
|
Get the first thing that instantiates this module.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - a 4 element list: instantiating module, file, instance name, line
|
Returns: - a 4 element list: instantiating module, file, instance name, line
|
|
|
Example:
|
Example:
|
($im,$f,$i) = $vdata->get_first_instantiator($m );
|
($im,$f,$i) = $vdata->get_first_instantiator($m );
|
|
|
=cut
|
=cut
|
# Get the first thing that instantiates or empty list if none.
|
# Get the first thing that instantiates or empty list if none.
|
# Returns: { module, file, inst }
|
# Returns: { module, file, inst }
|
sub get_first_instantiator{
|
sub get_first_instantiator{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
if ( exists( $self->{modules}{$module} )) {
|
if ( exists( $self->{modules}{$module} )) {
|
$self->{current_instantiator} =0;
|
$self->{current_instantiator} =0;
|
$self->{current_instantiator_module}=$module;
|
$self->{current_instantiator_module}=$module;
|
return $self->get_next_instantiator();
|
return $self->get_next_instantiator();
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_next_instantiator
|
=head1 get_next_instantiator
|
|
|
Get the first thing that instantiates the module specified in
|
Get the first thing that instantiates the module specified in
|
get_first_instantiator (or _by_context).
|
get_first_instantiator (or _by_context).
|
|
|
Returns: - a 4 element list: instantiating module, file,
|
Returns: - a 4 element list: instantiating module, file,
|
instance name, line
|
instance name, line
|
|
|
Example:
|
Example:
|
($im,$f,$i) = $vdata->get_next_instantiator();
|
($im,$f,$i) = $vdata->get_next_instantiator();
|
|
|
=cut
|
=cut
|
sub get_next_instantiator{
|
sub get_next_instantiator{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$i);
|
my ($module,$i);
|
|
|
$module = $self->{current_instantiator_module};
|
$module = $self->{current_instantiator_module};
|
$i = $self->{current_instantiator};
|
$i = $self->{current_instantiator};
|
|
|
if (@{$self->{modules}{$module}{inst_by}} > $i ) {
|
if (@{$self->{modules}{$module}{inst_by}} > $i ) {
|
$self->{current_instantiator}++;
|
$self->{current_instantiator}++;
|
return ($self->{modules}{$module}{inst_by}[$i]{module},
|
return ($self->{modules}{$module}{inst_by}[$i]{module},
|
$self->{modules}{$module}{inst_by}[$i]{file},
|
$self->{modules}{$module}{inst_by}[$i]{file},
|
$self->{modules}{$module}{inst_by}[$i]{inst},
|
$self->{modules}{$module}{inst_by}[$i]{inst},
|
$self->{modules}{$module}{inst_by}[$i]{line} );
|
$self->{modules}{$module}{inst_by}[$i]{line} );
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_first_instantiation
|
=head1 get_first_instantiation
|
|
|
Get the first thing that this module instantiates.
|
Get the first thing that this module instantiates.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - a 4 element list: instantiated module name, file,
|
Returns: - a 4 element list: instantiated module name, file,
|
instance name, and line number
|
instance name, and line number
|
|
|
Example:
|
Example:
|
($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
|
($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
|
|
|
=cut
|
=cut
|
sub get_first_instantiation{
|
sub get_first_instantiation{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
if ( exists( $self->{modules}{$module} )) {
|
if ( exists( $self->{modules}{$module} )) {
|
$self->{current_instantiation} =0;
|
$self->{current_instantiation} =0;
|
$self->{current_instantiation_module}=$module;
|
$self->{current_instantiation_module}=$module;
|
return $self->get_next_instantiation();
|
return $self->get_next_instantiation();
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_next_instantiation
|
=head1 get_next_instantiation
|
|
|
Get the next thing that this module instantiates.
|
Get the next thing that this module instantiates.
|
|
|
|
|
Returns: - a 4 element list: instantiated module name, file,
|
Returns: - a 4 element list: instantiated module name, file,
|
instance name, and line number
|
instance name, and line number
|
|
|
Example:
|
Example:
|
($im,$f,$i,$l) = $vdata->get_next_instantiation();
|
($im,$f,$i,$l) = $vdata->get_next_instantiation();
|
|
|
=cut
|
=cut
|
sub get_next_instantiation{
|
sub get_next_instantiation{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$i);
|
my ($module,$i);
|
|
|
$module = $self->{current_instantiation_module};
|
$module = $self->{current_instantiation_module};
|
$i = $self->{current_instantiation};
|
$i = $self->{current_instantiation};
|
|
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
$self->{current_instantiation}++;
|
$self->{current_instantiation}++;
|
return ($self->{modules}{$module}{instances}[$i]{module},
|
return ($self->{modules}{$module}{instances}[$i]{module},
|
$self->{modules}{$module}{instances}[$i]{file},
|
$self->{modules}{$module}{instances}[$i]{file},
|
$self->{modules}{$module}{instances}[$i]{inst_name},
|
$self->{modules}{$module}{instances}[$i]{inst_name},
|
$self->{modules}{$module}{instances}[$i]{line} );
|
$self->{modules}{$module}{instances}[$i]{line} );
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_current_instantiations_port_con
|
=head1 get_current_instantiations_port_con
|
|
|
Gets the port connections for the current instantiations (which is got
|
Gets the port connections for the current instantiations (which is got
|
using get_first_instantiation and get_next_instantiation). If the
|
using get_first_instantiation and get_next_instantiation). If the
|
instantiation does not use .port(...) syntax and rvp does not have 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
|
access to the source of the module then the port names will be returned as
|
numbers in connection order starting at 0.
|
numbers in connection order starting at 0.
|
|
|
|
|
Returns: - A hash (well, really a list that can be assigned to a hash).
|
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
|
The keys of the hash are the port names. The values of the
|
hash is everything (except comments) that appeared in the
|
hash is everything (except comments) that appeared in the
|
brackets in the verilog.
|
brackets in the verilog.
|
|
|
Example: %port_con = $vdata->get_current_instantiations_port_con();
|
Example: %port_con = $vdata->get_current_instantiations_port_con();
|
foreach $port (keys %port_con) { ...
|
foreach $port (keys %port_con) { ...
|
|
|
=cut
|
=cut
|
sub get_current_instantiations_port_con{
|
sub get_current_instantiations_port_con{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$i);
|
my ($module,$i);
|
|
|
$module = $self->{current_instantiation_module};
|
$module = $self->{current_instantiation_module};
|
$i = $self->{current_instantiation} - 1;
|
$i = $self->{current_instantiation} - 1;
|
|
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
return (%{$self->{modules}{$module}{instances}[$i]{connections}});
|
return (%{$self->{modules}{$module}{instances}[$i]{connections}});
|
}
|
}
|
else {
|
else {
|
return {};
|
return {};
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_current_instantiations_parameters
|
=head1 get_current_instantiations_parameters
|
|
|
Gets the parameters for the current instantiations (which is set using
|
Gets the parameters for the current instantiations (which is set using
|
get_first_instantiation and get_next_instantiation). If the
|
get_first_instantiation and get_next_instantiation). If the
|
instantiation parameters does not use the verilog 2001 .name(...)
|
instantiation parameters does not use the verilog 2001 .name(...)
|
syntax and rvp does not have the access to the source of the module
|
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
|
then the parameter names will be returned as numbers reflecting the
|
order (starting at 0).
|
order (starting at 0).
|
|
|
|
|
Returns: - A hash (well, really a list that can be assigned to a hash).
|
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
|
The keys of the hash are the parameters names. The values of the
|
hash is everything (except comments) in the value.
|
hash is everything (except comments) in the value.
|
|
|
Example: %parameters = $vdata->get_current_instantiations_parameters();
|
Example: %parameters = $vdata->get_current_instantiations_parameters();
|
foreach my $p (keys %parameters) { ...
|
foreach my $p (keys %parameters) { ...
|
|
|
=cut
|
=cut
|
sub get_current_instantiations_parameters{
|
sub get_current_instantiations_parameters{
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($module,$i);
|
my ($module,$i);
|
|
|
$module = $self->{current_instantiation_module};
|
$module = $self->{current_instantiation_module};
|
$i = $self->{current_instantiation} - 1;
|
$i = $self->{current_instantiation} - 1;
|
|
|
my %r;
|
my %r;
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
if (@{$self->{modules}{$module}{instances}} > $i ) {
|
foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
|
foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
|
$r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
|
$r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
|
}
|
}
|
}
|
}
|
|
|
return %r;
|
return %r;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_modules_parameters
|
=head1 get_modules_parameters
|
|
|
Gets the parameters for a module.
|
Gets the parameters for a module.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - A hash (well, really a list that can be assigned to a hash).
|
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
|
The keys of the hash are the parameters names. The values of the
|
hash is everything (except comments) in the value.
|
hash is everything (except comments) in the value.
|
|
|
Example: %parameters = $vdata->get_modules_parameters();
|
Example: %parameters = $vdata->get_modules_parameters();
|
foreach my $p (keys %parameters) { ...
|
foreach my $p (keys %parameters) { ...
|
|
|
=cut
|
=cut
|
sub get_modules_parameters{
|
sub get_modules_parameters{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
my %r;
|
my %r;
|
foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
|
foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
|
$r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
|
$r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
|
}
|
}
|
return %r;
|
return %r;
|
}
|
}
|
|
|
#######################################################
|
#######################################################
|
################### Modified ###########################
|
################### Modified ###########################
|
#######################################################
|
#######################################################
|
|
|
=head1 get_modules_parameters_not_local
|
=head1 get_modules_parameters_not_local
|
|
|
Gets the parameters for a module.
|
Gets the parameters for a module.
|
|
|
Arguments: - module name
|
Arguments: - module name
|
|
|
Returns: - A hash (well, really a list that can be assigned to a hash).
|
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
|
The keys of the hash are the parameters names. The values of the
|
hash is everything (except comments) in the value.
|
hash is everything (except comments) in the value.
|
|
|
Example: %parameters = $vdata->get_modules_parameters();
|
Example: %parameters = $vdata->get_modules_parameters();
|
foreach my $p (keys %parameters) { ...
|
foreach my $p (keys %parameters) { ...
|
|
|
=cut
|
=cut
|
sub get_modules_parameters_not_local{
|
sub get_modules_parameters_not_local{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
|
|
my %r;
|
my %r;
|
foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
|
foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
|
if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
|
if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
|
#print "$p\n";
|
#print "$p\n";
|
$r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
|
$r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
|
}
|
}
|
}
|
}
|
return %r;
|
return %r;
|
}
|
}
|
|
|
|
|
|
|
|
|
=head1 get_modules_parameters_not_local_in_order
|
=head1 get_modules_parameters_not_local_in_order
|
|
|
Gets the parameter names in_order for a module.
|
Gets the parameter names in_order for a module.
|
|
|
|
|
|
|
=cut
|
=cut
|
sub get_modules_parameters_not_local_order{
|
sub get_modules_parameters_not_local_order{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
my @r=@{$self->{modules}{$module}{parameter_order}};#param/localparam inorder
|
my @r=@{$self->{modules}{$module}{parameter_order}};#param/localparam inorder
|
my @w; #parameter inorder
|
my @w; #parameter inorder
|
foreach my $p (@r) {
|
foreach my $p (@r) {
|
if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
|
if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
|
push(@w,$p);
|
push(@w,$p);
|
}
|
}
|
|
|
}
|
}
|
|
|
return @w;
|
return @w;
|
}
|
}
|
|
|
|
|
|
|
|
|
=head1 get_module_ports_inorder
|
=head1 get_module_ports_inorder
|
|
|
Gets the parameter names in_order for a module.
|
Gets the parameter names in_order for a module.
|
|
|
|
|
|
|
=cut
|
=cut
|
sub get_module_ports_order{
|
sub get_module_ports_order{
|
my ($self,$module) = @_;
|
my ($self,$module) = @_;
|
return @{$self->{modules}{$module}{port_order}};
|
return @{$self->{modules}{$module}{port_order}};
|
}
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_define
|
=head1 get_define
|
|
|
Find out where a define is defined and what the value is
|
Find out where a define is defined and what the value is
|
|
|
Arguments: - name of the define
|
Arguments: - name of the define
|
Optional arguments where a you want the correct location and
|
Optional arguments where a you want the correct location and
|
value for a particular use of a multiplely defined define:
|
value for a particular use of a multiplely defined define:
|
- file where define is used
|
- file where define is used
|
- line where define is used
|
- line where define is used
|
|
|
Returns: - list with three elements: file, line, value
|
Returns: - list with three elements: file, line, value
|
or if the define does not exist it returns a empty list.
|
or if the define does not exist it returns a empty list.
|
if the define was defined on the command line it sets file=""
|
if the define was defined on the command line it sets file=""
|
and line=0
|
and line=0
|
|
|
|
|
Example: ($f,$l,$v) = $vdata->get_define($word,$file,$line);
|
Example: ($f,$l,$v) = $vdata->get_define($word,$file,$line);
|
|
|
=cut
|
=cut
|
sub get_define {
|
sub get_define {
|
my ($self,$define,$file,$line) = @_;
|
my ($self,$define,$file,$line) = @_;
|
|
|
if ( !defined($self) || !defined($define) ||
|
if ( !defined($self) || !defined($define) ||
|
( defined($file) && !defined($line) ) ) {
|
( defined($file) && !defined($line) ) ) {
|
die "Get define takes either two or four arguments";
|
die "Get define takes either two or four arguments";
|
}
|
}
|
|
|
$define =~ s/^\`// ; # remove the ` if any
|
$define =~ s/^\`// ; # remove the ` if any
|
|
|
if (!exists( $self->{defines}{$define} )) {
|
if (!exists( $self->{defines}{$define} )) {
|
return ();
|
return ();
|
}
|
}
|
my $index = 0;
|
my $index = 0;
|
my $dh = $self->{defines}{$define};
|
my $dh = $self->{defines}{$define};
|
|
|
if (defined($file) &&
|
if (defined($file) &&
|
exists($dh->{used}{$file}) &&
|
exists($dh->{used}{$file}) &&
|
exists($dh->{used}{$file}{$line})) {
|
exists($dh->{used}{$file}{$line})) {
|
$index = $dh->{used}{$file}{$line};
|
$index = $dh->{used}{$file}{$line};
|
}
|
}
|
|
|
|
|
if ($index eq "XX") { # define has been undefed
|
if ($index eq "XX") { # define has been undefed
|
return ();
|
return ();
|
}
|
}
|
|
|
return ( $dh->{defined}[$index]{file},
|
return ( $dh->{defined}[$index]{file},
|
$dh->{defined}[$index]{line},
|
$dh->{defined}[$index]{line},
|
$dh->{defined}[$index]{value});
|
$dh->{defined}[$index]{value});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_context
|
=head1 get_context
|
|
|
Get the context (if any) for a line in a file.
|
Get the context (if any) for a line in a file.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - line number if there is a context, zero if there is none.
|
Returns: - line number if there is a context, zero if there is none.
|
|
|
Example: $l = $vdata->get_context($filename,$line);
|
Example: $l = $vdata->get_context($filename,$line);
|
|
|
=cut
|
=cut
|
sub get_context{
|
sub get_context{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
if ( exists( $self->{files}{$file}{contexts}{$line} )) {
|
if ( exists( $self->{files}{$file}{contexts}{$line} )) {
|
return $line;
|
return $line;
|
}
|
}
|
else {
|
else {
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_module_start_by_context
|
=head1 get_module_start_by_context
|
|
|
Test if the context is a module definition start.
|
Test if the context is a module definition start.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - module name if it is a module start, 0 otherwise
|
Returns: - module name if it is a module start, 0 otherwise
|
|
|
Example: if($vdata->get_module_start_by_context($filename,$line))..
|
Example: if($vdata->get_module_start_by_context($filename,$line))..
|
|
|
=cut
|
=cut
|
# return true if the context for this line is a module start
|
# return true if the context for this line is a module start
|
sub get_module_start_by_context{
|
sub get_module_start_by_context{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
|
if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
|
return $self->{files}{$file}{contexts}{$line}{module_start};
|
return $self->{files}{$file}{contexts}{$line}{module_start};
|
}
|
}
|
else {
|
else {
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_has_value_by_context
|
=head1 get_has_value_by_context
|
|
|
Check if the context has a value (ie a new module or something). Contexts
|
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.
|
that just turn on and off preprocessor ignoring do not have values.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - 1 if there is a value, 0 otherwise
|
Returns: - 1 if there is a value, 0 otherwise
|
|
|
Example: if ($vdata->get_has_value_by_context($file,$line))..
|
Example: if ($vdata->get_has_value_by_context($file,$line))..
|
|
|
=cut
|
=cut
|
sub get_has_value_by_context{
|
sub get_has_value_by_context{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
return exists( $self->{files}{$file}{contexts}{$line}{value});
|
return exists( $self->{files}{$file}{contexts}{$line}{value});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_context_name_type
|
=head1 get_context_name_type
|
|
|
Find the reason for a new context - is it a module / function or task.
|
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.
|
Contexts that just turn on and off preprocessor ignoring do not have values.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - name
|
Returns: - name
|
- type [ module | function | task ]
|
- type [ module | function | task ]
|
|
|
Example: ($n,$t)=$vdata->get_context_name_type($file,$line);
|
Example: ($n,$t)=$vdata->get_context_name_type($file,$line);
|
|
|
=cut
|
=cut
|
sub get_context_name_type{
|
sub get_context_name_type{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
my ($name,$type);
|
my ($name,$type);
|
|
|
$type='';
|
$type='';
|
if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
|
if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
|
$name= $self->{files}{$file}{contexts}{$line}{value}{name};
|
$name= $self->{files}{$file}{contexts}{$line}{value}{name};
|
if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
|
if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
|
$type=$self->{files}{$file}{contexts}{$line}{value}{type};
|
$type=$self->{files}{$file}{contexts}{$line}{value}{type};
|
$type='module' if ($type eq 'primitive' || $type eq 'macromodule');
|
$type='module' if ($type eq 'primitive' || $type eq 'macromodule');
|
}
|
}
|
return ($name,$type);
|
return ($name,$type);
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_pre_ignore_by_context
|
=head1 get_pre_ignore_by_context
|
|
|
Test if the context is preprocessor ignore.
|
Test if the context is preprocessor ignore.
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - 1 if it is, 0 otherwise
|
Returns: - 1 if it is, 0 otherwise
|
|
|
Example: if ($vdata->get_pre_ignore_by_context($file,$line))..
|
Example: if ($vdata->get_pre_ignore_by_context($file,$line))..
|
|
|
=cut
|
=cut
|
sub get_pre_ignore_by_context{
|
sub get_pre_ignore_by_context{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
|
if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
|
return $self->{files}{$file}{contexts}{$line}{pre_ignore};
|
return $self->{files}{$file}{contexts}{$line}{pre_ignore};
|
}
|
}
|
else {
|
else {
|
return 0;
|
return 0;
|
}
|
}
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_first_instantiator_by_context
|
=head1 get_first_instantiator_by_context
|
|
|
Get the first thing that instantiates this module using the context. The
|
Get the first thing that instantiates this module using the context. The
|
context must be a module_start.
|
context must be a module_start.
|
|
|
Arguments: - file name (for context)
|
Arguments: - file name (for context)
|
- line name (for context)
|
- line name (for context)
|
|
|
Returns: - a 4 element list: instantiating module, file, instance name, line
|
Returns: - a 4 element list: instantiating module, file, instance name, line
|
|
|
Example:
|
Example:
|
@i=$vdata->get_first_instantiator_by_context($f,$l );
|
@i=$vdata->get_first_instantiator_by_context($f,$l );
|
|
|
=cut
|
=cut
|
sub get_first_instantiator_by_context{
|
sub get_first_instantiator_by_context{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
# note: the second exists() checks that the module still exists as
|
# note: the second exists() checks that the module still exists as
|
# it could have been deleted because a duplicate was found
|
# it could have been deleted because a duplicate was found
|
if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
|
if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
|
exists($self->{modules}
|
exists($self->{modules}
|
{$self->{files}{$file}{contexts}{$line}{module_start}}) &&
|
{$self->{files}{$file}{contexts}{$line}{module_start}}) &&
|
exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
|
exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
|
$self->{current_instantiator} =0;
|
$self->{current_instantiator} =0;
|
$self->{current_instantiator_module}=
|
$self->{current_instantiator_module}=
|
$self->{files}{$file}{contexts}{$line}{module_start};
|
$self->{files}{$file}{contexts}{$line}{module_start};
|
return $self->get_next_instantiator();
|
return $self->get_next_instantiator();
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
|
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_inst_on_line
|
=head1 get_inst_on_line
|
|
|
Gets the instance name of a line in a file
|
Gets the instance name of a line in a file
|
|
|
Arguments: - file name
|
Arguments: - file name
|
- line number
|
- line number
|
|
|
Returns: - name if the line has an instance name, 0 otherwise
|
Returns: - name if the line has an instance name, 0 otherwise
|
|
|
Example: if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
|
Example: if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
|
|
|
=cut
|
=cut
|
sub get_inst_on_line{
|
sub get_inst_on_line{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
if ( exists( $self->{files}{$file}{instance_lines}{$line})){
|
if ( exists( $self->{files}{$file}{instance_lines}{$line})){
|
return $self->{files}{$file}{instance_lines}{$line};
|
return $self->{files}{$file}{instance_lines}{$line};
|
}
|
}
|
else {
|
else {
|
return 0;
|
return 0;
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_signal_by_context
|
=head1 get_signal_by_context
|
|
|
Same as get_module_signal but works by specifying a context.
|
Same as get_module_signal but works by specifying a context.
|
|
|
Arguments: - context file name
|
Arguments: - context file name
|
- context line number
|
- context line number
|
- signal name
|
- signal name
|
|
|
Returns: same as get_module_signal
|
Returns: same as get_module_signal
|
|
|
Example:
|
Example:
|
|
|
=cut
|
=cut
|
# get a signal by context - returns: line, a_line, i_line, type, file
|
# get a signal by context - returns: line, a_line, i_line, type, file
|
sub get_signal_by_context{
|
sub get_signal_by_context{
|
my ($self,$file,$cline,$sig) = @_;
|
my ($self,$file,$cline,$sig) = @_;
|
|
|
my $sigp;
|
my $sigp;
|
|
|
# in tasks and functions signals can come from module (m_signals)
|
# in tasks and functions signals can come from module (m_signals)
|
# or from the task or function itself (which gets precedence).
|
# or from the task or function itself (which gets precedence).
|
if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
|
if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
|
print " found signal $sig\n" if $debug;
|
print " found signal $sig\n" if $debug;
|
$sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
|
$sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
|
}
|
}
|
elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
|
elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
|
print " found m_signal $sig\n" if $debug;
|
print " found m_signal $sig\n" if $debug;
|
$sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
|
$sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
|
|
return ($sigp->{line},
|
return ($sigp->{line},
|
$sigp->{a_line},
|
$sigp->{a_line},
|
$sigp->{i_line},
|
$sigp->{i_line},
|
$sigp->{type},
|
$sigp->{type},
|
$sigp->{file},
|
$sigp->{file},
|
$sigp->{posedge},
|
$sigp->{posedge},
|
$sigp->{negedge},
|
$sigp->{negedge},
|
$sigp->{type2},
|
$sigp->{type2},
|
$sigp->{source}{file},
|
$sigp->{source}{file},
|
$sigp->{source}{line},
|
$sigp->{source}{line},
|
$sigp->{range},
|
$sigp->{range},
|
$sigp->{a_file},
|
$sigp->{a_file},
|
$sigp->{i_file},
|
$sigp->{i_file},
|
$sigp->{dimensions});
|
$sigp->{dimensions});
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_t_or_f_by_context
|
=head1 get_t_or_f_by_context
|
|
|
Same as get_modules_t_or_f but works by specifying a context.
|
Same as get_modules_t_or_f but works by specifying a context.
|
|
|
Arguments: - context file name
|
Arguments: - context file name
|
- context line number
|
- context line number
|
- task name
|
- task name
|
|
|
Returns: - same as get_modules_t_or_f
|
Returns: - same as get_modules_t_or_f
|
|
|
Example:
|
Example:
|
|
|
=cut
|
=cut
|
sub get_t_or_f_by_context{
|
sub get_t_or_f_by_context{
|
my ($self,$cfile,$cline,$t_or_f) = @_;
|
my ($self,$cfile,$cline,$t_or_f) = @_;
|
|
|
if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$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},
|
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}{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}{file},
|
$self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
|
$self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_parameter_by_context
|
=head1 get_parameter_by_context
|
|
|
Return the file and line for a named parameter using context
|
Return the file and line for a named parameter using context
|
|
|
Arguments: - context file name
|
Arguments: - context file name
|
- context line number
|
- context line number
|
- parameter name
|
- parameter name
|
|
|
Returns: - file and line of definition
|
Returns: - file and line of definition
|
|
|
Example:
|
Example:
|
|
|
=cut
|
=cut
|
sub get_parameter_by_context{
|
sub get_parameter_by_context{
|
my ($self,$cfile,$cline,$parameter) = @_;
|
my ($self,$cfile,$cline,$parameter) = @_;
|
|
|
if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
|
if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
|
return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
|
return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
|
$self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
|
$self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
###########################################################################
|
###########################################################################
|
|
|
=head1 get_anchors
|
=head1 get_anchors
|
|
|
Get the anchors for a line in a file.
|
Get the anchors for a line in a file.
|
|
|
|
|
Returns: - a list of anchors
|
Returns: - a list of anchors
|
|
|
Example: foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
|
Example: foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
|
|
|
=cut
|
=cut
|
sub get_anchors{
|
sub get_anchors{
|
my ($self,$file,$line) = @_;
|
my ($self,$file,$line) = @_;
|
|
|
if (exists($self->{files}{$file}{anchors}{$line})) {
|
if (exists($self->{files}{$file}{anchors}{$line})) {
|
return @{$self->{files}{$file}{anchors}{$line}};
|
return @{$self->{files}{$file}{anchors}{$line}};
|
}
|
}
|
else {
|
else {
|
return ();
|
return ();
|
}
|
}
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 expand_defines
|
=head1 expand_defines
|
|
|
Expand the defines in a line of verilog code. for best use this
|
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
|
should be called line by line, so that the defines get the correct
|
values when defines are defined multiple times
|
values when defines are defined multiple times
|
|
|
Arguments: - a pointer to the string to expand the defines in
|
Arguments: - a pointer to the string to expand the defines in
|
- the file the line is from
|
- the file the line is from
|
- the line number of the line
|
- the line number of the line
|
|
|
Returns: - nothing
|
Returns: - nothing
|
|
|
Example: $vdata->expand_defines(\$line_to_expand,$file,$line);
|
Example: $vdata->expand_defines(\$line_to_expand,$file,$line);
|
|
|
=cut
|
=cut
|
###############################################################################
|
###############################################################################
|
#
|
#
|
sub expand_defines {
|
sub expand_defines {
|
my ($self,$bufp,$file,$line) = @_;
|
my ($self,$bufp,$file,$line) = @_;
|
|
|
if (exists($self->{files}{$file}{define_lines}{$line})) {
|
if (exists($self->{files}{$file}{define_lines}{$line})) {
|
# do not expand on a `define line - it doesn't make sense to do so
|
# 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
|
# as the substitution of defines in the value only occurs at the
|
# time of use when they could have different values!
|
# time of use when they could have different values!
|
return;
|
return;
|
}
|
}
|
|
|
|
|
while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
|
while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
|
my $b = $1;
|
my $b = $1;
|
my $d = $2;
|
my $d = $2;
|
my $dq = quotemeta($d);
|
my $dq = quotemeta($d);
|
my $v;
|
my $v;
|
if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
|
if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
|
$$bufp =~ s/\`$dq/$v/;
|
$$bufp =~ s/\`$dq/$v/;
|
}
|
}
|
else {
|
else {
|
$$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
|
$$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
|
}
|
}
|
|
|
}
|
}
|
$$bufp =~ s/_BaCkQuOtE_/\`/g;
|
$$bufp =~ s/_BaCkQuOtE_/\`/g;
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 verilog_gatetype_keywords
|
=head1 verilog_gatetype_keywords
|
|
|
|
|
Returns: - a list of verilog gatetype keywords
|
Returns: - a list of verilog gatetype keywords
|
|
|
Example: @keywords = rvp->verilog_gatetype_keywords();
|
Example: @keywords = rvp->verilog_gatetype_keywords();
|
|
|
=cut
|
=cut
|
sub verilog_gatetype_keywords {
|
sub verilog_gatetype_keywords {
|
return (@verilog_gatetype_keywords);
|
return (@verilog_gatetype_keywords);
|
}
|
}
|
###########################################################################
|
###########################################################################
|
|
|
=head1 verilog_compiler_keywords
|
=head1 verilog_compiler_keywords
|
|
|
Returns: - a list of verilog compiler keywords
|
Returns: - a list of verilog compiler keywords
|
|
|
Example: @keywords = rvp->verilog_compiler_keywords();
|
Example: @keywords = rvp->verilog_compiler_keywords();
|
|
|
=cut
|
=cut
|
sub verilog_compiler_keywords {
|
sub verilog_compiler_keywords {
|
return (@verilog_compiler_keywords);
|
return (@verilog_compiler_keywords);
|
}
|
}
|
###########################################################################
|
###########################################################################
|
|
|
=head1 verilog_signal_keywords
|
=head1 verilog_signal_keywords
|
|
|
Returns: - a list of verilog signal keywords
|
Returns: - a list of verilog signal keywords
|
|
|
Example: @keywords = rvp->verilog_signal_keywords();
|
Example: @keywords = rvp->verilog_signal_keywords();
|
|
|
=cut
|
=cut
|
sub verilog_signal_keywords {
|
sub verilog_signal_keywords {
|
return (@verilog_signal_keywords);
|
return (@verilog_signal_keywords);
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 chunk_read_init
|
=head1 chunk_read_init
|
|
|
Initialise a file for chunk reading (see chunk_read for more
|
Initialise a file for chunk reading (see chunk_read for more
|
details). It actually reads the whole file into a string, which
|
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
|
chunk_read then reads a chunk at a time. The file is closed before
|
chuck_read_init returns.
|
chuck_read_init returns.
|
|
|
Arguments: - the file to read (with path if needed)
|
Arguments: - the file to read (with path if needed)
|
- tabstop: 0 = leave tabs alone
|
- tabstop: 0 = leave tabs alone
|
N = turn tabs spaces with each tabstop=N
|
N = turn tabs spaces with each tabstop=N
|
Returns: - a handle to pass to chunk_read or 0 if file open fails
|
Returns: - a handle to pass to chunk_read or 0 if file open fails
|
|
|
Example:
|
Example:
|
my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
|
my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
|
|
|
=cut
|
=cut
|
sub chunk_read_init {
|
sub chunk_read_init {
|
|
|
my ($class,$f,$tabstop) = @_;
|
my ($class,$f,$tabstop) = @_;
|
local (*F);
|
local (*F);
|
|
|
open(F,"<$f") || return 0;
|
open(F,"<$f") || return 0;
|
|
|
my $chunk = { type => "",
|
my $chunk = { type => "",
|
text => "",
|
text => "",
|
isANewLine => 0,
|
isANewLine => 0,
|
isStart => 0,
|
isStart => 0,
|
isEnd => 1 ,
|
isEnd => 1 ,
|
line => 0 };
|
line => 0 };
|
|
|
my $this = { chunk => $chunk ,
|
my $this = { chunk => $chunk ,
|
tabstop => $tabstop ,
|
tabstop => $tabstop ,
|
linebuf => "" ,
|
linebuf => "" ,
|
state => 0 ,
|
state => 0 ,
|
fh => *F };
|
fh => *F };
|
return $this;
|
return $this;
|
}
|
}
|
|
|
###########################################################################
|
###########################################################################
|
|
|
=head1 chunk_read
|
=head1 chunk_read
|
|
|
Reads verilog a chunk at a time. The file is opened using
|
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
|
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.
|
time. A chunk is a line or part of a line that is all the same type.
|
|
|
The types are:
|
The types are:
|
comment - either // or /* */ comment
|
comment - either // or /* */ comment
|
attribute - verilog 2001 (* *) atribute
|
attribute - verilog 2001 (* *) atribute
|
include - a line containing `include "file"
|
include - a line containing `include "file"
|
string - a string
|
string - a string
|
code - anything else (verilog code, defines, compliler keywords)
|
code - anything else (verilog code, defines, compliler keywords)
|
|
|
Nothing is removed from the file, so if each chunk is printed after being read
|
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.
|
you will end up with exactly the same file as you put in.
|
|
|
Arguments: - handle (from chunk_read_init)
|
Arguments: - handle (from chunk_read_init)
|
|
|
Returns: - 0 at the end of file, or a hash ref with the following keys:
|
Returns: - 0 at the end of file, or a hash ref with the following keys:
|
type - one of the types (see above)
|
type - one of the types (see above)
|
text - the text read from the file
|
text - the text read from the file
|
line - the line number the text is on
|
line - the line number the text is on
|
isANewLine - true if chunk is the first chunk of the line
|
isANewLine - true if chunk is the first chunk of the line
|
isStart - true if the chunk is the start (eg "/*..." for
|
isStart - true if the chunk is the start (eg "/*..." for
|
a comment )
|
a comment )
|
isEnd - true if the chunk is the end ( eg "*/" )
|
isEnd - true if the chunk is the end ( eg "*/" )
|
NOTE: isEnd is set to undefined for a
|
NOTE: isEnd is set to undefined for a
|
type="code" that ends in a newline. This is
|
type="code" that ends in a newline. This is
|
because chunk_read doesn't know if the code is
|
because chunk_read doesn't know if the code is
|
ending or not. If you need to know in this case
|
ending or not. If you need to know in this case
|
you can read the next chunk and see what type it is.
|
you can read the next chunk and see what type it is.
|
|
|
Example:
|
Example:
|
my $chunkRead = rvp->chunk_read_init($f,0);
|
my $chunkRead = rvp->chunk_read_init($f,0);
|
while ($chunk = rvp->chunk_read($chunkRead)) {
|
while ($chunk = rvp->chunk_read($chunkRead)) {
|
print $chunk->{text} unless $chunk->{type} eq "comment";
|
print $chunk->{text} unless $chunk->{type} eq "comment";
|
}
|
}
|
|
|
=cut
|
=cut
|
sub chunk_read {
|
sub chunk_read {
|
my ($class,$this) = @_;
|
my ($class,$this) = @_;
|
|
|
my $chunk = $this->{chunk};
|
my $chunk = $this->{chunk};
|
$chunk->{isStart} = $chunk->{isEnd};
|
$chunk->{isStart} = $chunk->{isEnd};
|
$chunk->{isEnd} = 0;
|
$chunk->{isEnd} = 0;
|
$chunk->{isANewLine} = 0;
|
$chunk->{isANewLine} = 0;
|
|
|
if ( $this->{linebuf} eq "" ) {
|
if ( $this->{linebuf} eq "" ) {
|
if (!defined($this->{linebuf} = readline($this->{fh}))) {
|
if (!defined($this->{linebuf} = readline($this->{fh}))) {
|
close($this->{fh});
|
close($this->{fh});
|
return 0;
|
return 0;
|
}
|
}
|
$chunk->{isANewLine} = 1;
|
$chunk->{isANewLine} = 1;
|
$chunk->{line}++;
|
$chunk->{line}++;
|
if ($this->{tabstop}!=0) {
|
if ($this->{tabstop}!=0) {
|
# 1 while is some stupid perl thing meaning while (cond) {} may be a bit faster?
|
# 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 while ($this->{linebuf} =~ s/(^|\n)([^\t\n]*)(\t+)/
|
$1. $2 . (" " x ($this->{tabstop} * length($3) -
|
$1. $2 . (" " x ($this->{tabstop} * length($3) -
|
(length($2) % $this->{tabstop})))
|
(length($2) % $this->{tabstop})))
|
/gsex);
|
/gsex);
|
}
|
}
|
}
|
}
|
|
|
STATE_SWITCH:
|
STATE_SWITCH:
|
if ( $this->{state} == 0 ) {
|
if ( $this->{state} == 0 ) {
|
$chunk->{type} = "code";
|
$chunk->{type} = "code";
|
if ( $this->{linebuf} =~
|
if ( $this->{linebuf} =~
|
s%^(.*?)((/\*)| # anything followed by /* comment
|
s%^(.*?)((/\*)| # anything followed by /* comment
|
(//)| # or // comment
|
(//)| # or // comment
|
(\(\*(?!\s*\)))| # or (* attribute (but not (*)
|
(\(\*(?!\s*\)))| # or (* attribute (but not (*)
|
(\`include\s)| # or `include
|
(\`include\s)| # or `include
|
(\")) # or start of string
|
(\")) # or start of string
|
%$2%ox ) {
|
%$2%ox ) {
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
$chunk->{text} = $1;
|
$chunk->{text} = $1;
|
if (defined($3)) {
|
if (defined($3)) {
|
$this->{state} = 1; # long comment
|
$this->{state} = 1; # long comment
|
}
|
}
|
elsif (defined($4)) {
|
elsif (defined($4)) {
|
$this->{state} = 2; # short comment
|
$this->{state} = 2; # short comment
|
}
|
}
|
elsif (defined($5)) {
|
elsif (defined($5)) {
|
$this->{state} = 3; # attribute
|
$this->{state} = 3; # attribute
|
}
|
}
|
elsif (defined($6)) {
|
elsif (defined($6)) {
|
$this->{state} = 4; # include
|
$this->{state} = 4; # include
|
}
|
}
|
elsif (defined($7)) {
|
elsif (defined($7)) {
|
$this->{state} = 5; # string
|
$this->{state} = 5; # string
|
}
|
}
|
else {
|
else {
|
die "chunk_read internal error!";
|
die "chunk_read internal error!";
|
}
|
}
|
if (!$chunk->{text}) {
|
if (!$chunk->{text}) {
|
# this happens if we are in state code and a new line
|
# this happens if we are in state code and a new line
|
# starts with something that isn't code. So we change
|
# starts with something that isn't code. So we change
|
# and go back to the top.
|
# and go back to the top.
|
$chunk->{isStart} = 1;
|
$chunk->{isStart} = 1;
|
$chunk->{isEnd} = 0;
|
$chunk->{isEnd} = 0;
|
goto STATE_SWITCH;
|
goto STATE_SWITCH;
|
}
|
}
|
}
|
}
|
else {
|
else {
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{text} = $this->{linebuf};
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
# in this case we might be at end, but we don't really know!
|
# in this case we might be at end, but we don't really know!
|
$chunk->{isEnd} = undef;
|
$chunk->{isEnd} = undef;
|
}
|
}
|
}
|
}
|
elsif ( $this->{state} == 1 ) {
|
elsif ( $this->{state} == 1 ) {
|
$chunk->{type} = "comment";
|
$chunk->{type} = "comment";
|
# this first test is needed to work so /*/ */ works
|
# this first test is needed to work so /*/ */ works
|
if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
|
if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
|
$chunk->{text} = "/*";
|
$chunk->{text} = "/*";
|
}
|
}
|
else {
|
else {
|
$chunk->{text} = "";
|
$chunk->{text} = "";
|
}
|
}
|
if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) { # anything followed by */
|
if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) { # anything followed by */
|
$chunk->{text} .= $1;
|
$chunk->{text} .= $1;
|
$this->{state} = 0;
|
$this->{state} = 0;
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
}
|
}
|
else {
|
else {
|
$chunk->{text} .= $this->{linebuf};
|
$chunk->{text} .= $this->{linebuf};
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
}
|
}
|
}
|
}
|
elsif ( $this->{state} == 2 ) {
|
elsif ( $this->{state} == 2 ) {
|
$chunk->{type} = "comment";
|
$chunk->{type} = "comment";
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
if ( $chunk->{text} =~ s/\n$// ) {
|
if ( $chunk->{text} =~ s/\n$// ) {
|
$this->{linebuf} = "\n";
|
$this->{linebuf} = "\n";
|
}
|
}
|
$this->{state} = 0;
|
$this->{state} = 0;
|
}
|
}
|
elsif ( $this->{state} == 3 ) {
|
elsif ( $this->{state} == 3 ) {
|
$chunk->{type} = "attribute";
|
$chunk->{type} = "attribute";
|
if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) { # anything followed by *)
|
if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) { # anything followed by *)
|
$chunk->{text} = $1;
|
$chunk->{text} = $1;
|
$this->{state} = 0;
|
$this->{state} = 0;
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
}
|
}
|
else {
|
else {
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{text} = $this->{linebuf};
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
}
|
}
|
}
|
}
|
elsif ( $this->{state} == 4 ) {
|
elsif ( $this->{state} == 4 ) {
|
$chunk->{type} = "include";
|
$chunk->{type} = "include";
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {
|
if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {
|
$chunk->{text} = $1;
|
$chunk->{text} = $1;
|
$this->{state} = 0;
|
$this->{state} = 0;
|
}
|
}
|
else {
|
else {
|
# this is an error - just return the line as code - the parser will
|
# this is an error - just return the line as code - the parser will
|
# report the error
|
# report the error
|
$chunk->{type} = 0;
|
$chunk->{type} = 0;
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{text} = $this->{linebuf};
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
}
|
}
|
}
|
}
|
elsif ( $this->{state} == 5 ) {
|
elsif ( $this->{state} == 5 ) {
|
$chunk->{type} = "string";
|
$chunk->{type} = "string";
|
# string all on one line
|
# string all on one line
|
if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
|
if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
|
$chunk->{text} = $1;
|
$chunk->{text} = $1;
|
$this->{state} = 0;
|
$this->{state} = 0;
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
}
|
}
|
# end of multiline string (doesn't start with quote)
|
# end of multiline string (doesn't start with quote)
|
elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
|
elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
|
$chunk->{text} = $1;
|
$chunk->{text} = $1;
|
$this->{state} = 0;
|
$this->{state} = 0;
|
$chunk->{isEnd} = 1;
|
$chunk->{isEnd} = 1;
|
}
|
}
|
# middle of multiline string
|
# middle of multiline string
|
else {
|
else {
|
$chunk->{text} = $this->{linebuf};
|
$chunk->{text} = $this->{linebuf};
|
$this->{linebuf} = "";
|
$this->{linebuf} = "";
|
}
|
}
|
}
|
}
|
|
|
return $chunk;
|
return $chunk;
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# RVP internal functions from now on.... (they all start with _ to
|
# RVP internal functions from now on.... (they all start with _ to
|
# let you know they are internal
|
# let you know they are internal
|
###############################################################################
|
###############################################################################
|
|
|
###############################################################################
|
###############################################################################
|
# search a file, putting the data in $self
|
# search a file, putting the data in $self
|
# Note: be careful coding in the main loop... there are a few optimisations
|
# 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
|
# which result in big chunks of code being skipped if the line does not
|
# contain certain characters (eg ' " / *)
|
# contain certain characters (eg ' " / *)
|
sub _search {
|
sub _search {
|
my ($self,$f,$inc_dirs) = @_;
|
my ($self,$f,$inc_dirs) = @_;
|
|
|
my $verilog_compiler_keywords_regexp = "(?:" .
|
my $verilog_compiler_keywords_regexp = "(?:" .
|
join("|",@verilog_compiler_keywords) .
|
join("|",@verilog_compiler_keywords) .
|
")";
|
")";
|
|
|
|
|
my $file=_ffile($f);
|
my $file=_ffile($f);
|
_init_file($self->{files},$f);
|
_init_file($self->{files},$f);
|
|
|
print "Searching $f " unless $quiet;
|
print "Searching $f " unless $quiet;
|
my $chunkRead= rvp->chunk_read_init($f,0) ||
|
my $chunkRead= rvp->chunk_read_init($f,0) ||
|
die "Error: can not open file $f to read: $!\n";
|
die "Error: can not open file $f to read: $!\n";
|
my $file_dir = dirname($f);
|
my $file_dir = dirname($f);
|
|
|
my $rs = {};
|
my $rs = {};
|
$rs->{modules} = $self->{modules};
|
$rs->{modules} = $self->{modules};
|
$rs->{files} = $self->{files};
|
$rs->{files} = $self->{files};
|
$rs->{unres_mod} = $self->{unresolved_modules};
|
$rs->{unres_mod} = $self->{unresolved_modules};
|
|
|
$rs->{module} = '';
|
$rs->{module} = '';
|
$rs->{function} = '';
|
$rs->{function} = '';
|
$rs->{task} = '';
|
$rs->{task} = '';
|
$rs->{t} = undef; # temp store
|
$rs->{t} = undef; # temp store
|
$rs->{p} = undef;
|
$rs->{p} = undef;
|
|
|
my $printline = 1000;
|
my $printline = 1000;
|
|
|
my $ps = {};
|
my $ps = {};
|
my $nest=0;
|
my $nest=0;
|
my $nest_at_ignore;
|
my $nest_at_ignore;
|
my @ignore_from_elsif;
|
my @ignore_from_elsif;
|
my $ignoring=0;
|
my $ignoring=0;
|
my @fileStack =();
|
my @fileStack =();
|
my $pp_ignore;
|
my $pp_ignore;
|
my $chunk;
|
my $chunk;
|
while (1) {
|
while (1) {
|
while ($chunk = rvp->chunk_read($chunkRead)) {
|
while ($chunk = rvp->chunk_read($chunkRead)) {
|
$self->{files}{$file}{lines} = $chunk->{line};
|
$self->{files}{$file}{lines} = $chunk->{line};
|
if ($chunk->{line}>$printline && !$quiet) {
|
if ($chunk->{line}>$printline && !$quiet) {
|
$printline+=1000;
|
$printline+=1000;
|
$|=1; # turn on autoflush
|
$|=1; # turn on autoflush
|
print ".";
|
print ".";
|
$|=0 unless $debug; # turn off autoflush
|
$|=0 unless $debug; # turn off autoflush
|
}
|
}
|
|
|
# deal quickly with blank lines
|
# deal quickly with blank lines
|
if ( $chunk->{text} =~ m/^\s*\n/ ) {
|
if ( $chunk->{text} =~ m/^\s*\n/ ) {
|
next;
|
next;
|
}
|
}
|
|
|
|
|
if ( $chunk->{type} eq "code" ) {
|
if ( $chunk->{type} eq "code" ) {
|
|
|
|
|
####################################################
|
####################################################
|
# Optimisation: if there are no `
|
# Optimisation: if there are no `
|
# we can parse the line now
|
# we can parse the line now
|
if ( $chunk->{text} !~ m|[\`]| ) {
|
if ( $chunk->{text} !~ m|[\`]| ) {
|
if ($nest && $ignoring) {
|
if ($nest && $ignoring) {
|
next;
|
next;
|
}
|
}
|
$self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
|
$self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
|
next;
|
next;
|
}
|
}
|
|
|
# handle ifdefs
|
# handle ifdefs
|
if ($nest && $ignoring) {
|
if ($nest && $ignoring) {
|
if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
|
if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
|
print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
|
$nest++;
|
$nest++;
|
}
|
}
|
elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
|
elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
|
print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
|
if ($1 eq 'else' ||
|
if ($1 eq 'else' ||
|
_parsing_is_defined($self->{defines},$2,
|
_parsing_is_defined($self->{defines},$2,
|
$file,$chunk->{line})) {
|
$file,$chunk->{line})) {
|
# true elsif or plain else
|
# true elsif or plain else
|
if ($nest == $nest_at_ignore &&
|
if ($nest == $nest_at_ignore &&
|
!$ignore_from_elsif[$nest]) {
|
!$ignore_from_elsif[$nest]) {
|
$ignoring=0;
|
$ignoring=0;
|
$$pp_ignore = $chunk->{line};
|
$$pp_ignore = $chunk->{line};
|
}
|
}
|
}
|
}
|
}
|
}
|
elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
|
elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
|
print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
|
if ($nest == $nest_at_ignore) {
|
if ($nest == $nest_at_ignore) {
|
$ignoring=0;
|
$ignoring=0;
|
$$pp_ignore = $chunk->{line};
|
$$pp_ignore = $chunk->{line};
|
}
|
}
|
$nest--;
|
$nest--;
|
}
|
}
|
next;
|
next;
|
}
|
}
|
# handle the case where the endif is on the same line as the ifdef
|
# 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)
|
# (note: generally I only accept endif at the start of a line)
|
if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
|
if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
|
print "$file: ifdef and endif on same line\n" if $debug;
|
print "$file: ifdef and endif on same line\n" if $debug;
|
my $is_defined = _parsing_is_defined($self->{defines},$2,
|
my $is_defined = _parsing_is_defined($self->{defines},$2,
|
$file,$chunk->{line});
|
$file,$chunk->{line});
|
if ( (($1 eq 'ifdef' ) && !$is_defined) ||
|
if ( (($1 eq 'ifdef' ) && !$is_defined) ||
|
(($1 eq 'ifndef') && $is_defined)) {
|
(($1 eq 'ifndef') && $is_defined)) {
|
# replace ifdef with nothing
|
# replace ifdef with nothing
|
$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
|
$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
|
}
|
}
|
else {
|
else {
|
# replace ifdef with what is between the ifdef and endif
|
# replace ifdef with what is between the ifdef and endif
|
$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
|
$chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
|
}
|
}
|
}
|
}
|
if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
|
if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
|
$nest++;
|
$nest++;
|
print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
|
my $is_defined = _parsing_is_defined($self->{defines},$2,
|
my $is_defined = _parsing_is_defined($self->{defines},$2,
|
$file,$chunk->{line});
|
$file,$chunk->{line});
|
if ( (($1 eq 'ifdef' ) && !$is_defined) ||
|
if ( (($1 eq 'ifdef' ) && !$is_defined) ||
|
(($1 eq 'ifndef') && $is_defined)) {
|
(($1 eq 'ifndef') && $is_defined)) {
|
$ignoring=1;
|
$ignoring=1;
|
$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
|
$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
|
$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
|
$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
|
$nest_at_ignore=$nest;
|
$nest_at_ignore=$nest;
|
$ignore_from_elsif[$nest]=0;
|
$ignore_from_elsif[$nest]=0;
|
}
|
}
|
next;
|
next;
|
}
|
}
|
if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
|
if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
|
print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
|
if ($nest) {
|
if ($nest) {
|
$ignoring=1;
|
$ignoring=1;
|
$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
|
$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
|
$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
|
$pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
|
$nest_at_ignore=$nest;
|
$nest_at_ignore=$nest;
|
# an ignore from an elsif means you will never stop ignoring
|
# an ignore from an elsif means you will never stop ignoring
|
# at this nest level
|
# at this nest level
|
$ignore_from_elsif[$nest]=($1 ne 'else');
|
$ignore_from_elsif[$nest]=($1 ne 'else');
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
|
$self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
|
}
|
}
|
next;
|
next;
|
}
|
}
|
if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
|
if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
|
print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
|
print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
|
if ($nest) {
|
if ($nest) {
|
$nest--;
|
$nest--;
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
|
$self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
|
}
|
}
|
next;
|
next;
|
}
|
}
|
|
|
# match define. Note: /s makes the .* match the \n too
|
# match define. Note: /s makes the .* match the \n too
|
if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
|
if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
|
my $def = $1;
|
my $def = $1;
|
my $rest = defined($2)?$2:'';
|
my $rest = defined($2)?$2:'';
|
my $defLine = $chunk->{line};
|
my $defLine = $chunk->{line};
|
$self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
|
$self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
|
|
|
# _parsing_expand_defines is called to register the use
|
# _parsing_expand_defines is called to register the use
|
# of any multiplely defined defines in the value part of
|
# of any multiplely defined defines in the value part of
|
# the define
|
# the define
|
my $tmpValue=$rest;
|
my $tmpValue=$rest;
|
$self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
|
$self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
|
|
|
# handle multiline defines: read more stuff if line ends in backslash
|
# handle multiline defines: read more stuff if line ends in backslash
|
# (revisit: verilog spec says leave the newline in the value)
|
# (revisit: verilog spec says leave the newline in the value)
|
# also keep adding stuff to value until it ends in a newline or comment
|
# also keep adding stuff to value until it ends in a newline or comment
|
# because strings are seperated out, `define T $display("test")
|
# because strings are seperated out, `define T $display("test")
|
# is delivered as chunks '`define T $display(' ,'"test"', ')\n'
|
# is delivered as chunks '`define T $display(' ,'"test"', ')\n'
|
while ( (($rest =~ s|\\\n|| ) || ($rest !~ m/\n$/) )
|
while ( (($rest =~ s|\\\n|| ) || ($rest !~ m/\n$/) )
|
&& ($chunk = rvp->chunk_read($chunkRead))) {
|
&& ($chunk = rvp->chunk_read($chunkRead))) {
|
last if $chunk->{type} eq "comment";
|
last if $chunk->{type} eq "comment";
|
$rest .= $chunk->{text};
|
$rest .= $chunk->{text};
|
$self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
|
$self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
|
# _parsing_expand_defines call: see comment ~15 lines back
|
# _parsing_expand_defines call: see comment ~15 lines back
|
my $tmpValue=$chunk->{text};
|
my $tmpValue=$chunk->{text};
|
$self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
|
$self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
|
}
|
}
|
my $value = $rest;
|
my $value = $rest;
|
$value =~ s/^\s+(.*)(\n)?/$1/;
|
$value =~ s/^\s+(.*)(\n)?/$1/;
|
|
|
print " Found in $file line $defLine : define $def = $value\n"
|
print " Found in $file line $defLine : define $def = $value\n"
|
if $debug;
|
if $debug;
|
_add_define($self->{defines}, $def , $value , $file, $defLine );
|
_add_define($self->{defines}, $def , $value , $file, $defLine );
|
_add_anchor($self->{files}{$file}{anchors},$defLine,"");
|
_add_anchor($self->{files}{$file}{anchors},$defLine,"");
|
# Don't substitute now: [defines] shall be substituted after the
|
# Don't substitute now: [defines] shall be substituted after the
|
# original macro is substituted, not when it is defined(1364-2001 pg353)
|
# original macro is substituted, not when it is defined(1364-2001 pg353)
|
next;
|
next;
|
}
|
}
|
|
|
if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
|
if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
|
_undef_define($self->{defines},$1);
|
_undef_define($self->{defines},$1);
|
print " Found at line $chunk->{line} : undef $1\n" if $debug;
|
print " Found at line $chunk->{line} : undef $1\n" if $debug;
|
next;
|
next;
|
}
|
}
|
|
|
if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
|
if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
|
next;
|
next;
|
}
|
}
|
$self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
|
$self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
|
|
|
# Note this is called from two other places (optimisations)
|
# Note this is called from two other places (optimisations)
|
$self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
|
$self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
|
}
|
}
|
elsif ( $chunk->{type} eq "include" ) {
|
elsif ( $chunk->{type} eq "include" ) {
|
if ($nest && $ignoring) {
|
if ($nest && $ignoring) {
|
next;
|
next;
|
}
|
}
|
|
|
$chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
|
$chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
|
# revisit - need to check for recursive includes
|
# revisit - need to check for recursive includes
|
print " Found at line $chunk->{line} : include $1\n" if $debug;
|
print " Found at line $chunk->{line} : include $1\n" if $debug;
|
$self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
|
$self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
|
my $inc_file = $1;
|
my $inc_file = $1;
|
my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
|
my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
|
if ($inc_file_and_path) {
|
if ($inc_file_and_path) {
|
push(@fileStack,$chunkRead,$f);
|
push(@fileStack,$chunkRead,$f);
|
$f = $inc_file_and_path;
|
$f = $inc_file_and_path;
|
$file=_ffile($f);
|
$file=_ffile($f);
|
$file_dir = dirname($f);
|
$file_dir = dirname($f);
|
|
|
if (!exists($self->{files}{$file})) {
|
if (!exists($self->{files}{$file})) {
|
_init_file($self->{files},$f);
|
_init_file($self->{files},$f);
|
if (exists($rs->{modules}{$rs->{module}})) {
|
if (exists($rs->{modules}{$rs->{module}})) {
|
$self->{files}{$file}{contexts}{"1"}{value} =
|
$self->{files}{$file}{contexts}{"1"}{value} =
|
$rs->{modules}{$rs->{module}};
|
$rs->{modules}{$rs->{module}};
|
}
|
}
|
}
|
}
|
print "\n Include: $f " unless $quiet;
|
print "\n Include: $f " unless $quiet;
|
$chunkRead=rvp->chunk_read_init($f,0);
|
$chunkRead=rvp->chunk_read_init($f,0);
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
|
$self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
|
}
|
}
|
next;
|
next;
|
}
|
}
|
|
|
if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
|
if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
|
$$pp_ignore = $chunk->{line};
|
$$pp_ignore = $chunk->{line};
|
}
|
}
|
}
|
}
|
# check if we were included from another file
|
# check if we were included from another file
|
if (0==scalar(@fileStack)) {
|
if (0==scalar(@fileStack)) {
|
print "Stack is empty\n" if $debug;
|
print "Stack is empty\n" if $debug;
|
last;
|
last;
|
}
|
}
|
else {
|
else {
|
$f = pop(@fileStack);
|
$f = pop(@fileStack);
|
$chunkRead = pop(@fileStack);
|
$chunkRead = pop(@fileStack);
|
$file = _ffile($f);
|
$file = _ffile($f);
|
$file_dir = dirname($f);
|
$file_dir = dirname($f);
|
print "\n Back to $f" unless $quiet;
|
print "\n Back to $f" unless $quiet;
|
}
|
}
|
}
|
}
|
|
|
print "\n" unless $quiet;
|
print "\n" unless $quiet;
|
|
|
$self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
|
$self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
|
|
|
}
|
}
|
|
|
sub _open_file {
|
sub _open_file {
|
my ($f) = @_;
|
my ($f) = @_;
|
local (*F);
|
local (*F);
|
|
|
print "Searching $f " unless $quiet;
|
print "Searching $f " unless $quiet;
|
open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
|
open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
|
return *F;
|
return *F;
|
}
|
}
|
|
|
# only for use while parsing - returns the last defined value
|
# only for use while parsing - returns the last defined value
|
# in a multiple define case, and also sets up the {used} info
|
# in a multiple define case, and also sets up the {used} info
|
# for use later when querying the database
|
# for use later when querying the database
|
# returns ($value,$errcode)
|
# returns ($value,$errcode)
|
# where $errcode = 0 value ok
|
# where $errcode = 0 value ok
|
# 1 value never defined
|
# 1 value never defined
|
# 2 value has been undefined
|
# 2 value has been undefined
|
sub _parsing_get_define_value {
|
sub _parsing_get_define_value {
|
my ($defines,$define,$file,$line) = @_;
|
my ($defines,$define,$file,$line) = @_;
|
|
|
if (!exists( $defines->{$define} )) {
|
if (!exists( $defines->{$define} )) {
|
return ('',1);
|
return ('',1);
|
}
|
}
|
my $index = 0;
|
my $index = 0;
|
my $dh = $defines->{$define};
|
my $dh = $defines->{$define};
|
|
|
if ( 1 < @{$dh->{defined}} ) {
|
if ( 1 < @{$dh->{defined}} ) {
|
$index = $#{$dh->{defined}};
|
$index = $#{$dh->{defined}};
|
|
|
$dh->{used}{$file}{$line} = $index;
|
$dh->{used}{$file}{$line} = $index;
|
}
|
}
|
|
|
if ($dh->{defined}[$index]{undefed}) {
|
if ($dh->{defined}[$index]{undefed}) {
|
$dh->{used}{$file}{$line} = "XX";
|
$dh->{used}{$file}{$line} = "XX";
|
return ('',2);
|
return ('',2);
|
}
|
}
|
|
|
return ( $dh->{defined}[$index]{value} , 0 );
|
return ( $dh->{defined}[$index]{value} , 0 );
|
}
|
}
|
|
|
sub _parsing_is_defined {
|
sub _parsing_is_defined {
|
my ($defines,$define,$file,$line) = @_;
|
my ($defines,$define,$file,$line) = @_;
|
|
|
my $v;
|
my $v;
|
my $errcode;
|
my $errcode;
|
($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
|
($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
|
if ( ($errcode == 1) || # never defined
|
if ( ($errcode == 1) || # never defined
|
($errcode == 2) ) { # defined then undefed
|
($errcode == 2) ) { # defined then undefed
|
return 0;
|
return 0;
|
}
|
}
|
elsif ($errcode == 0) {
|
elsif ($errcode == 0) {
|
return 1;
|
return 1;
|
}
|
}
|
else {
|
else {
|
die "parsing_is_defined internal error code=$errcode";
|
die "parsing_is_defined internal error code=$errcode";
|
}
|
}
|
}
|
}
|
|
|
sub _undef_define {
|
sub _undef_define {
|
my ($defines,$define) = @_;
|
my ($defines,$define) = @_;
|
|
|
if (exists( $defines->{$define} )) {
|
if (exists( $defines->{$define} )) {
|
my $index = $#{$defines->{$define}{defined}};
|
my $index = $#{$defines->{$define}{defined}};
|
$defines->{$define}{defined}[$index]{undefed} = 1;
|
$defines->{$define}{defined}[$index]{undefed} = 1;
|
}
|
}
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# for best use this should be called line by line, so that the
|
# for best use this should be called line by line, so that the
|
# defines get the correct values when defines are defined multiple
|
# defines get the correct values when defines are defined multiple
|
# times
|
# times
|
# - this function is only used during the initial parsing of the files
|
# - 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 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
|
# it also expands on define lines (used to register the use of multiple
|
# define defines) which expand_defines doesn't
|
# define defines) which expand_defines doesn't
|
#
|
#
|
sub _parsing_expand_defines {
|
sub _parsing_expand_defines {
|
my ($self,$bufp,$file,$line) = @_;
|
my ($self,$bufp,$file,$line) = @_;
|
|
|
my $defines = $self->{defines};
|
my $defines = $self->{defines};
|
while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
|
while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
|
my $b = $1;
|
my $b = $1;
|
my $d = $2;
|
my $d = $2;
|
my $dq = quotemeta($d);
|
my $dq = quotemeta($d);
|
my $v;
|
my $v;
|
my $errCode=0;
|
my $errCode=0;
|
($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
|
($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
|
|
|
if ($errCode == 0) { # no error
|
if ($errCode == 0) { # no error
|
$$bufp =~ s/\`$dq/$v/;
|
$$bufp =~ s/\`$dq/$v/;
|
}
|
}
|
else {
|
else {
|
if ($errCode == 2) { # defined but then undefed
|
if ($errCode == 2) { # defined but then undefed
|
$self->_add_warning("$file:$line: define `$d used after undef");
|
$self->_add_warning("$file:$line: define `$d used after undef");
|
$$bufp =~ s/\`$dq//;
|
$$bufp =~ s/\`$dq//;
|
}
|
}
|
elsif ($b =~ m/^\s*$/) {
|
elsif ($b =~ m/^\s*$/) {
|
$self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
|
$self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
|
$$bufp='';
|
$$bufp='';
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$file:$line: found undefined define `$d");
|
$self->_add_warning("$file:$line: found undefined define `$d");
|
$$bufp =~ s/\`$dq//;
|
$$bufp =~ s/\`$dq//;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Look through all the include/library directories for an include/library file
|
# Look through all the include/library directories for an include/library file
|
# optional $file_dir is used when including - here a relative path is
|
# 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
|
# relative to the file doing the including, so check this it checks this
|
sub _scan_dirs {
|
sub _scan_dirs {
|
my ($fname,$inc_dirs,$file_dir) = @_;
|
my ($fname,$inc_dirs,$file_dir) = @_;
|
my ($dir);
|
my ($dir);
|
|
|
if ( $fname =~ m|^/| ) { # an absolute path
|
if ( $fname =~ m|^/| ) { # an absolute path
|
return "$fname" if ( -r "$fname" && ! -d "$fname");
|
return "$fname" if ( -r "$fname" && ! -d "$fname");
|
}
|
}
|
if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
|
if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
|
return "$file_dir/$fname";
|
return "$file_dir/$fname";
|
}
|
}
|
else {
|
else {
|
foreach $dir (@{$inc_dirs}) {
|
foreach $dir (@{$inc_dirs}) {
|
$dir =~ s|/$||;
|
$dir =~ s|/$||;
|
return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
|
return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
|
}
|
}
|
}
|
}
|
return '';
|
return '';
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Take a look through the unresolved modules , delete any that have already
|
# Take a look through the unresolved modules , delete any that have already
|
# been found, and for the others look on the search path
|
# been found, and for the others look on the search path
|
#
|
#
|
sub _resolve_modules {
|
sub _resolve_modules {
|
my ($self,$lib_dirs, $lib_exts)= @_;
|
my ($self,$lib_dirs, $lib_exts)= @_;
|
my ($m,$file,@resolved,$lib_ext);
|
my ($m,$file,@resolved,$lib_ext);
|
|
|
@resolved=();
|
@resolved=();
|
foreach $m (sort (keys %{$self->{unresolved_modules}})) {
|
foreach $m (sort (keys %{$self->{unresolved_modules}})) {
|
if ( exists( $self->{modules}{$m} )) {
|
if ( exists( $self->{modules}{$m} )) {
|
delete( $self->{unresolved_modules}{$m} );
|
delete( $self->{unresolved_modules}{$m} );
|
}
|
}
|
else {
|
else {
|
foreach $lib_ext (@{$lib_exts}) {
|
foreach $lib_ext (@{$lib_exts}) {
|
if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
|
if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
|
delete( $self->{unresolved_modules}{$m} );
|
delete( $self->{unresolved_modules}{$m} );
|
print "resolve_modules: found $m in $file\n" if $debug;
|
print "resolve_modules: found $m in $file\n" if $debug;
|
push(@resolved,$file);
|
push(@resolved,$file);
|
last;
|
last;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
return @resolved;
|
return @resolved;
|
}
|
}
|
|
|
|
|
###############################################################################
|
###############################################################################
|
# Initialize fdata->{files}{FILE} which stores file data
|
# Initialize fdata->{files}{FILE} which stores file data
|
#
|
#
|
sub _init_file {
|
sub _init_file {
|
my ($fdataf,$file) = @_;
|
my ($fdataf,$file) = @_;
|
my ($fb);
|
my ($fb);
|
$fb = _ffile($file);
|
$fb = _ffile($file);
|
$fdataf->{$fb} = {}; # set up hash for each file
|
$fdataf->{$fb} = {}; # set up hash for each file
|
$fdataf->{$fb}{full_name} = $file;
|
$fdataf->{$fb}{full_name} = $file;
|
$fdataf->{$fb}{anchors} = {};
|
$fdataf->{$fb}{anchors} = {};
|
$fdataf->{$fb}{modules} = {};
|
$fdataf->{$fb}{modules} = {};
|
$fdataf->{$fb}{contexts} = {};
|
$fdataf->{$fb}{contexts} = {};
|
$fdataf->{$fb}{includes} = {};
|
$fdataf->{$fb}{includes} = {};
|
$fdataf->{$fb}{inc_done} = 0;
|
$fdataf->{$fb}{inc_done} = 0;
|
$fdataf->{$fb}{lines} = 0;
|
$fdataf->{$fb}{lines} = 0;
|
$fdataf->{$fb}{instance_lines} = {};
|
$fdataf->{$fb}{instance_lines} = {};
|
$fdataf->{$fb}{define_lines} = {};
|
$fdataf->{$fb}{define_lines} = {};
|
$fdataf->{$fb}{included_by} = [];
|
$fdataf->{$fb}{included_by} = [];
|
|
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Initialize fdata->{FILE}{modules}{MODULE} which stores
|
# Initialize fdata->{FILE}{modules}{MODULE} which stores
|
# module (or macromodule or primitive) data
|
# module (or macromodule or primitive) data
|
#
|
#
|
sub _init_module {
|
sub _init_module {
|
my ($modules,$module,$file,$line,$type) = @_;
|
my ($modules,$module,$file,$line,$type) = @_;
|
|
|
|
|
die "Error: attempt to reinit module" if (exists($modules->{$module}));
|
die "Error: attempt to reinit module" if (exists($modules->{$module}));
|
|
|
$modules->{$module}{line} = $line;
|
$modules->{$module}{line} = $line;
|
$modules->{$module}{name} = $module;
|
$modules->{$module}{name} = $module;
|
$modules->{$module}{type} = $type;
|
$modules->{$module}{type} = $type;
|
$modules->{$module}{end} = -1;
|
$modules->{$module}{end} = -1;
|
$modules->{$module}{file} = $file;
|
$modules->{$module}{file} = $file;
|
$modules->{$module}{t_and_f} = {}; # tasks and functions
|
$modules->{$module}{t_and_f} = {}; # tasks and functions
|
$modules->{$module}{signals} = {};
|
$modules->{$module}{signals} = {};
|
$modules->{$module}{parameter_order}= [];
|
$modules->{$module}{parameter_order}= [];
|
$modules->{$module}{parameters}= {};
|
$modules->{$module}{parameters}= {};
|
$modules->{$module}{instances} = []; # things that this module instantiates
|
$modules->{$module}{instances} = []; # things that this module instantiates
|
$modules->{$module}{inst_by} = []; # things that instantiated this module
|
$modules->{$module}{inst_by} = []; # things that instantiated this module
|
$modules->{$module}{port_order} = [];
|
$modules->{$module}{port_order} = [];
|
$modules->{$module}{named_ports} = 1; # assume named ports in instantiations
|
$modules->{$module}{named_ports} = 1; # assume named ports in instantiations
|
$modules->{$module}{duplicate} = 0; # set if another definition is found
|
$modules->{$module}{duplicate} = 0; # set if another definition is found
|
|
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
|
# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
|
# stores tasks and functions' data
|
# stores tasks and functions' data
|
#
|
#
|
sub _init_t_and_f {
|
sub _init_t_and_f {
|
my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
|
my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
|
|
|
if (exists($module->{t_and_f}{$tf})) {
|
if (exists($module->{t_and_f}{$tf})) {
|
$self->_add_warning("$file:$line new definition of $tf ".
|
$self->_add_warning("$file:$line new definition of $tf ".
|
"(discarding previous from ".
|
"(discarding previous from ".
|
"$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
|
"$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
|
}
|
}
|
$module->{t_and_f}{$tf} = {};
|
$module->{t_and_f}{$tf} = {};
|
$module->{t_and_f}{$tf}{type} = $type;
|
$module->{t_and_f}{$tf}{type} = $type;
|
$module->{t_and_f}{$tf}{name} = $tf;
|
$module->{t_and_f}{$tf}{name} = $tf;
|
$module->{t_and_f}{$tf}{line} = $line;
|
$module->{t_and_f}{$tf}{line} = $line;
|
$module->{t_and_f}{$tf}{end} = -1;
|
$module->{t_and_f}{$tf}{end} = -1;
|
$module->{t_and_f}{$tf}{file} = $file;
|
$module->{t_and_f}{$tf}{file} = $file;
|
$module->{t_and_f}{$tf}{signals} = {};
|
$module->{t_and_f}{$tf}{signals} = {};
|
$module->{t_and_f}{$tf}{anchor} = $anchor;
|
$module->{t_and_f}{$tf}{anchor} = $anchor;
|
# point up at things to share with module:
|
# point up at things to share with module:
|
# - task and functions
|
# - task and functions
|
# - module signals
|
# - module signals
|
$module->{t_and_f}{$tf}{t_and_f} = $module->{t_and_f};
|
$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}{parameters} = $module->{parameters};
|
$module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order};
|
$module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order};
|
$module->{t_and_f}{$tf}{m_signals} = $module->{signals};
|
$module->{t_and_f}{$tf}{m_signals} = $module->{signals};
|
}
|
}
|
|
|
# note returns 1 if a signal is added (and an anchor needs to be dropped)
|
# note returns 1 if a signal is added (and an anchor needs to be dropped)
|
sub _init_signal {
|
sub _init_signal {
|
my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
|
my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
|
|
|
if (exists( $signals->{$name} )) {
|
if (exists( $signals->{$name} )) {
|
if ($warnDuplicate) {
|
if ($warnDuplicate) {
|
if (($signals->{$name}{type} eq "output")||
|
if (($signals->{$name}{type} eq "output")||
|
($signals->{$name}{type} eq "inout")||
|
($signals->{$name}{type} eq "inout")||
|
($signals->{$name}{type} eq "input")) {
|
($signals->{$name}{type} eq "input")) {
|
if (($signals->{$name}{type} eq "input")
|
if (($signals->{$name}{type} eq "input")
|
&& ($type eq "reg")) {
|
&& ($type eq "reg")) {
|
$self->_add_warning("$file:$line: ignoring definition".
|
$self->_add_warning("$file:$line: ignoring definition".
|
" of input $name as reg (defined as input at".
|
" of input $name as reg (defined as input at".
|
" $signals->{$name}{file}:$signals->{$name}{line})");
|
" $signals->{$name}{file}:$signals->{$name}{line})");
|
}
|
}
|
else {
|
else {
|
$signals->{$name}{type2}=$type;
|
$signals->{$name}{type2}=$type;
|
}
|
}
|
}
|
}
|
elsif (($signals->{$name}{type} eq "reg")&& # reg before output
|
elsif (($signals->{$name}{type} eq "reg")&& # reg before output
|
(($type eq "output") ||
|
(($type eq "output") ||
|
($type eq "inout"))) {
|
($type eq "inout"))) {
|
$signals->{$name}{type}=$type;
|
$signals->{$name}{type}=$type;
|
$signals->{$name}{type2}="reg";
|
$signals->{$name}{type2}="reg";
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$file:$line: ignoring another definition".
|
$self->_add_warning("$file:$line: ignoring another definition".
|
" of signal $name ($type) first seen as".
|
" of signal $name ($type) first seen as".
|
" $signals->{$name}{type} at".
|
" $signals->{$name}{type} at".
|
" $signals->{$name}{file}:$signals->{$name}{line}");
|
" $signals->{$name}{file}:$signals->{$name}{line}");
|
}
|
}
|
}
|
}
|
return 0;
|
return 0;
|
}
|
}
|
else {
|
else {
|
$signals->{$name} = { type => $type,
|
$signals->{$name} = { type => $type,
|
file => $file,
|
file => $file,
|
line => $line,
|
line => $line,
|
a_line => -1,
|
a_line => -1,
|
a_file => "",
|
a_file => "",
|
i_line => -1,
|
i_line => -1,
|
i_file => "",
|
i_file => "",
|
port_con => [],
|
port_con => [],
|
con_to => [],
|
con_to => [],
|
posedge => 0,
|
posedge => 0,
|
negedge => 0,
|
negedge => 0,
|
type2 => $type2,
|
type2 => $type2,
|
source => { checked => 0, file => "" ,
|
source => { checked => 0, file => "" ,
|
line => "" },
|
line => "" },
|
range => $range,
|
range => $range,
|
dimensions => $dims,
|
dimensions => $dims,
|
};
|
};
|
return 1;
|
return 1;
|
}
|
}
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Add an anchor to the list of anchors that need to be put in
|
# Add an anchor to the list of anchors that need to be put in
|
# the file
|
# the file
|
#
|
#
|
sub _add_anchor {
|
sub _add_anchor {
|
my ($anchors,$line,$name) = @_;
|
my ($anchors,$line,$name) = @_;
|
|
|
my ($a,$no_name_exists);
|
my ($a,$no_name_exists);
|
|
|
if (! exists($anchors->{$line}) ) {
|
if (! exists($anchors->{$line}) ) {
|
$anchors->{$line} = [];
|
$anchors->{$line} = [];
|
}
|
}
|
|
|
if ( $name ) {
|
if ( $name ) {
|
push( @{$anchors->{$line}} , $name );
|
push( @{$anchors->{$line}} , $name );
|
}
|
}
|
else {
|
else {
|
# if no name is specified then you'll get the line number
|
# if no name is specified then you'll get the line number
|
# as the name, but make sure this only happens once
|
# as the name, but make sure this only happens once
|
$no_name_exists = 0;
|
$no_name_exists = 0;
|
foreach $a ( @{$anchors->{$line}} ) {
|
foreach $a ( @{$anchors->{$line}} ) {
|
if ($a eq $line) {
|
if ($a eq $line) {
|
$no_name_exists=1;
|
$no_name_exists=1;
|
last;
|
last;
|
}
|
}
|
}
|
}
|
push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
|
push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
|
}
|
}
|
}
|
}
|
|
|
sub _add_define {
|
sub _add_define {
|
my ($defines,$def_name,$def_value,$file,$line) = @_;
|
my ($defines,$def_name,$def_value,$file,$line) = @_;
|
|
|
$def_value = '' if (!defined($def_value));
|
$def_value = '' if (!defined($def_value));
|
$def_value =~ s/\s+$//; # remove whitespace from end of define
|
$def_value =~ s/\s+$//; # remove whitespace from end of define
|
|
|
if (!exists($defines->{$def_name})) {
|
if (!exists($defines->{$def_name})) {
|
$defines->{$def_name} = { defined => [] , used => {} };
|
$defines->{$def_name} = { defined => [] , used => {} };
|
}
|
}
|
|
|
if ( (1 == @{$defines->{$def_name}{defined}}) &&
|
if ( (1 == @{$defines->{$def_name}{defined}}) &&
|
($defines->{$def_name}{defined}[0]{file} eq $file) &&
|
($defines->{$def_name}{defined}[0]{file} eq $file) &&
|
($defines->{$def_name}{defined}[0]{line} == $line) ) {
|
($defines->{$def_name}{defined}[0]{line} == $line) ) {
|
# if the define is already defined once (and only once) and that
|
# if the define is already defined once (and only once) and that
|
# was the same def (file & line the same - for instance in included
|
# was the same def (file & line the same - for instance in included
|
# file) then there is no need to do anything
|
# file) then there is no need to do anything
|
}
|
}
|
else {
|
else {
|
push (@{$defines->{$def_name}{defined}},
|
push (@{$defines->{$def_name}{defined}},
|
{ line => $line, file => $file ,
|
{ line => $line, file => $file ,
|
value => $def_value, undefed => 0 });
|
value => $def_value, undefed => 0 });
|
}
|
}
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Cross referencing
|
# Cross referencing
|
###############################################################################
|
###############################################################################
|
|
|
###############################################################################
|
###############################################################################
|
# Cross-reference all the files:
|
# Cross-reference all the files:
|
# - find the modules and set up $self->{modules}
|
# - find the modules and set up $self->{modules}
|
# - store the data about where it is instatiated with each module
|
# - store the data about where it is instatiated with each module
|
# - check for self instantiation
|
# - check for self instantiation
|
# - check for files with modules + instances outside modules
|
# - check for files with modules + instances outside modules
|
# - set a_line for signals driven by output and i_line
|
# - set a_line for signals driven by output and i_line
|
#
|
#
|
sub _cross_reference {
|
sub _cross_reference {
|
my ($self) = @_;
|
my ($self) = @_;
|
my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
|
my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
|
|
|
# stores the instantiation data in an
|
# stores the instantiation data in an
|
# array so that we can easily tell which modules
|
# array so that we can easily tell which modules
|
# are disconnected and which are the tops of the
|
# are disconnected and which are the tops of the
|
# hierarchy and makes it easier to go up
|
# hierarchy and makes it easier to go up
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
print " Making inst_by for $m\n" if $debug;
|
print " Making inst_by for $m\n" if $debug;
|
foreach $m2 (sort (keys %{$self->{modules}})) {
|
foreach $m2 (sort (keys %{$self->{modules}})) {
|
foreach $inst (@{$self->{modules}{$m2}{instances}}) {
|
foreach $inst (@{$self->{modules}{$m2}{instances}}) {
|
if (($inst->{module} eq $m) &&
|
if (($inst->{module} eq $m) &&
|
exists($self->{modules}{$m})) {
|
exists($self->{modules}{$m})) {
|
print " inst by $m2\n" if $debug;
|
print " inst by $m2\n" if $debug;
|
push( @{$self->{modules}{$m}{inst_by}},
|
push( @{$self->{modules}{$m}{inst_by}},
|
{ module => $m2,
|
{ module => $m2,
|
file => $inst->{file},
|
file => $inst->{file},
|
inst => $inst->{inst_name} ,
|
inst => $inst->{inst_name} ,
|
line => $inst->{line} } );
|
line => $inst->{line} } );
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
# Find any modules that appear to instantiate themselves
|
# Find any modules that appear to instantiate themselves
|
# (to prevent getting into infinite recursions later on)
|
# (to prevent getting into infinite recursions later on)
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
print " Checking self instantiations for $m\n" if $debug;
|
print " Checking self instantiations for $m\n" if $debug;
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
if ($inst->{module} eq $m) {
|
if ($inst->{module} eq $m) {
|
$self->_add_warning("$inst->{file}:$inst->{line}: $m ".
|
$self->_add_warning("$inst->{file}:$inst->{line}: $m ".
|
"instantiates itself");
|
"instantiates itself");
|
$inst->{module} = '_ERROR_SELF_INSTANTIATION_';
|
$inst->{module} = '_ERROR_SELF_INSTANTIATION_';
|
# remove the port con for all signals not attached
|
# remove the port con for all signals not attached
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
my $port_con_ok=[];
|
my $port_con_ok=[];
|
foreach $port_con (@{$sigp->{port_con}}) {
|
foreach $port_con (@{$sigp->{port_con}}) {
|
if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
|
if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
|
else { print " Deleting connection for $sig\n" if $debug; }
|
else { print " Deleting connection for $sig\n" if $debug; }
|
}
|
}
|
$sigp->{port_con} = $port_con_ok;
|
$sigp->{port_con} = $port_con_ok;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
# Go through instances without named ports (port will be a number instead) and
|
# 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
|
# resolve name if you can, otherwise delete. These can appear in signal's port_con
|
# lists and in instances connections lists.
|
# lists and in instances connections lists.
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
if (0 == $self->{modules}{$m}{named_ports}) {
|
if (0 == $self->{modules}{$m}{named_ports}) {
|
$f = $self->{modules}{$m}{file}; # for error messages
|
$f = $self->{modules}{$m}{file}; # for error messages
|
print " Resolving numbered port connections in $m\n" if $debug;
|
print " Resolving numbered port connections in $m\n" if $debug;
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
print " doing $sig\n" if $debug;
|
print " doing $sig\n" if $debug;
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
|
|
foreach $port_con (@{$sigp->{port_con}}) {
|
foreach $port_con (@{$sigp->{port_con}}) {
|
if ($port_con->{port} =~ m/^[0-9]/ ) {
|
if ($port_con->{port} =~ m/^[0-9]/ ) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
$m2 = $self->{modules}{$port_con->{module}};
|
$m2 = $self->{modules}{$port_con->{module}};
|
if (defined($m2->{port_order}[$port_con->{port}])) {
|
if (defined($m2->{port_order}[$port_con->{port}])) {
|
$port_con->{port}=$m2->{port_order}[$port_con->{port}];
|
$port_con->{port}=$m2->{port_order}[$port_con->{port}];
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$port_con->{file}:$port_con->{line}:".
|
$self->_add_warning("$port_con->{file}:$port_con->{line}:".
|
" could not resolve port number to name");
|
" could not resolve port number to name");
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
if ( exists( $self->{modules}{$inst->{module}}) ) {
|
if ( exists( $self->{modules}{$inst->{module}}) ) {
|
$m2 = $self->{modules}{$inst->{module}};
|
$m2 = $self->{modules}{$inst->{module}};
|
foreach $port (sort (keys %{$inst->{connections}})) {
|
foreach $port (sort (keys %{$inst->{connections}})) {
|
last if ($port !~ m/^[0-9]/); # if any are named, all are named
|
last if ($port !~ m/^[0-9]/); # if any are named, all are named
|
if (defined($m2->{port_order}[$port])) {
|
if (defined($m2->{port_order}[$port])) {
|
# move old connection to named port
|
# move old connection to named port
|
$inst->{connections}{$m2->{port_order}[$port]} =
|
$inst->{connections}{$m2->{port_order}[$port]} =
|
$inst->{connections}{$port};
|
$inst->{connections}{$port};
|
# remove old numbered port from hash
|
# remove old numbered port from hash
|
delete($inst->{connections}{$port});
|
delete($inst->{connections}{$port});
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$inst->{file}:$inst->{line}:".
|
$self->_add_warning("$inst->{file}:$inst->{line}:".
|
"could not resolve port number $port to name)");
|
"could not resolve port number $port to name)");
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
# Go through all instances with parameter lists and try to resolve names parameter
|
# Go through all instances with parameter lists and try to resolve names parameter
|
#
|
#
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
foreach $inst (@{$self->{modules}{$m}{instances}}) {
|
if ($inst->{parameters}) {
|
if ($inst->{parameters}) {
|
if ( exists( $self->{modules}{$inst->{module}}) ) {
|
if ( exists( $self->{modules}{$inst->{module}}) ) {
|
my $mp=$self->{modules}{$inst->{module}};
|
my $mp=$self->{modules}{$inst->{module}};
|
foreach my $p (sort (keys %{$inst->{parameters}})){
|
foreach my $p (sort (keys %{$inst->{parameters}})){
|
last if ( $p !~ m/^[0-9]+$/ );
|
last if ( $p !~ m/^[0-9]+$/ );
|
my $pn = $mp->{parameter_order}[$p];
|
my $pn = $mp->{parameter_order}[$p];
|
if ($pn) {
|
if ($pn) {
|
$inst->{parameters}{$pn} =
|
$inst->{parameters}{$pn} =
|
$inst->{parameters}{$p};
|
$inst->{parameters}{$p};
|
delete($inst->{parameters}{$p});
|
delete($inst->{parameters}{$p});
|
print "$inst->{parameters}{$pn}{file}:".
|
print "$inst->{parameters}{$pn}{file}:".
|
"$inst->{parameters}{$pn}{line}: ".
|
"$inst->{parameters}{$pn}{line}: ".
|
"Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
|
"Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
|
if $debug;
|
if $debug;
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$inst->{parameters}{$p}{file}:".
|
$self->_add_warning("$inst->{parameters}{$p}{file}:".
|
"$inst->{parameters}{$p}{line} ".
|
"$inst->{parameters}{$p}{line} ".
|
"could not resolve parameter number $p to name");
|
"could not resolve parameter number $p to name");
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
# Go through all the modules and each signal inside
|
# Go through all the modules and each signal inside
|
# looking at whether the signal is connected to any outputs
|
# looking at whether the signal is connected to any outputs
|
# (set the a_line on the first one if it is not already set)
|
# (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
|
# Also, when you see a signal connected to an input (and that
|
# submod is only instantiated once) reach down into the submod
|
# submod is only instantiated once) reach down into the submod
|
# and set the i_line of that signal, so that clicking on the
|
# 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
|
# input can pop you up to the line that input is driven in
|
# one of the instantiations
|
# one of the instantiations
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
print " Finding port connections in $m\n" if $debug;
|
print " Finding port connections in $m\n" if $debug;
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
print " checking signal $sig\n" if $debug;
|
print " checking signal $sig\n" if $debug;
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
|
|
foreach $port_con (@{$sigp->{port_con}}) {
|
foreach $port_con (@{$sigp->{port_con}}) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
print " connection to $port_con->{module}\n" if $debug;
|
print " connection to $port_con->{module}\n" if $debug;
|
$m2 = $self->{modules}{$port_con->{module}};
|
$m2 = $self->{modules}{$port_con->{module}};
|
if (exists( $m2->{signals}{$port_con->{port}})) {
|
if (exists( $m2->{signals}{$port_con->{port}})) {
|
push(@{$m2->{signals}{$port_con->{port}}{con_to}},
|
push(@{$m2->{signals}{$port_con->{port}}{con_to}},
|
{ signal => $sig , module => $m , inst => $port_con->{inst}});
|
{ signal => $sig , module => $m , inst => $port_con->{inst}});
|
if ( ($m2->{signals}{$port_con->{port}}{type} eq
|
if ( ($m2->{signals}{$port_con->{port}}{type} eq
|
'output') &&
|
'output') &&
|
($sigp->{a_line} == -1)) {
|
($sigp->{a_line} == -1)) {
|
$sigp->{driven_by_port}=1;
|
$sigp->{driven_by_port}=1;
|
$sigp->{a_line} = $port_con->{line};
|
$sigp->{a_line} = $port_con->{line};
|
$sigp->{a_file} = $port_con->{file};
|
$sigp->{a_file} = $port_con->{file};
|
_add_anchor($self->{files}{$port_con->{file}}{anchors},
|
_add_anchor($self->{files}{$port_con->{file}}{anchors},
|
$port_con->{line},'');
|
$port_con->{line},'');
|
}
|
}
|
elsif ($m2->{signals}{$port_con->{port}}{type} eq
|
elsif ($m2->{signals}{$port_con->{port}}{type} eq
|
'input') {
|
'input') {
|
$m2->{signals}{$port_con->{port}}{driven_by_port}=1;
|
$m2->{signals}{$port_con->{port}}{driven_by_port}=1;
|
if (scalar(@{$m2->{inst_by}}) &&
|
if (scalar(@{$m2->{inst_by}}) &&
|
($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
|
($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
|
$m2->{signals}{$port_con->{port}}{i_line}=
|
$m2->{signals}{$port_con->{port}}{i_line}=
|
$port_con->{line};
|
$port_con->{line};
|
$m2->{signals}{$port_con->{port}}{i_file}=
|
$m2->{signals}{$port_con->{port}}{i_file}=
|
$port_con->{file};
|
$port_con->{file};
|
_add_anchor($self->{files}{$port_con->{file}}{anchors},
|
_add_anchor($self->{files}{$port_con->{file}}{anchors},
|
$port_con->{line},'');
|
$port_con->{line},'');
|
print " set i_line $port_con->{port} ".
|
print " set i_line $port_con->{port} ".
|
"$port_con->{file}:$port_con->{line}\n" if $debug;
|
"$port_con->{file}:$port_con->{line}\n" if $debug;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
# find all signal sources
|
# find all signal sources
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
print " Finding signal sources in $m\n" if $debug;
|
print " Finding signal sources in $m\n" if $debug;
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
next if $sigp->{source}{checked};
|
next if $sigp->{source}{checked};
|
print " finding signal source for $sig of $m\n" if $debug;
|
print " finding signal source for $sig of $m\n" if $debug;
|
$sigp->{source} = $self->_find_signal_source($sigp);
|
$sigp->{source} = $self->_find_signal_source($sigp);
|
}
|
}
|
}
|
}
|
|
|
# propagate the posedge, negedge stuff up the hierarchy
|
# propagate the posedge, negedge stuff up the hierarchy
|
foreach $m (sort (keys %{$self->{modules}})) {
|
foreach $m (sort (keys %{$self->{modules}})) {
|
# only do the recursion for top level modules
|
# only do the recursion for top level modules
|
if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
|
if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
|
$self->_prop_edges($m);
|
$self->_prop_edges($m);
|
}
|
}
|
}
|
}
|
|
|
# get included_by information
|
# get included_by information
|
foreach $f ( sort (keys %{$self->{files}} )) {
|
foreach $f ( sort (keys %{$self->{files}} )) {
|
foreach $i ($self->get_files_includes($f)) {
|
foreach $i ($self->get_files_includes($f)) {
|
if (exists $self->{files}{$i}) {
|
if (exists $self->{files}{$i}) {
|
push( @{$self->{files}{$i}{included_by}} , $f );
|
push( @{$self->{files}{$i}{included_by}} , $f );
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
sub _find_signal_source {
|
sub _find_signal_source {
|
my ($self,$sigp) = @_;
|
my ($self,$sigp) = @_;
|
my ($con_to,$port_con,$ret_val);
|
my ($con_to,$port_con,$ret_val);
|
|
|
if ($sigp->{source}{checked}) {
|
if ($sigp->{source}{checked}) {
|
print " source already found\n" if $debug;
|
print " source already found\n" if $debug;
|
$ret_val = $sigp->{source};
|
$ret_val = $sigp->{source};
|
}
|
}
|
else {
|
else {
|
$ret_val = { checked => 1, file => '' , line => '' };
|
$ret_val = { checked => 1, file => '' , line => '' };
|
if (exists($sigp->{driven_by_port})) {
|
if (exists($sigp->{driven_by_port})) {
|
print " drive by port\n" if $debug;
|
print " drive by port\n" if $debug;
|
foreach $con_to (@{$sigp->{con_to}}) {
|
foreach $con_to (@{$sigp->{con_to}}) {
|
# if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
|
# if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
|
if ($sigp->{type} eq 'input') {
|
if ($sigp->{type} eq 'input') {
|
print " following input $con_to->{signal} $con_to->{module} $con_to->{inst}\n" if $debug;
|
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 $!"; }
|
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(
|
$ret_val = $self->_find_signal_source(
|
$self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
|
$self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
|
}
|
}
|
}
|
}
|
foreach $port_con (@{$sigp->{port_con}}) {
|
foreach $port_con (@{$sigp->{port_con}}) {
|
if (exists ($self->{modules}{$port_con->{module}})) {
|
if (exists ($self->{modules}{$port_con->{module}})) {
|
if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
|
if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
|
if ($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}}{type} eq 'output') {
|
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;
|
print " following output $port_con->{port} $port_con->{module} $port_con->{inst}\n" if $debug;
|
$ret_val = $self->_find_signal_source(
|
$ret_val = $self->_find_signal_source(
|
$self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
|
$self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
|
}
|
}
|
}
|
}
|
else {
|
else {
|
$self->_add_warning("$port_con->{file}:$port_con->{line}:".
|
$self->_add_warning("$port_con->{file}:$port_con->{line}:".
|
" Connection to nonexistent port ".
|
" Connection to nonexistent port ".
|
" $port_con->{port} of module $port_con->{module}");
|
" $port_con->{port} of module $port_con->{module}");
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
else {
|
else {
|
if ($sigp->{a_line}==-1) {
|
if ($sigp->{a_line}==-1) {
|
if ($sigp->{type} eq 'input') {
|
if ($sigp->{type} eq 'input') {
|
print " signal is an input not driven at higher level\n" if $debug;
|
print " signal is an input not driven at higher level\n" if $debug;
|
$ret_val = { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
|
$ret_val = { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
|
}
|
}
|
else {
|
else {
|
print " signal has unknown source\n" if $debug;
|
print " signal has unknown source\n" if $debug;
|
}
|
}
|
}
|
}
|
else {
|
else {
|
print " signal is driven in this module\n" if $debug;
|
print " signal is driven in this module\n" if $debug;
|
$ret_val = { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
|
$ret_val = { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
$sigp->{source} = $ret_val;
|
$sigp->{source} = $ret_val;
|
return $ret_val;
|
return $ret_val;
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
# Propagate posedge and negedge attributes of signals up the hierarchy
|
# Propagate posedge and negedge attributes of signals up the hierarchy
|
#
|
#
|
sub _prop_edges {
|
sub _prop_edges {
|
my ($self,$m) = @_;
|
my ($self,$m) = @_;
|
my ($imod,@inst,$sig,$sigp,$port_con,$m2);
|
my ($imod,@inst,$sig,$sigp,$port_con,$m2);
|
|
|
print "Prop_edges $m\n" if $debug;
|
print "Prop_edges $m\n" if $debug;
|
|
|
for ( ($imod) = $self->get_first_instantiation($m) ;
|
for ( ($imod) = $self->get_first_instantiation($m) ;
|
$imod;
|
$imod;
|
($imod) = $self->get_next_instantiation()) {
|
($imod) = $self->get_next_instantiation()) {
|
push(@inst,$imod) if (exists( $self->{modules}{$imod}));
|
push(@inst,$imod) if (exists( $self->{modules}{$imod}));
|
}
|
}
|
foreach $imod (@inst) { $self->_prop_edges($imod); }
|
foreach $imod (@inst) { $self->_prop_edges($imod); }
|
|
|
# Propagate all the edges up the hierarchy
|
# Propagate all the edges up the hierarchy
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
|
print " checking signal $sig\n" if $debug;
|
print " checking signal $sig\n" if $debug;
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
$sigp = $self->{modules}{$m}{signals}{$sig};
|
|
|
foreach $port_con (@{$sigp->{port_con}}) {
|
foreach $port_con (@{$sigp->{port_con}}) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
if ( exists( $self->{modules}{$port_con->{module}}) ) {
|
print " connection to $port_con->{module}\n" if $debug;
|
print " connection to $port_con->{module}\n" if $debug;
|
$m2 = $self->{modules}{$port_con->{module}};
|
$m2 = $self->{modules}{$port_con->{module}};
|
if (exists( $m2->{signals}{$port_con->{port}})) {
|
if (exists( $m2->{signals}{$port_con->{port}})) {
|
print "Propagating posedge on $sig from $port_con->{module} to $m\n"
|
print "Propagating posedge on $sig from $port_con->{module} to $m\n"
|
if ($debug && (!$sigp->{posedge}) && $m2->{signals}{$port_con->{port}}{posedge});
|
if ($debug && (!$sigp->{posedge}) && $m2->{signals}{$port_con->{port}}{posedge});
|
$sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
|
$sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
|
$sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
|
$sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
###############################################################################
|
###############################################################################
|
# given a source file name work out the file without the path
|
# given a source file name work out the file without the path
|
#
|
#
|
sub _ffile {
|
sub _ffile {
|
my ($sfile) = @_;
|
my ($sfile) = @_;
|
|
|
$sfile =~ s/^.*[\/\\]//;
|
$sfile =~ s/^.*[\/\\]//;
|
|
|
return $sfile;
|
return $sfile;
|
}
|
}
|
|
|
sub _add_warning {
|
sub _add_warning {
|
my ($self,$p) = @_;
|
my ($self,$p) = @_;
|
|
|
print "Warning:$p\n" if $debug;
|
print "Warning:$p\n" if $debug;
|
push (@{$self->{problems}},"Warning:$p");
|
push (@{$self->{problems}},"Warning:$p");
|
}
|
}
|
sub _add_confused {
|
sub _add_confused {
|
my ($self,$p) = @_;
|
my ($self,$p) = @_;
|
|
|
print "Confused:$p\n" if $debug;
|
print "Confused:$p\n" if $debug;
|
push (@{$self->{problems}},"Confused:$p");
|
push (@{$self->{problems}},"Confused:$p");
|
}
|
}
|
|
|
###############################################################################
|
###############################################################################
|
#
|
#
|
BEGIN {
|
BEGIN {
|
$baseEval = {
|
$baseEval = {
|
START => {
|
START => {
|
MODULE => '$rs->{t}={ type=>$match, line=>$line };',
|
MODULE => '$rs->{t}={ type=>$match, line=>$line };',
|
},
|
},
|
MODULE => {
|
MODULE => {
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
# if you add to this also edit {AFTER_INST}{COMMA}
|
# if you add to this also edit {AFTER_INST}{COMMA}
|
INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 ,
|
INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 ,
|
params=>{}, param_number=>0 , portName=>"" , vids=>[]};',
|
params=>{}, param_number=>0 , portName=>"" , vids=>[]};',
|
},
|
},
|
MODULE_NAME => {
|
MODULE_NAME => {
|
NAME => 'my $nState="MODULE_PPL";
|
NAME => 'my $nState="MODULE_PPL";
|
my $type = $rs->{t}{type}; $rs->{t}=undef;',
|
my $type = $rs->{t}{type}; $rs->{t}=undef;',
|
},
|
},
|
IN_CONCAT => {
|
IN_CONCAT => {
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
|
},
|
},
|
IN_BRACKET => {
|
IN_BRACKET => {
|
VID => 'IN_CONCAT:VID',
|
VID => 'IN_CONCAT:VID',
|
},
|
},
|
SCALARED_OR_VECTORED => {
|
SCALARED_OR_VECTORED => {
|
TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
|
TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
|
},
|
},
|
SIGNAL_NAME => {
|
SIGNAL_NAME => {
|
VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
|
VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
|
},
|
},
|
SIGNAL_AFTER_EQUALS => {
|
SIGNAL_AFTER_EQUALS => {
|
END => '$rs->{t}=undef;',
|
END => '$rs->{t}=undef;',
|
},
|
},
|
INST_PARAM_BRACKET => {
|
INST_PARAM_BRACKET => {
|
NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
|
NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
|
},
|
},
|
INST_NAME => {
|
INST_NAME => {
|
VID => '$rs->{t}{name}=$match;',
|
VID => '$rs->{t}{name}=$match;',
|
},
|
},
|
INST_PORTS => {
|
INST_PORTS => {
|
COMMA => '$rs->{t}{port}++;',
|
COMMA => '$rs->{t}{port}++;',
|
},
|
},
|
INST_PORT_NAME => {
|
INST_PORT_NAME => {
|
NAME => '$rs->{t}{portName}=$match;
|
NAME => '$rs->{t}{portName}=$match;
|
$rs->{t}{vids} = [];', # throw away any instance parameters picked up
|
$rs->{t}{vids} = [];', # throw away any instance parameters picked up
|
},
|
},
|
INST_NAMED_PORT_CON => {
|
INST_NAMED_PORT_CON => {
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
|
},
|
},
|
INST_NAMED_PORT_CON_AFTER => {
|
INST_NAMED_PORT_CON_AFTER => {
|
COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
|
COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
|
my @vids = @{$rs->{t}{vids}};
|
my @vids = @{$rs->{t}{vids}};
|
my $portName = $rs->{t}{portName};
|
my $portName = $rs->{t}{portName};
|
$rs->{t}{portName}="";
|
$rs->{t}{portName}="";
|
$rs->{t}{vids}=[];',
|
$rs->{t}{vids}=[];',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
},
|
},
|
INST_NUMBERED_PORT => {
|
INST_NUMBERED_PORT => {
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
|
VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
|
},
|
},
|
AFTER_INST => {
|
AFTER_INST => {
|
SEMICOLON => '$rs->{t}=undef;',
|
SEMICOLON => '$rs->{t}=undef;',
|
COMMA => '$rs->{t}{line}=$line;
|
COMMA => '$rs->{t}{line}=$line;
|
$rs->{t}{name}="";
|
$rs->{t}{name}="";
|
$rs->{t}{port}=0;
|
$rs->{t}{port}=0;
|
$rs->{t}{portName}="";
|
$rs->{t}{portName}="";
|
$rs->{t}{vids}=[];',
|
$rs->{t}{vids}=[];',
|
},
|
},
|
SIGNAL_AFTER_NAME => {
|
SIGNAL_AFTER_NAME => {
|
SEMICOLON => '$rs->{t}=undef;',
|
SEMICOLON => '$rs->{t}=undef;',
|
},
|
},
|
IN_EVENT_BRACKET => {
|
IN_EVENT_BRACKET => {
|
EDGE => '$rs->{t}={ type=>$match };',
|
EDGE => '$rs->{t}={ type=>$match };',
|
},
|
},
|
IN_EVENT_BRACKET_EDGE => {
|
IN_EVENT_BRACKET_EDGE => {
|
VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
|
VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
|
},
|
},
|
STMNT => {
|
STMNT => {
|
ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};',
|
ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};',
|
HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};',
|
HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};',
|
CONCAT => '$rs->{t}={ vids=>[]};',
|
CONCAT => '$rs->{t}={ vids=>[]};',
|
},
|
},
|
STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
|
STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
|
EQUALS => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;',
|
EQUALS => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;',
|
# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
|
# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
|
# SEMICOLON => '$rs->{t}=undef;',
|
# SEMICOLON => '$rs->{t}=undef;',
|
BRACKET => '$rs->{t}=undef;',
|
BRACKET => '$rs->{t}=undef;',
|
},
|
},
|
STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
|
STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
|
EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
|
EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
|
},
|
},
|
IN_SIG_RANGE => {
|
IN_SIG_RANGE => {
|
END => '$rs->{t}{range}=$fromLastPos;',
|
END => '$rs->{t}{range}=$fromLastPos;',
|
},
|
},
|
IN_MEM_RANGE => {
|
IN_MEM_RANGE => {
|
END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
|
END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
|
},
|
},
|
ANSI_PORTS_TYPE => { # V2001 ansi ports
|
ANSI_PORTS_TYPE => { # V2001 ansi ports
|
TYPE => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
TYPE => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
},
|
},
|
ANSI_PORTS_TYPE2 => { # V2001 ansi ports
|
ANSI_PORTS_TYPE2 => { # V2001 ansi ports
|
TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
|
TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
|
},
|
},
|
ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
|
ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
|
VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
|
VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
|
},
|
},
|
};
|
};
|
|
|
############################################################
|
############################################################
|
# debugEval
|
# debugEval
|
############################################################
|
############################################################
|
$debugEval = {
|
$debugEval = {
|
ANSI_PORTS_SIGNAL_NAME => {
|
ANSI_PORTS_SIGNAL_NAME => {
|
VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
|
VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
|
},
|
},
|
SIGNAL_NAME => {
|
SIGNAL_NAME => {
|
VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
|
VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
|
},
|
},
|
INST_BRACKET => {
|
INST_BRACKET => {
|
PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
|
PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
|
},
|
},
|
INST_NAMED_PORT_CON_AFTER => {
|
INST_NAMED_PORT_CON_AFTER => {
|
COMMA => 'my @vidnames;
|
COMMA => 'my @vidnames;
|
foreach my $vid (@vids) {push @vidnames,$vid->{name};}
|
foreach my $vid (@vids) {push @vidnames,$vid->{name};}
|
print " Port $portName connected to ".join(",",@vidnames)."\n";',
|
print " Port $portName connected to ".join(",",@vidnames)."\n";',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
},
|
},
|
INST_NUMBERED_PORT => {
|
INST_NUMBERED_PORT => {
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
},
|
},
|
};
|
};
|
|
|
|
|
############################################################
|
############################################################
|
# rvpEval
|
# rvpEval
|
############################################################
|
############################################################
|
|
|
$rvpEval = {
|
$rvpEval = {
|
MODULE => {
|
MODULE => {
|
ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
|
ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
|
(($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
|
(($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
|
$self->_add_warning("$file:$line: module of type".
|
$self->_add_warning("$file:$line: module of type".
|
" $rs->{p}{type} ended by $match");
|
" $rs->{p}{type} ended by $match");
|
}
|
}
|
$rs->{modules}{$rs->{module}}{end} = $line;
|
$rs->{modules}{$rs->{module}}{end} = $line;
|
$rs->{module} = "";
|
$rs->{module} = "";
|
$rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
|
$rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
|
$rs->{p}= undef;',
|
$rs->{p}= undef;',
|
PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
|
PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
|
},
|
},
|
MODULE_NAME => {
|
MODULE_NAME => {
|
NAME => 'if (exists($rs->{modules}{$match})) {
|
NAME => 'if (exists($rs->{modules}{$match})) {
|
$nState = "IGNORE_MODULE";
|
$nState = "IGNORE_MODULE";
|
$rs->{modules}{$match}{duplicate} = 1;
|
$rs->{modules}{$match}{duplicate} = 1;
|
$self->_add_warning("$file:$line ignoring new definition of ".
|
$self->_add_warning("$file:$line ignoring new definition of ".
|
"module $match, previous was at ".
|
"module $match, previous was at ".
|
"$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
|
"$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
|
}
|
}
|
else {
|
else {
|
$rs->{module}=$match;
|
$rs->{module}=$match;
|
_init_module($rs->{modules},$rs->{module},$file,$line,$type);
|
_init_module($rs->{modules},$rs->{module},$file,$line,$type);
|
$rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
|
$rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
|
_add_anchor($rs->{files}{$file}{anchors},$line,$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}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};
|
$rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
|
$rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
|
}',
|
}',
|
},
|
},
|
MODULE_PORTS => {
|
MODULE_PORTS => {
|
VID => 'push(@{$rs->{p}{port_order}},$match);',
|
VID => 'push(@{$rs->{p}{port_order}},$match);',
|
},
|
},
|
FUNCTION => {
|
FUNCTION => {
|
NAME => '$rs->{function}=$match;
|
NAME => '$rs->{function}=$match;
|
$self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
|
$self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
|
$rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
|
$rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
|
_add_anchor($rs->{files}{$file}{anchors},$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}};',
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}};',
|
},
|
},
|
TASK => {
|
TASK => {
|
NAME => '$rs->{task}=$match;
|
NAME => '$rs->{task}=$match;
|
$self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
|
$self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
|
$rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
|
$rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
|
_add_anchor($rs->{files}{$file}{anchors},$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}};',
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}};',
|
},
|
},
|
ENDTASK => {
|
ENDTASK => {
|
ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
|
ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
|
$rs->{task}="";
|
$rs->{task}="";
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
|
},
|
},
|
T_SIGNAL => {
|
T_SIGNAL => {
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
|
ENDTASK => 'ENDTASK:ENDTASK',
|
ENDTASK => 'ENDTASK:ENDTASK',
|
PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
|
PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
|
},
|
},
|
ENDFUNCTION => {
|
ENDFUNCTION => {
|
ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
|
ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
|
$rs->{function}="";
|
$rs->{function}="";
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
|
$rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
|
},
|
},
|
F_SIGNAL => {
|
F_SIGNAL => {
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
|
ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
|
ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
|
PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
|
PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
|
},
|
},
|
BLOCK_SIGNAL => {
|
BLOCK_SIGNAL => {
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
|
SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
|
},
|
},
|
PARAM_NAME => {
|
PARAM_NAME => {
|
NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions
|
NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions
|
$rs->{t}= { file => $file, line => $line , value => "" ,
|
$rs->{t}= { file => $file, line => $line , value => "" ,
|
ptype => $rs->{t}{ptype}}; # ptype is same as the last one
|
ptype => $rs->{t}{ptype}}; # ptype is same as the last one
|
push(@{$rs->{p}{parameter_order}}, $match)
|
push(@{$rs->{p}{parameter_order}}, $match)
|
unless ($rs->{t}{ptype} eq "localparam");
|
unless ($rs->{t}{ptype} eq "localparam");
|
$rs->{p}{parameters}{$match}=$rs->{t};
|
$rs->{p}{parameters}{$match}=$rs->{t};
|
_add_anchor($rs->{files}{$file}{anchors},$line,""); }',
|
_add_anchor($rs->{files}{$file}{anchors},$line,""); }',
|
},
|
},
|
PPL_PARAM => {
|
PPL_PARAM => {
|
PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
|
PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
|
},
|
},
|
PPL_NAME => {
|
PPL_NAME => {
|
NAME => 'PARAM_NAME:NAME',
|
NAME => 'PARAM_NAME:NAME',
|
},
|
},
|
PARAM_AFTER_EQUALS => {
|
PARAM_AFTER_EQUALS => {
|
COMMA => '$rs->{t}{value} = $fromLastPos;',
|
COMMA => '$rs->{t}{value} = $fromLastPos;',
|
SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
|
SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
|
},
|
},
|
PPL_AFTER_EQUALS => {
|
PPL_AFTER_EQUALS => {
|
COMMA => 'PARAM_AFTER_EQUALS:COMMA',
|
COMMA => 'PARAM_AFTER_EQUALS:COMMA',
|
END => 'PARAM_AFTER_EQUALS:COMMA',
|
END => 'PARAM_AFTER_EQUALS:COMMA',
|
},
|
},
|
ASSIGN => {
|
ASSIGN => {
|
VID => 'if ( exists($rs->{p}{signals}{$match}) &&
|
VID => 'if ( exists($rs->{p}{signals}{$match}) &&
|
($rs->{p}{signals}{$match}{a_line} == -1)) {
|
($rs->{p}{signals}{$match}{a_line} == -1)) {
|
$rs->{p}{signals}{$match}{a_line} = $line;
|
$rs->{p}{signals}{$match}{a_line} = $line;
|
$rs->{p}{signals}{$match}{a_file} = $file;
|
$rs->{p}{signals}{$match}{a_file} = $file;
|
_add_anchor($rs->{files}{$file}{anchors},$line,"");
|
_add_anchor($rs->{files}{$file}{anchors},$line,"");
|
}',
|
}',
|
},
|
},
|
SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
|
SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
|
VID => 'if ($rs->{t}{block} != 1) {
|
VID => 'if ($rs->{t}{block} != 1) {
|
$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
|
$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
|
$rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
|
$rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
|
&& _add_anchor($rs->{files}{$file}{anchors},$line,"");
|
&& _add_anchor($rs->{files}{$file}{anchors},$line,"");
|
}',
|
}',
|
},
|
},
|
SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is
|
SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is
|
# only the initial value
|
# only the initial value
|
ASSIGN => 'if ($rs->{t}{block} != 1) {
|
ASSIGN => 'if ($rs->{t}{block} != 1) {
|
if ( $rs->{p}{signals}{$rs->{t}{name}}{type} ne "reg" ) {
|
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_line}=$rs->{t}{line};
|
$rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
|
$rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
|
_add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
|
_add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
|
}
|
}
|
}',
|
}',
|
},
|
},
|
INST_PARAM_VALUE => {
|
INST_PARAM_VALUE => {
|
# Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
|
# Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
|
# and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
|
# and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
|
# and the second uses $match to capture the parameter value
|
# and the second uses $match to capture the parameter value
|
COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
|
COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
|
$rs->{t}{params}{$rs->{t}{param_number}} =
|
$rs->{t}{params}{$rs->{t}{param_number}} =
|
{ file => $file , line => $line , value => $fromLastPos };
|
{ file => $file , line => $line , value => $fromLastPos };
|
$rs->{t}{param_number}++;',
|
$rs->{t}{param_number}++;',
|
END => 'INST_PARAM_VALUE:COMMA',
|
END => 'INST_PARAM_VALUE:COMMA',
|
},
|
},
|
INST_PARAM_BRACKET => {
|
INST_PARAM_BRACKET => {
|
# Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
|
# Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
|
# and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
|
# and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
|
# and the second uses $match to capture the parameter value
|
# and the second uses $match to capture the parameter value
|
NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
|
NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
|
$rs->{t}{params}{$rs->{t}{param_number}} =
|
$rs->{t}{params}{$rs->{t}{param_number}} =
|
{ file => $file , line => $line , value => $match };
|
{ file => $file , line => $line , value => $match };
|
$rs->{t}{param_number}++;',
|
$rs->{t}{param_number}++;',
|
},
|
},
|
INST_BRACKET => {
|
INST_BRACKET => {
|
PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
|
PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
|
$rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
|
$rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
|
push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} ,
|
push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} ,
|
inst_name => $rs->{t}{name} ,
|
inst_name => $rs->{t}{name} ,
|
file => $file,
|
file => $file,
|
line => $rs->{t}{line},
|
line => $rs->{t}{line},
|
parameters => $rs->{t}{params},
|
parameters => $rs->{t}{params},
|
connections => {} });
|
connections => {} });
|
_add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
|
_add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
|
$rs->{module}."_".$rs->{t}{name});',
|
$rs->{module}."_".$rs->{t}{name});',
|
},
|
},
|
INST_NAMED_PORT_CON_AFTER => {
|
INST_NAMED_PORT_CON_AFTER => {
|
COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
|
COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
|
$rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
|
$rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
|
if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
|
if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
|
$rs->{p}{named_ports} = 0;
|
$rs->{p}{named_ports} = 0;
|
}
|
}
|
else { # remove the bracket from the end if a named port
|
else { # remove the bracket from the end if a named port
|
$rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
|
$rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
|
}
|
}
|
foreach my $s (@vids) {
|
foreach my $s (@vids) {
|
$self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
|
$self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
|
&& _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
|
&& _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
|
push( @{$rs->{p}{signals}{$s->{name}}{port_con}},
|
push( @{$rs->{p}{signals}{$s->{name}}{port_con}},
|
{ port => $portName ,
|
{ port => $portName ,
|
line => $s->{line},
|
line => $s->{line},
|
file => $file,
|
file => $file,
|
module => $rs->{t}{mod} ,
|
module => $rs->{t}{mod} ,
|
inst => $rs->{t}{name} });
|
inst => $rs->{t}{name} });
|
}',
|
}',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
},
|
},
|
INST_NUMBERED_PORT => {
|
INST_NUMBERED_PORT => {
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
COMMA => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
|
},
|
},
|
IN_EVENT_BRACKET_EDGE => {
|
IN_EVENT_BRACKET_EDGE => {
|
VID => 'if (exists($rs->{p}{signals}{$match})) {
|
VID => 'if (exists($rs->{p}{signals}{$match})) {
|
$rs->{p}{signals}{$match}{$edgeType}=1; };',
|
$rs->{p}{signals}{$match}{$edgeType}=1; };',
|
},
|
},
|
|
|
STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
|
STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
|
EQUALS => 'foreach my $s (@vids) {
|
EQUALS => 'foreach my $s (@vids) {
|
my $sigp = undef;
|
my $sigp = undef;
|
if ( exists($rs->{p}{signals}{$s->{name}} )) {
|
if ( exists($rs->{p}{signals}{$s->{name}} )) {
|
$sigp = $rs->{p}{signals}{$s->{name}};
|
$sigp = $rs->{p}{signals}{$s->{name}};
|
}
|
}
|
elsif ( exists($rs->{p}{m_signals}) &&
|
elsif ( exists($rs->{p}{m_signals}) &&
|
exists($rs->{p}{m_signals}{$s->{name}}) ) {
|
exists($rs->{p}{m_signals}{$s->{name}}) ) {
|
$sigp = $rs->{p}{m_signals}{$s->{name}};
|
$sigp = $rs->{p}{m_signals}{$s->{name}};
|
}
|
}
|
if (defined($sigp) && ($sigp->{a_line}==-1)) {
|
if (defined($sigp) && ($sigp->{a_line}==-1)) {
|
$sigp->{a_line}=$s->{line};
|
$sigp->{a_line}=$s->{line};
|
$sigp->{a_file}=$file;
|
$sigp->{a_file}=$file;
|
_add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
|
_add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
|
}
|
}
|
}',
|
}',
|
},
|
},
|
STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
|
STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
|
EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
|
EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
|
},
|
},
|
ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
|
ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
|
VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
|
VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
|
$rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
|
$rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
|
push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
|
push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
|
_add_anchor($rs->{files}{$file}{anchors},$line,"");',
|
_add_anchor($rs->{files}{$file}{anchors},$line,"");',
|
},
|
},
|
};
|
};
|
|
|
############################################################
|
############################################################
|
# language definition
|
# language definition
|
############################################################
|
############################################################
|
|
|
$vid_vnum_or_string =
|
$vid_vnum_or_string =
|
[ { arcName=> 'HVID', regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
|
[ { arcName=> 'HVID', regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
|
{ arcName=> 'VID', regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
|
{ arcName=> 'VID', regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
|
{ arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
|
{ arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
|
{ arcName=> 'STRING', regexp=> '\\"', nextState=> ['IN_STRING','$ps->{curState}'],},
|
{ arcName=> 'STRING', regexp=> '\\"', nextState=> ['IN_STRING','$ps->{curState}'],},
|
];
|
];
|
|
|
$languageDef =
|
$languageDef =
|
[
|
[
|
{
|
{
|
stateName => 'START',
|
stateName => 'START',
|
confusedNextState => 'START',
|
confusedNextState => 'START',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'MODULE' , regexp => '\b(?:module|macromodule|primitive)\b',
|
{ arcName => 'MODULE' , regexp => '\b(?:module|macromodule|primitive)\b',
|
nextState => ['MODULE_NAME'] ,},
|
nextState => ['MODULE_NAME'] ,},
|
{ arcName => 'CONFIG', regexp => '\bconfig\b', # V2001
|
{ arcName => 'CONFIG', regexp => '\bconfig\b', # V2001
|
nextState => ['CONFIG'] , },
|
nextState => ['CONFIG'] , },
|
{ arcName => 'LIBRARY', regexp => '\blibrary\b', # V2001
|
{ arcName => 'LIBRARY', regexp => '\blibrary\b', # V2001
|
nextState => ['LIBRARY'] , },
|
nextState => ['LIBRARY'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'MODULE',
|
stateName => 'MODULE',
|
confusedNextState => 'MODULE',
|
confusedNextState => 'MODULE',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'ENDMODULE' , regexp => '\b(?:end(?:module|primitive))\b',
|
{ arcName => 'ENDMODULE' , regexp => '\b(?:end(?:module|primitive))\b',
|
nextState => ['START'] , },
|
nextState => ['START'] , },
|
{ arcName => 'FUNCTION', regexp => '\bfunction\b',
|
{ arcName => 'FUNCTION', regexp => '\bfunction\b',
|
nextState => ['FUNCTION'] , },
|
nextState => ['FUNCTION'] , },
|
{ arcName => 'TASK', regexp => '\btask\b',
|
{ arcName => 'TASK', regexp => '\btask\b',
|
nextState => ['TASK'] , },
|
nextState => ['TASK'] , },
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
nextState => ['PARAM_TYPE','MODULE'] , },
|
nextState => ['PARAM_TYPE','MODULE'] , },
|
{ arcName => 'SPECIFY', regexp => '\bspecify\b',
|
{ arcName => 'SPECIFY', regexp => '\bspecify\b',
|
nextState => ['SPECIFY'] , },
|
nextState => ['SPECIFY'] , },
|
{ arcName => 'TABLE', regexp => '\btable\b',
|
{ arcName => 'TABLE', regexp => '\btable\b',
|
nextState => ['TABLE'] , },
|
nextState => ['TABLE'] , },
|
{ arcName => 'EVENT_DECLARATION' , regexp => '\bevent\b' ,
|
{ arcName => 'EVENT_DECLARATION' , regexp => '\bevent\b' ,
|
nextState => ['EVENT_DECLARATION'] , },
|
nextState => ['EVENT_DECLARATION'] , },
|
{ arcName => 'DEFPARAM' , regexp => '\bdefparam\b' ,
|
{ arcName => 'DEFPARAM' , regexp => '\bdefparam\b' ,
|
nextState => ['DEFPARAM'] , },
|
nextState => ['DEFPARAM'] , },
|
{ arcName => 'GATE' , regexp => "$verilog_gatetype_regexp" ,
|
{ arcName => 'GATE' , regexp => "$verilog_gatetype_regexp" ,
|
nextState => ['GATE'] , },
|
nextState => ['GATE'] , },
|
{ arcName => 'ASSIGN' , regexp => '\bassign\b' ,
|
{ arcName => 'ASSIGN' , regexp => '\bassign\b' ,
|
nextState => ['ASSIGN'] , },
|
nextState => ['ASSIGN'] , },
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
nextState => ['DRIVE_STRENGTH','MODULE'] , },
|
nextState => ['DRIVE_STRENGTH','MODULE'] , },
|
{ arcName => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
|
{ arcName => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
|
nextState => ['STMNT','MODULE'] , },
|
nextState => ['STMNT','MODULE'] , },
|
{ arcName => 'GENERATE', regexp => '\bgenerate\b', # V2001
|
{ arcName => 'GENERATE', regexp => '\bgenerate\b', # V2001
|
nextState => ['GENERATE'] , },
|
nextState => ['GENERATE'] , },
|
|
|
|
|
{ arcName => 'INST', regexp => '$VID' ,
|
{ arcName => 'INST', regexp => '$VID' ,
|
nextState => ['INST_PARAM'] , },
|
nextState => ['INST_PARAM'] , },
|
# don't put any more states here because $VID matches almost anything
|
# don't put any more states here because $VID matches almost anything
|
],
|
],
|
},################ END OF MODULE STATE
|
},################ END OF MODULE STATE
|
{
|
{
|
stateName => 'MODULE_NAME',
|
stateName => 'MODULE_NAME',
|
search => # $nState is usually MODULE_PPL, but is set to
|
search => # $nState is usually MODULE_PPL, but is set to
|
# IGNORE_MODULE when a duplicate module is found
|
# IGNORE_MODULE when a duplicate module is found
|
[ { arcName => 'NAME', regexp => '$VID' , nextState => ['$nState'] , }, ],
|
[ { arcName => 'NAME', regexp => '$VID' , nextState => ['$nState'] , }, ],
|
},
|
},
|
{
|
{
|
stateName => 'IGNORE_MODULE' , # just look for endmodule
|
stateName => 'IGNORE_MODULE' , # just look for endmodule
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [
|
search => [
|
{ arcName => 'ENDMODULE' , regexp => '\bendmodule\b',
|
{ arcName => 'ENDMODULE' , regexp => '\bendmodule\b',
|
nextState => ['START'], },
|
nextState => ['START'], },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'MODULE_PPL' , # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'MODULE_PPL' , # v2001 module_parameter_port_list (A.1.3)
|
failNextState => ['MODULE_PORTS'],
|
failNextState => ['MODULE_PORTS'],
|
search => [ { regexp => '#', nextState => ['PPL_BRACKET'], }, ],
|
search => [ { regexp => '#', nextState => ['PPL_BRACKET'], }, ],
|
},
|
},
|
{
|
{
|
stateName => 'MODULE_PORTS' , # just look for signals until ;
|
stateName => 'MODULE_PORTS' , # just look for signals until ;
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [
|
search => [
|
{ arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b', # V2001 ansi ports
|
{ arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b', # V2001 ansi ports
|
nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, },
|
nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, },
|
{ arcName => 'END', regexp => ';' , nextState => ['MODULE'] , },
|
{ arcName => 'END', regexp => ';' , nextState => ['MODULE'] , },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'FUNCTION' ,
|
stateName => 'FUNCTION' ,
|
search => [
|
search => [
|
{ arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
|
{ arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
|
{ arcName => 'TYPE', regexp => '\b(?:real|integer|time|realtime)\b',
|
{ arcName => 'TYPE', regexp => '\b(?:real|integer|time|realtime)\b',
|
nextState => ['FUNCTION'] , },
|
nextState => ['FUNCTION'] , },
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] , }, # V2001
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] , }, # V2001
|
{ arcName => 'AUTO', regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] , }, # V2001
|
{ arcName => 'AUTO', regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] , }, # V2001
|
{ arcName => 'NAME', regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] ,
|
{ arcName => 'NAME', regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] ,
|
},
|
},
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'FUNCTION_AFTER_NAME' ,
|
stateName => 'FUNCTION_AFTER_NAME' ,
|
search => [
|
search => [
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
|
{ arcName => 'BRACKET', regexp => '\(' , # V2001
|
{ arcName => 'BRACKET', regexp => '\(' , # V2001
|
nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] , },
|
nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'TASK' ,
|
stateName => 'TASK' ,
|
search => [
|
search => [
|
{ arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
|
{ arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
|
{ arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
|
{ arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
|
},
|
},
|
{
|
{
|
stateName => 'TASK_AFTER_NAME' ,
|
stateName => 'TASK_AFTER_NAME' ,
|
search => [
|
search => [
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
|
{ arcName => 'BRACKET', regexp => '\(' , # V2001
|
{ arcName => 'BRACKET', regexp => '\(' , # V2001
|
nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] , },
|
nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'T_SIGNAL' ,
|
stateName => 'T_SIGNAL' ,
|
failNextState => ['STMNT','ENDTASK'],
|
failNextState => ['STMNT','ENDTASK'],
|
search => [
|
search => [
|
{ arcName => 'ENDTASK', regexp => '\bendtask\b',
|
{ arcName => 'ENDTASK', regexp => '\bendtask\b',
|
nextState => ['MODULE'] , },
|
nextState => ['MODULE'] , },
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
|
nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
nextState => ['PARAM_TYPE','T_SIGNAL'] , },
|
nextState => ['PARAM_TYPE','T_SIGNAL'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'ENDTASK',
|
stateName => 'ENDTASK',
|
search => [
|
search => [
|
{ arcName => 'ENDTASK', regexp => '\bendtask\b',
|
{ arcName => 'ENDTASK', regexp => '\bendtask\b',
|
nextState => ['MODULE'] , },
|
nextState => ['MODULE'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'F_SIGNAL' ,
|
stateName => 'F_SIGNAL' ,
|
failNextState => ['STMNT','ENDFUNCTION'],
|
failNextState => ['STMNT','ENDFUNCTION'],
|
search => [
|
search => [
|
{ arcName => 'ENDFUNCTION', regexp => '\bendfunction\b',
|
{ arcName => 'ENDFUNCTION', regexp => '\bendfunction\b',
|
nextState => ['MODULE'] , },
|
nextState => ['MODULE'] , },
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
|
nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
{ arcName => 'PARAM', regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
|
nextState => ['PARAM_TYPE','F_SIGNAL'] , },
|
nextState => ['PARAM_TYPE','F_SIGNAL'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'ENDFUNCTION',
|
stateName => 'ENDFUNCTION',
|
search => [
|
search => [
|
{ arcName => 'ENDFUNCTION', regexp => '\bendfunction\b',
|
{ arcName => 'ENDFUNCTION', regexp => '\bendfunction\b',
|
nextState => ['MODULE'] , },
|
nextState => ['MODULE'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'PARAM_TYPE',
|
stateName => 'PARAM_TYPE',
|
failNextState => ['PARAM_NAME'],
|
failNextState => ['PARAM_NAME'],
|
search => [
|
search => [
|
{ arcName => 'RANGE', regexp => '\[' ,
|
{ arcName => 'RANGE', regexp => '\[' ,
|
nextState => ['IN_RANGE','PARAM_NAME'] , },
|
nextState => ['IN_RANGE','PARAM_NAME'] , },
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,
|
nextState => ['PARAM_TYPE'] , }, # may be followed by a range
|
nextState => ['PARAM_TYPE'] , }, # may be followed by a range
|
{ arcName => 'OTHER', regexp => '\b(?:integer|real|realtime|time)\b' ,
|
{ arcName => 'OTHER', regexp => '\b(?:integer|real|realtime|time)\b' ,
|
nextState => ['PARAM_NAME'] , },
|
nextState => ['PARAM_NAME'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'PARAM_NAME',
|
stateName => 'PARAM_NAME',
|
search => [
|
search => [
|
{ arcName => 'NAME', regexp => '$VID' ,
|
{ arcName => 'NAME', regexp => '$VID' ,
|
nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
|
nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'PARAMETER_EQUAL',
|
stateName => 'PARAMETER_EQUAL',
|
search => [ { regexp => '=' , storePos => 1, }, ]
|
search => [ { regexp => '=' , storePos => 1, }, ]
|
},
|
},
|
{
|
{
|
stateName => 'PARAM_AFTER_EQUALS',
|
stateName => 'PARAM_AFTER_EQUALS',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'CONCAT', regexp => '{' ,
|
{ arcName => 'CONCAT', regexp => '{' ,
|
nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] , },
|
nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] , },
|
{ arcName => 'COMMA', regexp => ',' ,
|
{ arcName => 'COMMA', regexp => ',' ,
|
nextState => ['PARAM_NAME'] , },
|
nextState => ['PARAM_NAME'] , },
|
{ arcName => 'SEMICOLON', regexp => ';' , },
|
{ arcName => 'SEMICOLON', regexp => ';' , },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_CONCAT',
|
stateName => 'IN_CONCAT',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'CONCAT' , regexp => '{' ,
|
{ arcName => 'CONCAT' , regexp => '{' ,
|
nextState => ['IN_CONCAT','IN_CONCAT'] , },
|
nextState => ['IN_CONCAT','IN_CONCAT'] , },
|
{ arcName => 'END' , regexp => '}' , }, # pop up
|
{ arcName => 'END' , regexp => '}' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_RANGE',
|
stateName => 'IN_RANGE',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
nextState => ['IN_RANGE','IN_RANGE'] , },
|
nextState => ['IN_RANGE','IN_RANGE'] , },
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_SIG_RANGE', # just like in range, but stores
|
stateName => 'IN_SIG_RANGE', # just like in range, but stores
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
|
nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_MEM_RANGE', # just like in range, but stores
|
stateName => 'IN_MEM_RANGE', # just like in range, but stores
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
|
nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
{ arcName => 'END' , regexp => '\]' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_BRACKET',
|
stateName => 'IN_BRACKET',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'BRACKET' , regexp => '\(' ,
|
{ arcName => 'BRACKET' , regexp => '\(' ,
|
nextState => ['IN_BRACKET','IN_BRACKET'] , },
|
nextState => ['IN_BRACKET','IN_BRACKET'] , },
|
{ arcName => 'END' , regexp => '\)' , }, # pop up
|
{ arcName => 'END' , regexp => '\)' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_STRING',
|
stateName => 'IN_STRING',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[ # note: put \" in regexp so that emacs colouring doesn't get confused
|
[ # note: put \" in regexp so that emacs colouring doesn't get confused
|
{ arcName => 'ESCAPED_QUOTE' , regexp => '\\\\\\"' , # match \"
|
{ arcName => 'ESCAPED_QUOTE' , regexp => '\\\\\\"' , # match \"
|
nextState => ['IN_STRING'] , },
|
nextState => ['IN_STRING'] , },
|
# match \\ (to make sure that \\" does not match \"
|
# match \\ (to make sure that \\" does not match \"
|
{ arcName => 'ESCAPE' , regexp => '\\\\\\\\' ,
|
{ arcName => 'ESCAPE' , regexp => '\\\\\\\\' ,
|
nextState => ['IN_STRING'] , },
|
nextState => ['IN_STRING'] , },
|
{ arcName => 'END' , regexp => '\\"' , }, # match " and pop up
|
{ arcName => 'END' , regexp => '\\"' , }, # match " and pop up
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'SPECIFY',
|
stateName => 'SPECIFY',
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,},
|
search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,},
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'TABLE',
|
stateName => 'TABLE',
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => '\bendtable\b' , nextState => ['MODULE'] ,},
|
search => [ { regexp => '\bendtable\b' , nextState => ['MODULE'] ,},
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'EVENT_DECLARATION' , # just look for ;
|
stateName => 'EVENT_DECLARATION' , # just look for ;
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'DEFPARAM' , # just look for ;
|
stateName => 'DEFPARAM' , # just look for ;
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
# REVISIT: could find signal driven by gate here (is output always the first one??)
|
# REVISIT: could find signal driven by gate here (is output always the first one??)
|
stateName => 'GATE' ,
|
stateName => 'GATE' ,
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
search => [ { regexp => ';' , nextState => ['MODULE'] , },
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'ASSIGN',
|
stateName => 'ASSIGN',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
{ arcName => 'RANGE' , regexp => '\[' ,
|
nextState => ['IN_RANGE','ASSIGN'] , },
|
nextState => ['IN_RANGE','ASSIGN'] , },
|
{ arcName => 'EQUALS' , regexp => '=' ,
|
{ arcName => 'EQUALS' , regexp => '=' ,
|
nextState => ['ASSIGN_AFTER_EQUALS'] , },
|
nextState => ['ASSIGN_AFTER_EQUALS'] , },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'ASSIGN_AFTER_EQUALS' ,
|
stateName => 'ASSIGN_AFTER_EQUALS' ,
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName=>'COMMA', regexp => ',',
|
{ arcName=>'COMMA', regexp => ',',
|
nextState => ['ASSIGN'],},
|
nextState => ['ASSIGN'],},
|
{ arcName=>'CONCAT', regexp => '{',
|
{ arcName=>'CONCAT', regexp => '{',
|
nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
|
nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
|
# don't get confused by function calls (which can also contain commas)
|
# don't get confused by function calls (which can also contain commas)
|
{ arcName=>'BRACKET', regexp => '\(',
|
{ arcName=>'BRACKET', regexp => '\(',
|
nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
|
nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
|
{ arcName=>'END', regexp => ';',
|
{ arcName=>'END', regexp => ';',
|
nextState => ['MODULE'],},
|
nextState => ['MODULE'],},
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'DRIVE_STRENGTH', # signal defs - drive strength or charge strength
|
stateName => 'DRIVE_STRENGTH', # signal defs - drive strength or charge strength
|
failNextState => ['SCALARED_OR_VECTORED'],
|
failNextState => ['SCALARED_OR_VECTORED'],
|
search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
|
search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
|
},
|
},
|
{ # REVISIT: V2001 - the name of this is misleading now
|
{ # REVISIT: V2001 - the name of this is misleading now
|
stateName => 'SCALARED_OR_VECTORED', # for signal defs
|
stateName => 'SCALARED_OR_VECTORED', # for signal defs
|
failNextState => ['SIGNAL_RANGE'],
|
failNextState => ['SIGNAL_RANGE'],
|
search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
|
search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
|
{ arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
|
{ arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
|
nextState => ['SCALARED_OR_VECTORED'],},
|
nextState => ['SCALARED_OR_VECTORED'],},
|
{ regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
|
{ regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
|
},
|
},
|
{
|
{
|
stateName => 'SIGNAL_RANGE', # for signal defs
|
stateName => 'SIGNAL_RANGE', # for signal defs
|
failNextState => ['SIGNAL_DELAY'],
|
failNextState => ['SIGNAL_DELAY'],
|
search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
|
search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
|
storePos => 1,}, ],
|
storePos => 1,}, ],
|
},
|
},
|
{
|
{
|
stateName => 'SIGNAL_DELAY', # for signal defs
|
stateName => 'SIGNAL_DELAY', # for signal defs
|
failNextState => ['SIGNAL_NAME'],
|
failNextState => ['SIGNAL_NAME'],
|
search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],}, ],
|
search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],}, ],
|
},
|
},
|
{
|
{
|
stateName => 'SIGNAL_NAME', # for signal defs
|
stateName => 'SIGNAL_NAME', # for signal defs
|
search => [ { arcName => 'VID' , regexp => '$VID',
|
search => [ { arcName => 'VID' , regexp => '$VID',
|
nextState => ['SIGNAL_AFTER_NAME'], }, ],
|
nextState => ['SIGNAL_AFTER_NAME'], }, ],
|
},
|
},
|
{ # for signal defs
|
{ # for signal defs
|
stateName => 'SIGNAL_AFTER_NAME',
|
stateName => 'SIGNAL_AFTER_NAME',
|
search =>
|
search =>
|
[
|
[
|
{ regexp => ',', nextState => ['SIGNAL_NAME'],},
|
{ regexp => ',', nextState => ['SIGNAL_NAME'],},
|
{ regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
|
{ regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
|
storePos => 1 , }, # memories
|
storePos => 1 , }, # memories
|
{ arcName => 'SEMICOLON' , regexp => ';',}, # pop up
|
{ arcName => 'SEMICOLON' , regexp => ';',}, # pop up
|
{ arcName => 'ASSIGN', regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
|
{ arcName => 'ASSIGN', regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'SIGNAL_AFTER_EQUALS' ,
|
stateName => 'SIGNAL_AFTER_EQUALS' ,
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ regexp => ',', nextState => ['SIGNAL_NAME'],},
|
{ regexp => ',', nextState => ['SIGNAL_NAME'],},
|
{ regexp => '{', nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
|
{ regexp => '{', nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
|
{ regexp => '\(', nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
|
{ regexp => '\(', nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
|
{ arcName => 'END', regexp => ';', }, # pop up
|
{ arcName => 'END', regexp => ';', }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'INST_PARAM',
|
stateName => 'INST_PARAM',
|
failNextState => ['INST_NAME'],
|
failNextState => ['INST_NAME'],
|
search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
|
search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
|
},
|
},
|
{
|
{
|
stateName => 'INST_PARAM_BRACKET',
|
stateName => 'INST_PARAM_BRACKET',
|
search => [ { arcName => 'BRACKET' ,
|
search => [ { arcName => 'BRACKET' ,
|
regexp => '\(',
|
regexp => '\(',
|
storePos => 1,
|
storePos => 1,
|
nextState=> ['INST_PARAM_VALUE'],},
|
nextState=> ['INST_PARAM_VALUE'],},
|
# this is here to catch and illegal case which DC accepts
|
# this is here to catch and illegal case which DC accepts
|
{ arcName => 'NO_BRACKET' ,
|
{ arcName => 'NO_BRACKET' ,
|
regexp => '($VID|$VNUM)',
|
regexp => '($VID|$VNUM)',
|
nextState=> ['INST_NAME'],}, ],
|
nextState=> ['INST_NAME'],}, ],
|
},
|
},
|
{
|
{
|
stateName => 'INST_PARAM_VALUE',
|
stateName => 'INST_PARAM_VALUE',
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [
|
search => [
|
{ regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
|
{ regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
|
{ regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
|
{ regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
|
{ regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
|
{ regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
|
{ arcName => 'COMMA' ,
|
{ arcName => 'COMMA' ,
|
regexp => ',',
|
regexp => ',',
|
storePos => 1,
|
storePos => 1,
|
nextState=> ['INST_PARAM_VALUE'],},
|
nextState=> ['INST_PARAM_VALUE'],},
|
{ arcName => 'END' ,
|
{ arcName => 'END' ,
|
regexp => '\)',
|
regexp => '\)',
|
nextState=> ['INST_NAME'],},
|
nextState=> ['INST_NAME'],},
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'INST_NAME',
|
stateName => 'INST_NAME',
|
failNextState => ['INST_BRACKET'],
|
failNextState => ['INST_BRACKET'],
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'VID' , regexp => '$VID',
|
{ arcName => 'VID' , regexp => '$VID',
|
nextState => ['INST_RANGE'], },
|
nextState => ['INST_RANGE'], },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'INST_NO_NAME' ,
|
stateName => 'INST_NO_NAME' ,
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
|
search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'INST_RANGE',
|
stateName => 'INST_RANGE',
|
failNextState => ['INST_BRACKET'],
|
failNextState => ['INST_BRACKET'],
|
search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
|
search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
|
},
|
},
|
{
|
{
|
stateName => 'INST_BRACKET',
|
stateName => 'INST_BRACKET',
|
search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
|
search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
|
},
|
},
|
{
|
{
|
stateName => 'INST_PORTS',
|
stateName => 'INST_PORTS',
|
failNextState => ['INST_NUMBERED_PORT'],
|
failNextState => ['INST_NUMBERED_PORT'],
|
failStorePos => 1,
|
failStorePos => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'COMMA', regexp => ',', nextState => ['INST_PORTS'], },
|
{ arcName => 'COMMA', regexp => ',', nextState => ['INST_PORTS'], },
|
{ regexp => '\.', nextState => ['INST_PORT_NAME'], },
|
{ regexp => '\.', nextState => ['INST_PORT_NAME'], },
|
{ regexp => '\)', nextState => ['AFTER_INST'], },
|
{ regexp => '\)', nextState => ['AFTER_INST'], },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'INST_PORT_NAME',
|
stateName => 'INST_PORT_NAME',
|
search => [ { arcName => 'NAME' , regexp => '$VID',
|
search => [ { arcName => 'NAME' , regexp => '$VID',
|
nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
|
nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
|
'INST_NAMED_PORT_CON_AFTER'], }, ],
|
'INST_NAMED_PORT_CON_AFTER'], }, ],
|
},
|
},
|
{
|
{
|
stateName => 'INST_NAMED_PORT_BRACKET',
|
stateName => 'INST_NAMED_PORT_BRACKET',
|
search => [ { regexp => '\(' , storePos => 1, },]
|
search => [ { regexp => '\(' , storePos => 1, },]
|
},
|
},
|
{
|
{
|
stateName => 'INST_NAMED_PORT_CON',
|
stateName => 'INST_NAMED_PORT_CON',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
|
{ regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
|
{ regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
|
{ regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
|
{ regexp => '\(' ,
|
{ regexp => '\(' ,
|
nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
|
nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
|
{ arcName => 'END', regexp => '\)' , }, # pop up
|
{ arcName => 'END', regexp => '\)' , }, # pop up
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'INST_NAMED_PORT_CON_AFTER',
|
stateName => 'INST_NAMED_PORT_CON_AFTER',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'BRACKET', regexp => '\)' ,
|
{ arcName => 'BRACKET', regexp => '\)' ,
|
nextState => ['AFTER_INST']},
|
nextState => ['AFTER_INST']},
|
{ arcName => 'COMMA' , regexp => ',' ,
|
{ arcName => 'COMMA' , regexp => ',' ,
|
nextState => ['INST_DOT']},
|
nextState => ['INST_DOT']},
|
]
|
]
|
},
|
},
|
{ stateName => 'INST_DOT',
|
{ stateName => 'INST_DOT',
|
search =>
|
search =>
|
[
|
[
|
{ regexp => '\.' , nextState => ['INST_PORT_NAME']},
|
{ regexp => '\.' , nextState => ['INST_PORT_NAME']},
|
{ regexp => ',' , nextState => ['INST_DOT']}, # blank port
|
{ regexp => ',' , nextState => ['INST_DOT']}, # blank port
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'INST_NUMBERED_PORT',
|
stateName => 'INST_NUMBERED_PORT',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
|
{ regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
|
{ regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
|
{ regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
|
{ regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
|
{ regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
|
{ arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
|
{ arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
|
{ arcName => 'COMMA' , regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
|
{ arcName => 'COMMA' , regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
|
storePos => 1, },
|
storePos => 1, },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{ stateName => 'AFTER_INST',
|
{ stateName => 'AFTER_INST',
|
search => [
|
search => [
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
|
{ arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
|
{ arcName => 'COMMA', regexp => ',', nextState => ['INST_NAME'], },
|
{ arcName => 'COMMA', regexp => ',', nextState => ['INST_NAME'], },
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'STMNT',
|
stateName => 'STMNT',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'IF', regexp => '\bif\b' ,
|
{ arcName => 'IF', regexp => '\bif\b' ,
|
nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
|
nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
|
{ arcName => 'REPEAT_WHILE_FOR_WAIT', regexp => '\b(?:repeat|while|for|wait)\b' ,
|
{ arcName => 'REPEAT_WHILE_FOR_WAIT', regexp => '\b(?:repeat|while|for|wait)\b' ,
|
nextState => ['BRACKET','IN_BRACKET','STMNT'] , },
|
nextState => ['BRACKET','IN_BRACKET','STMNT'] , },
|
{ arcName => 'FOREVER', regexp => '\bforever\b' ,
|
{ arcName => 'FOREVER', regexp => '\bforever\b' ,
|
nextState => ['STMNT'] , },
|
nextState => ['STMNT'] , },
|
{ arcName => 'CASE', regexp => '\bcase[xz]?\b' ,
|
{ arcName => 'CASE', regexp => '\bcase[xz]?\b' ,
|
nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
|
nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
|
{ arcName => 'BEGIN', regexp => '\bbegin\b' ,
|
{ arcName => 'BEGIN', regexp => '\bbegin\b' ,
|
nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
|
nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
|
{ arcName => 'FORK', regexp => '\bfork\b' ,
|
{ arcName => 'FORK', regexp => '\bfork\b' ,
|
nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
|
nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
|
{ arcName => 'DELAY', regexp => '\#' ,
|
{ arcName => 'DELAY', regexp => '\#' ,
|
nextState => ['DELAY_VALUE','STMNT'] , },
|
nextState => ['DELAY_VALUE','STMNT'] , },
|
{ arcName => 'EVENT_CONTROL', regexp => '\@' ,
|
{ arcName => 'EVENT_CONTROL', regexp => '\@' ,
|
nextState => ['EVENT_CONTROL'] , },
|
nextState => ['EVENT_CONTROL'] , },
|
{ arcName => 'SYSTEM_TASK', regexp => '\$$VID' ,
|
{ arcName => 'SYSTEM_TASK', regexp => '\$$VID' ,
|
nextState => ['SYSTEM_TASK'] , },
|
nextState => ['SYSTEM_TASK'] , },
|
{ arcName => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
|
{ arcName => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
|
regexp => '\b(?:disable|assign|deassign|force|release)\b',
|
regexp => '\b(?:disable|assign|deassign|force|release)\b',
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
|
# a assignment to a hierarchical thing mustn't collect the vid
|
# a assignment to a hierarchical thing mustn't collect the vid
|
# like a normal assign as hierarchical nets/signals will confuse downstream code
|
# like a normal assign as hierarchical nets/signals will confuse downstream code
|
{ arcName => 'HIER_ASSIGN_OR_TASK', regexp => '$HVID' ,
|
{ arcName => 'HIER_ASSIGN_OR_TASK', regexp => '$HVID' ,
|
nextState => ['STMNT_ASSIGN_OR_TASK'] , },
|
nextState => ['STMNT_ASSIGN_OR_TASK'] , },
|
{ arcName => 'ASSIGN_OR_TASK', regexp => '$VID' ,
|
{ arcName => 'ASSIGN_OR_TASK', regexp => '$VID' ,
|
nextState => ['STMNT_ASSIGN_OR_TASK'] , },
|
nextState => ['STMNT_ASSIGN_OR_TASK'] , },
|
{ arcName => 'CONCAT', regexp => '{' ,
|
{ arcName => 'CONCAT', regexp => '{' ,
|
nextState => ['IN_CONCAT','STMNT_ASSIGN'] , },
|
nextState => ['IN_CONCAT','STMNT_ASSIGN'] , },
|
{ arcName => 'NULL', regexp => ';' ,
|
{ arcName => 'NULL', regexp => ';' ,
|
}, # pop up
|
}, # pop up
|
{ arcName => 'POINTY_THING', regexp => '->' , # not sure what this is!
|
{ arcName => 'POINTY_THING', regexp => '->' , # not sure what this is!
|
nextState => ['POINTY_THING_NAME'] , },
|
nextState => ['POINTY_THING_NAME'] , },
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'MAYBE_ELSE',
|
stateName => 'MAYBE_ELSE',
|
failNextState => [] , # don't get confused, just pop the stack for the next state
|
failNextState => [] , # don't get confused, just pop the stack for the next state
|
search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
|
search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
|
},
|
},
|
{
|
{
|
stateName => 'BLOCK_NAME',
|
stateName => 'BLOCK_NAME',
|
failNextState => [] , # don't get confused, just pop the stack for the next state
|
failNextState => [] , # don't get confused, just pop the stack for the next state
|
search => [{ arcName => 'COLON', regexp => ':' ,
|
search => [{ arcName => 'COLON', regexp => ':' ,
|
nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
|
nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
|
},
|
},
|
{
|
{
|
stateName => 'BLOCK_NAME_AFTER_COLON',
|
stateName => 'BLOCK_NAME_AFTER_COLON',
|
search => [ { arcName => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
|
search => [ { arcName => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
|
},
|
},
|
{
|
{
|
stateName => 'BLOCK_SIGNAL' ,
|
stateName => 'BLOCK_SIGNAL' ,
|
failNextState => [], # don't get confused, just pop the stack for the next state
|
failNextState => [], # don't get confused, just pop the stack for the next state
|
search => [
|
search => [
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
{ arcName => 'SIGNAL' , regexp => "$verilog_sigs_regexp" ,
|
nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
|
nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
|
],
|
],
|
},
|
},
|
|
|
|
|
{
|
{
|
stateName => 'IN_SEQ_BLOCK',
|
stateName => 'IN_SEQ_BLOCK',
|
failNextState => ['STMNT','IN_SEQ_BLOCK'] ,
|
failNextState => ['STMNT','IN_SEQ_BLOCK'] ,
|
search => [{ arcName => 'END', regexp => '\bend\b' , }, ]
|
search => [{ arcName => 'END', regexp => '\bend\b' , }, ]
|
},
|
},
|
{
|
{
|
stateName => 'IN_PAR_BLOCK',
|
stateName => 'IN_PAR_BLOCK',
|
failNextState => ['STMNT','IN_PAR_BLOCK'] ,
|
failNextState => ['STMNT','IN_PAR_BLOCK'] ,
|
search => [{ arcName => 'JOIN', regexp => '\bjoin\b' , }, ]
|
search => [{ arcName => 'JOIN', regexp => '\bjoin\b' , }, ]
|
},
|
},
|
{
|
{
|
stateName => 'DELAY_VALUE',
|
stateName => 'DELAY_VALUE',
|
search =>
|
search =>
|
[{ arcName => 'NUMBER', regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
|
[{ arcName => 'NUMBER', regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
|
{ arcName => 'ID', regexp => '$VID', nextState => ['DELAY_COLON1'], },
|
{ arcName => 'ID', regexp => '$VID', nextState => ['DELAY_COLON1'], },
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET','DELAY_COLON1'],},]
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET','DELAY_COLON1'],},]
|
},
|
},
|
{
|
{
|
stateName => 'DELAY_COLON1',
|
stateName => 'DELAY_COLON1',
|
failNextState => [] , # popup
|
failNextState => [] , # popup
|
search => [{ arcName => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
|
search => [{ arcName => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
|
},
|
},
|
{
|
{
|
stateName => 'DELAY_VALUE2',
|
stateName => 'DELAY_VALUE2',
|
search =>
|
search =>
|
[{ arcName => 'NUMBER', regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
|
[{ arcName => 'NUMBER', regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
|
{ arcName => 'ID', regexp => '$VID', nextState => ['DELAY_COLON2'], },
|
{ arcName => 'ID', regexp => '$VID', nextState => ['DELAY_COLON2'], },
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET','DELAY_COLON2'],},]
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET','DELAY_COLON2'],},]
|
},
|
},
|
{
|
{
|
stateName => 'DELAY_COLON2',
|
stateName => 'DELAY_COLON2',
|
search => [{ arcName => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
|
search => [{ arcName => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
|
},
|
},
|
{
|
{
|
stateName => 'DELAY_VALUE3',
|
stateName => 'DELAY_VALUE3',
|
search =>
|
search =>
|
[{ arcName => 'NUMBER', regexp => '$VNUM', },
|
[{ arcName => 'NUMBER', regexp => '$VNUM', },
|
{ arcName => 'ID', regexp => '$VID', },
|
{ arcName => 'ID', regexp => '$VID', },
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET'],}, ]
|
{ arcName => 'BRACKET', regexp => '\(', nextState => ['IN_BRACKET'],}, ]
|
},
|
},
|
{
|
{
|
stateName => 'EVENT_CONTROL',
|
stateName => 'EVENT_CONTROL',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'ID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
|
{ arcName => 'ID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
|
{ arcName => 'STAR', regexp => '\*', nextState => ['STMNT'], }, # V2001
|
{ arcName => 'STAR', regexp => '\*', nextState => ['STMNT'], }, # V2001
|
{ arcName => 'BRACKET', regexp => '\(',
|
{ arcName => 'BRACKET', regexp => '\(',
|
nextState => ['IN_EVENT_BRACKET','STMNT'], },
|
nextState => ['IN_EVENT_BRACKET','STMNT'], },
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'IN_EVENT_BRACKET',
|
stateName => 'IN_EVENT_BRACKET',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
# must go before vid_vnum_or_string as posedge and negedge look like VIDs
|
# must go before vid_vnum_or_string as posedge and negedge look like VIDs
|
{ arcName => 'EDGE' , regexp => '\b(?:posedge|negedge)\b' ,
|
{ arcName => 'EDGE' , regexp => '\b(?:posedge|negedge)\b' ,
|
nextState => ['IN_EVENT_BRACKET_EDGE'] , },
|
nextState => ['IN_EVENT_BRACKET_EDGE'] , },
|
{ arcName => 'BRACKET' , regexp => '\(' ,
|
{ arcName => 'BRACKET' , regexp => '\(' ,
|
nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
|
nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
|
{ arcName => 'STAR', regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
|
{ arcName => 'STAR', regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
|
{ arcName => 'END' , regexp => '\)' , }, # popup
|
{ arcName => 'END' , regexp => '\)' , }, # popup
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{ # in theory there could be an expression here, I just take the first VID
|
{ # in theory there could be an expression here, I just take the first VID
|
stateName => 'IN_EVENT_BRACKET_EDGE',
|
stateName => 'IN_EVENT_BRACKET_EDGE',
|
failNextState => ['IN_EVENT_BRACKET'] ,
|
failNextState => ['IN_EVENT_BRACKET'] ,
|
search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
|
search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
|
},
|
},
|
{
|
{
|
stateName => 'STMNT_ASSIGN_OR_TASK',
|
stateName => 'STMNT_ASSIGN_OR_TASK',
|
failNextState => ['STMNT_SEMICOLON'],
|
failNextState => ['STMNT_SEMICOLON'],
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'EQUALS', regexp => '[<]?=',
|
{ arcName => 'EQUALS', regexp => '[<]?=',
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
|
{ arcName => 'RANGE', regexp => '\[',
|
{ arcName => 'RANGE', regexp => '\[',
|
nextState => ['IN_RANGE','STMNT_ASSIGN'],},
|
nextState => ['IN_RANGE','STMNT_ASSIGN'],},
|
{ arcName => 'BRACKET', regexp => '\(', # task with params
|
{ arcName => 'BRACKET', regexp => '\(', # task with params
|
nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },
|
nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },
|
]
|
]
|
},
|
},
|
{
|
{
|
stateName => 'STMNT_ASSIGN',
|
stateName => 'STMNT_ASSIGN',
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'EQUALS', regexp => '[<]?=',
|
{ arcName => 'EQUALS', regexp => '[<]?=',
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
|
nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
|
{ arcName => 'RANGE', regexp => '\[',
|
{ arcName => 'RANGE', regexp => '\[',
|
nextState => ['IN_RANGE','STMNT_ASSIGN'],},
|
nextState => ['IN_RANGE','STMNT_ASSIGN'],},
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'SYSTEM_TASK',
|
stateName => 'SYSTEM_TASK',
|
failNextState => ['STMNT_SEMICOLON'],
|
failNextState => ['STMNT_SEMICOLON'],
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'BRACKET', regexp => '\(',
|
{ arcName => 'BRACKET', regexp => '\(',
|
nextState => ['IN_BRACKET','STMNT_SEMICOLON'], }, ],
|
nextState => ['IN_BRACKET','STMNT_SEMICOLON'], }, ],
|
},
|
},
|
{
|
{
|
stateName => 'POINTY_THING_NAME',
|
stateName => 'POINTY_THING_NAME',
|
search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
|
search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
|
},
|
},
|
{
|
{
|
stateName => 'CASE_ITEM',
|
stateName => 'CASE_ITEM',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'END', regexp => '\bendcase\b', },
|
{ arcName => 'END', regexp => '\bendcase\b', },
|
{ arcName => 'COLON', regexp => ':',
|
{ arcName => 'COLON', regexp => ':',
|
nextState => ['STMNT','CASE_ITEM'], },
|
nextState => ['STMNT','CASE_ITEM'], },
|
{ arcName => 'DEFAULT', regexp => '\bdefault\b',
|
{ arcName => 'DEFAULT', regexp => '\bdefault\b',
|
nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
|
nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
|
# don't get confused by colons in ranges
|
# don't get confused by colons in ranges
|
{ arcName => 'RANGE', regexp => '\[',
|
{ arcName => 'RANGE', regexp => '\[',
|
nextState => ['IN_RANGE','CASE_ITEM'], },
|
nextState => ['IN_RANGE','CASE_ITEM'], },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'MAYBE_COLON',
|
stateName => 'MAYBE_COLON',
|
failNextState => [],
|
failNextState => [],
|
search => [ { regexp => ':' , }, ]
|
search => [ { regexp => ':' , }, ]
|
},
|
},
|
{ # look for ; but also allow the ending of a statement with an end
|
{ # 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)
|
# even though it is not really legal (verilog seems to accept it, so I do too)
|
stateName => 'STMNT_JUNK_TO_SEMICOLON' ,
|
stateName => 'STMNT_JUNK_TO_SEMICOLON' ,
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [
|
search => [
|
{ regexp => ';' , },
|
{ regexp => ';' , },
|
# popup and reset pos to before the end/join cope with nosemicolon case
|
# popup and reset pos to before the end/join cope with nosemicolon case
|
{ regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
|
{ regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
],
|
],
|
},
|
},
|
{
|
{
|
stateName => 'STMNT_SEMICOLON',
|
stateName => 'STMNT_SEMICOLON',
|
search => [ { regexp => ';' , },
|
search => [ { regexp => ';' , },
|
# popup and reset pos to before the end/join cope with nosemicolon case
|
# popup and reset pos to before the end/join cope with nosemicolon case
|
{ regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
|
{ regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
|
],
|
],
|
},
|
},
|
{ stateName => 'BRACKET', search => [ { regexp => '\(' , },] },
|
{ stateName => 'BRACKET', search => [ { regexp => '\(' , },] },
|
{ stateName => 'SEMICOLON', search => [ { regexp => ';' , },] },
|
{ stateName => 'SEMICOLON', search => [ { regexp => ';' , },] },
|
# V2001
|
# V2001
|
{
|
{
|
stateName => 'CONFIG',
|
stateName => 'CONFIG',
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,},
|
search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,},
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'LIBRARY' , # just look for ;
|
stateName => 'LIBRARY' , # just look for ;
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => ';' , nextState => ['START'] , },
|
search => [ { regexp => ';' , nextState => ['START'] , },
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
{
|
{
|
stateName => 'GENERATE',
|
stateName => 'GENERATE',
|
allowAnything => 1,
|
allowAnything => 1,
|
search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,},
|
search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,},
|
@$vid_vnum_or_string,],
|
@$vid_vnum_or_string,],
|
},
|
},
|
|
|
|
|
|
|
{ # V2001 ansi module ports
|
{ # V2001 ansi module ports
|
stateName => 'ANSI_PORTS_TYPE',
|
stateName => 'ANSI_PORTS_TYPE',
|
failNextState => ['ANSI_PORTS_TYPE2'],
|
failNextState => ['ANSI_PORTS_TYPE2'],
|
search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
|
search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
|
nextState => ['ANSI_PORTS_TYPE2'],},
|
nextState => ['ANSI_PORTS_TYPE2'],},
|
# a null list. note this is only possible for a task or function
|
# 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)
|
# (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.
|
# but it is not legal acording to the BNF. I allow it any way.
|
{ regexp => '\)', nextState => ['SEMICOLON'], },
|
{ regexp => '\)', nextState => ['SEMICOLON'], },
|
],
|
],
|
},
|
},
|
{ # V2001 ansi module ports
|
{ # V2001 ansi module ports
|
stateName => 'ANSI_PORTS_TYPE2',
|
stateName => 'ANSI_PORTS_TYPE2',
|
failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
|
failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
|
search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp",
|
search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp",
|
nextState => ['ANSI_PORTS_TYPE2'],},
|
nextState => ['ANSI_PORTS_TYPE2'],},
|
{ regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
|
{ regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
|
},
|
},
|
{ # V2001 ansi module ports
|
{ # V2001 ansi module ports
|
stateName => 'ANSI_PORTS_SIGNAL_RANGE', # for signal defs
|
stateName => 'ANSI_PORTS_SIGNAL_RANGE', # for signal defs
|
failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
|
failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
|
search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
|
search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
|
storePos => 1,}, ],
|
storePos => 1,}, ],
|
},
|
},
|
{ # V2001 ansi module ports
|
{ # V2001 ansi module ports
|
stateName => 'ANSI_PORTS_SIGNAL_NAME',
|
stateName => 'ANSI_PORTS_SIGNAL_NAME',
|
search => [
|
search => [
|
{ arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
|
{ arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
|
nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, },
|
nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, },
|
{ arcName => 'VID' , regexp => '$VID',
|
{ arcName => 'VID' , regexp => '$VID',
|
nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], },
|
nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], },
|
],
|
],
|
},
|
},
|
{ # V2001 ansi module ports
|
{ # V2001 ansi module ports
|
stateName => 'ANSI_PORTS_SIGNAL_AFTER_NAME',
|
stateName => 'ANSI_PORTS_SIGNAL_AFTER_NAME',
|
search =>
|
search =>
|
[
|
[
|
{ regexp => ',', nextState => ['ANSI_PORTS_SIGNAL_NAME'],},
|
{ regexp => ',', nextState => ['ANSI_PORTS_SIGNAL_NAME'],},
|
{ regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
|
{ regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
|
{ regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
|
{ regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
|
],
|
],
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_BRACKET' ,
|
stateName => 'PPL_BRACKET' ,
|
search => [ { regexp => '\(', nextState => ['PPL_PARAM'], }, ],
|
search => [ { regexp => '\(', nextState => ['PPL_PARAM'], }, ],
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_PARAM' ,
|
stateName => 'PPL_PARAM' ,
|
search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
|
search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_TYPE',
|
stateName => 'PPL_TYPE',
|
failNextState => ['PPL_NAME'],
|
failNextState => ['PPL_NAME'],
|
search => [
|
search => [
|
{ arcName => 'RANGE', regexp => '\[' ,
|
{ arcName => 'RANGE', regexp => '\[' ,
|
nextState => ['IN_RANGE','PPL_NAME'] , },
|
nextState => ['IN_RANGE','PPL_NAME'] , },
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,
|
{ arcName => 'SIGNED', regexp => '\bsigned\b' ,
|
nextState => ['PPL_TYPE'] , }, # may be followed by a range
|
nextState => ['PPL_TYPE'] , }, # may be followed by a range
|
{ arcName => 'OTHER', regexp => '\b(?:integer|real|realtime|time)\b' ,
|
{ arcName => 'OTHER', regexp => '\b(?:integer|real|realtime|time)\b' ,
|
nextState => ['PPL_NAME'] , },
|
nextState => ['PPL_NAME'] , },
|
],
|
],
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_NAME',
|
stateName => 'PPL_NAME',
|
search => [
|
search => [
|
{ arcName => 'NAME', regexp => '$VID' ,
|
{ arcName => 'NAME', regexp => '$VID' ,
|
nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
|
nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
|
],
|
],
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_AFTER_EQUALS',
|
stateName => 'PPL_AFTER_EQUALS',
|
allowAnything => 1,
|
allowAnything => 1,
|
search =>
|
search =>
|
[
|
[
|
{ arcName => 'CONCAT', regexp => '{' ,
|
{ arcName => 'CONCAT', regexp => '{' ,
|
nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] , },
|
nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] , },
|
{ arcName => 'BRACKET', regexp => '\(' ,
|
{ arcName => 'BRACKET', regexp => '\(' ,
|
nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] , },
|
nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] , },
|
{ arcName => 'COMMA', regexp => ',' ,
|
{ arcName => 'COMMA', regexp => ',' ,
|
nextState => ['PPL_PARAM_OR_NAME'] , },
|
nextState => ['PPL_PARAM_OR_NAME'] , },
|
{ arcName => 'END', regexp => '\)' ,
|
{ arcName => 'END', regexp => '\)' ,
|
nextState => ['MODULE_PORTS'] , },
|
nextState => ['MODULE_PORTS'] , },
|
@$vid_vnum_or_string,
|
@$vid_vnum_or_string,
|
]
|
]
|
},
|
},
|
{ # v2001 module_parameter_port_list (A.1.3)
|
{ # v2001 module_parameter_port_list (A.1.3)
|
stateName => 'PPL_PARAM_OR_NAME' ,
|
stateName => 'PPL_PARAM_OR_NAME' ,
|
failNextState => ['PPL_NAME'],
|
failNextState => ['PPL_NAME'],
|
search => [ { regexp => '\bparameter\b', nextState => ['PPL_TYPE'], }, ],
|
search => [ { regexp => '\bparameter\b', nextState => ['PPL_TYPE'], }, ],
|
},
|
},
|
];
|
];
|
}
|
}
|
|
|
|
|
############################################################
|
############################################################
|
# make the parser, and return it as a string
|
# make the parser, and return it as a string
|
############################################################
|
############################################################
|
|
|
|
|
sub _make_parser {
|
sub _make_parser {
|
my ($evalDefs,$genDebugCode) = @_;
|
my ($evalDefs,$genDebugCode) = @_;
|
|
|
_check_data_structures($evalDefs);
|
_check_data_structures($evalDefs);
|
|
|
my $perlCode; # the perl code we are making
|
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);':'';
|
my $debugPrint = $genDebugCode ? 'print "---- $ps->{curState} $file:$line (".pos($code).")\\n" if defined $ps->{curState} && defined pos($code);':'';
|
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
# vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
|
$perlCode .= <<EOF;
|
$perlCode .= <<EOF;
|
sub _parse_line {
|
sub _parse_line {
|
|
|
my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
|
my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
|
|
|
if (!exists(\$ps->{curState})){
|
if (!exists(\$ps->{curState})){
|
\$ps->{curState} = undef;
|
\$ps->{curState} = undef;
|
\$ps->{prevState}= undef;
|
\$ps->{prevState}= undef;
|
\$ps->{nextStateStack}= ["START"];
|
\$ps->{nextStateStack}= ["START"];
|
\$ps->{storing}= 0;
|
\$ps->{storing}= 0;
|
\$ps->{stored}= "";
|
\$ps->{stored}= "";
|
\$ps->{confusedNextState}= "START";
|
\$ps->{confusedNextState}= "START";
|
}
|
}
|
|
|
my \$storePos = -1;
|
my \$storePos = -1;
|
my \$lastPos = 0;
|
my \$lastPos = 0;
|
my \$posMark;
|
my \$posMark;
|
my \$fromLastPos;
|
my \$fromLastPos;
|
PARSE_LINE_LOOP: while (1) {
|
PARSE_LINE_LOOP: while (1) {
|
|
|
\$lastPos = pos(\$code) if (defined(pos(\$code)));
|
\$lastPos = pos(\$code) if (defined(pos(\$code)));
|
|
|
if ( \$code =~ m/\\G\\s*\\Z/gs ) {
|
if ( \$code =~ m/\\G\\s*\\Z/gs ) {
|
last PARSE_LINE_LOOP;
|
last PARSE_LINE_LOOP;
|
}
|
}
|
else {
|
else {
|
pos(\$code) = \$lastPos;
|
pos(\$code) = \$lastPos;
|
}
|
}
|
|
|
\$code =~ m/\\G\\s*/gs ; # skip any whitespace
|
\$code =~ m/\\G\\s*/gs ; # skip any whitespace
|
|
|
\$ps->{prevState} = \$ps->{curState};
|
\$ps->{prevState} = \$ps->{curState};
|
\$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
|
\$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
|
die "Error: No next state after \$ps->{prevState} ".
|
die "Error: No next state after \$ps->{prevState} ".
|
"\$file line \$line :\n \$code";
|
"\$file line \$line :\n \$code";
|
$debugPrint
|
$debugPrint
|
|
|
goto \$ps->{curState};
|
goto \$ps->{curState};
|
die \"Confused: Bad state \$ps->{curState}\";
|
die \"Confused: Bad state \$ps->{curState}\";
|
|
|
CONFUSED:
|
CONFUSED:
|
\$posMark = '';
|
\$posMark = '';
|
# make the position marker: tricky because code can contain tabs
|
# make the position marker: tricky because code can contain tabs
|
# which we want to match in the blank space before the ^
|
# which we want to match in the blank space before the ^
|
\$posMark = substr(\$code,0,\$lastPos);
|
\$posMark = substr(\$code,0,\$lastPos);
|
\$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
|
\$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
|
\$posMark .= "^" ;
|
\$posMark .= "^" ;
|
if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
|
if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
|
\$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
|
\$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
|
"\$code".\$posMark);
|
"\$code".\$posMark);
|
\@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
|
\@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
|
return; # ignore the rest of the line
|
return; # ignore the rest of the line
|
EOF
|
EOF
|
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
# ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
|
|
|
|
foreach my $state (@$languageDef) {
|
foreach my $state (@$languageDef) {
|
my $stateName = $state->{stateName};
|
my $stateName = $state->{stateName};
|
my $allowAnything = exists($state->{allowAnything}) && $state->{allowAnything};
|
my $allowAnything = exists($state->{allowAnything}) && $state->{allowAnything};
|
my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match
|
my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match
|
# where we left off last time
|
# where we left off last time
|
$perlCode.= " $stateName:\n";
|
$perlCode.= " $stateName:\n";
|
|
|
if (exists($state->{confusedNextState})) {
|
if (exists($state->{confusedNextState})) {
|
$perlCode.= " \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
|
$perlCode.= " \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
|
}
|
}
|
|
|
if (exists($state->{search})) {
|
if (exists($state->{search})) {
|
my @searchTerms=();
|
my @searchTerms=();
|
foreach my $search (@{$state->{search}}) {
|
foreach my $search (@{$state->{search}}) {
|
push @searchTerms, $search->{regexp};
|
push @searchTerms, $search->{regexp};
|
}
|
}
|
$re .= "(?:(". join(")|(",@searchTerms)."))";
|
$re .= "(?:(". join(")|(",@searchTerms)."))";
|
|
|
my $failNextState='';
|
my $failNextState='';
|
|
|
if (exists($state->{failNextState})) {
|
if (exists($state->{failNextState})) {
|
if (scalar(@{$state->{failNextState}}) != 0) {
|
if (scalar(@{$state->{failNextState}}) != 0) {
|
$failNextState="\"".
|
$failNextState="\"".
|
join('","',reverse(@{$state->{failNextState}})).
|
join('","',reverse(@{$state->{failNextState}})).
|
"\"";
|
"\"";
|
}
|
}
|
# else leave it set at nothing - means just popup
|
# else leave it set at nothing - means just popup
|
}
|
}
|
else {
|
else {
|
$failNextState='"CONFUSED"';
|
$failNextState='"CONFUSED"';
|
}
|
}
|
$perlCode.= " if (\$code =~ m/$re/gos) {\n";
|
$perlCode.= " if (\$code =~ m/$re/gos) {\n";
|
|
|
my $elsif2="if";
|
my $elsif2="if";
|
my $i=0;
|
my $i=0;
|
foreach my $search (@{$state->{search}}) {
|
foreach my $search (@{$state->{search}}) {
|
$i++;
|
$i++;
|
|
|
my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
|
my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
|
|
|
$perlCode.= " $elsif2 (defined(\$$i)) {\n";
|
$perlCode.= " $elsif2 (defined(\$$i)) {\n";
|
if ($genDebugCode) {
|
if ($genDebugCode) {
|
$perlCode.=" print \"---- -$arcName (\$$i)->\\n\";\n";
|
$perlCode.=" print \"---- -$arcName (\$$i)->\\n\";\n";
|
$perlCode.=" \$takenArcs->{'$stateName'}{$i}++;\n";
|
$perlCode.=" \$takenArcs->{'$stateName'}{$i}++;\n";
|
}
|
}
|
$elsif2="elsif";
|
$elsif2="elsif";
|
if (exists($search->{resetPos}) && $search->{resetPos}) {
|
if (exists($search->{resetPos}) && $search->{resetPos}) {
|
$perlCode.=" pos(\$code)=pos(\$code)-length(\$$i);\n";
|
$perlCode.=" pos(\$code)=pos(\$code)-length(\$$i);\n";
|
}
|
}
|
if (exists($search->{arcName})) {
|
if (exists($search->{arcName})) {
|
$perlCode.= # " " .
|
$perlCode.= # " " .
|
_make_eval_code($evalDefs,$stateName,
|
_make_eval_code($evalDefs,$stateName,
|
$search->{arcName},$i,$genDebugCode);
|
$search->{arcName},$i,$genDebugCode);
|
}
|
}
|
if (exists $search->{nextState}) {
|
if (exists $search->{nextState}) {
|
$perlCode.= " push (\@{\$ps->{nextStateStack}}, \"".
|
$perlCode.= " push (\@{\$ps->{nextStateStack}}, \"".
|
join('","',reverse(@{$search->{nextState}}))."\");\n";
|
join('","',reverse(@{$search->{nextState}}))."\");\n";
|
}
|
}
|
if (exists($search->{storePos}) && $search->{storePos}) {
|
if (exists($search->{storePos}) && $search->{storePos}) {
|
$perlCode.= " \$ps->{storing} == 0 or\n";
|
$perlCode.= " \$ps->{storing} == 0 or\n";
|
$perlCode.= " die \"Setting storing ".
|
$perlCode.= " die \"Setting storing ".
|
"flag when it is already set: $stateName:$arcName\";\n";
|
"flag when it is already set: $stateName:$arcName\";\n";
|
$perlCode.= " \$storePos = pos(\$code);\n";
|
$perlCode.= " \$storePos = pos(\$code);\n";
|
$perlCode.= " \$ps->{storing} = 1;\n";
|
$perlCode.= " \$ps->{storing} = 1;\n";
|
$perlCode.= " \$ps->{stored} = '';\n";
|
$perlCode.= " \$ps->{stored} = '';\n";
|
}
|
}
|
$perlCode.= " }\n";
|
$perlCode.= " }\n";
|
}
|
}
|
$perlCode.= " }\n";
|
$perlCode.= " }\n";
|
|
|
if ($allowAnything) {
|
if ($allowAnything) {
|
$perlCode.= " else { ".
|
$perlCode.= " else { ".
|
"push(\@{\$ps->{nextStateStack}},\"$stateName\"); last PARSE_LINE_LOOP; }\n";
|
"push(\@{\$ps->{nextStateStack}},\"$stateName\"); last PARSE_LINE_LOOP; }\n";
|
}
|
}
|
else {
|
else {
|
$perlCode.= " else {\n";
|
$perlCode.= " else {\n";
|
if (exists($state->{failStorePos}) && $state->{failStorePos}) {
|
if (exists($state->{failStorePos}) && $state->{failStorePos}) {
|
$perlCode.= " \$ps->{storing} == 0 or\n";
|
$perlCode.= " \$ps->{storing} == 0 or\n";
|
$perlCode.= " die \"Setting storing ".
|
$perlCode.= " die \"Setting storing ".
|
"flag when it is already set: $stateName:fail\";\n";
|
"flag when it is already set: $stateName:fail\";\n";
|
#NB:uses lastPos here because there was no match, so can't
|
#NB:uses lastPos here because there was no match, so can't
|
# use pos(code)
|
# use pos(code)
|
$perlCode.= " \$storePos = \$lastPos;\n";
|
$perlCode.= " \$storePos = \$lastPos;\n";
|
$perlCode.= " \$ps->{storing} = 1;\n";
|
$perlCode.= " \$ps->{storing} = 1;\n";
|
$perlCode.= " \$ps->{stored} = '';\n";
|
$perlCode.= " \$ps->{stored} = '';\n";
|
}
|
}
|
if ($failNextState) {
|
if ($failNextState) {
|
$perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
|
$perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
|
}
|
}
|
$perlCode.= " pos(\$code)=\$lastPos; }\n";
|
$perlCode.= " pos(\$code)=\$lastPos; }\n";
|
}
|
}
|
}
|
}
|
$perlCode.= " next PARSE_LINE_LOOP;\n";
|
$perlCode.= " next PARSE_LINE_LOOP;\n";
|
}
|
}
|
$perlCode.= " }\n";
|
$perlCode.= " }\n";
|
$perlCode.= " if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
|
$perlCode.= " if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
|
$perlCode.= " elsif ( \$ps->{storing} ) { \$ps->{stored} .= \$code; }\n";
|
$perlCode.= " elsif ( \$ps->{storing} ) { \$ps->{stored} .= \$code; }\n";
|
$perlCode.= "}\n";
|
$perlCode.= "}\n";
|
|
|
return $perlCode;
|
return $perlCode;
|
}
|
}
|
|
|
sub _make_eval_code {
|
sub _make_eval_code {
|
my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
|
my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
|
|
|
my $eval='';
|
my $eval='';
|
|
|
foreach my $evalDef (@$evalDefs) {
|
foreach my $evalDef (@$evalDefs) {
|
|
|
if (exists($evalDef->{$stateName}{$arcName})) {
|
if (exists($evalDef->{$stateName}{$arcName})) {
|
if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
|
if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
|
$eval.=$evalDef->{$1}{$2};
|
$eval.=$evalDef->{$1}{$2};
|
}
|
}
|
else {
|
else {
|
$eval.=$evalDef->{$stateName}{$arcName};
|
$eval.=$evalDef->{$stateName}{$arcName};
|
}
|
}
|
$eval.="\n";
|
$eval.="\n";
|
}
|
}
|
}
|
}
|
# replace $match variable with the actual number of the match
|
# replace $match variable with the actual number of the match
|
$eval=~ s/\$match/\$$matchNo/g;
|
$eval=~ s/\$match/\$$matchNo/g;
|
|
|
# if fromLastPos is used then generate the code to work it out
|
# if fromLastPos is used then generate the code to work it out
|
if ($eval =~ /\$fromLastPos/) {
|
if ($eval =~ /\$fromLastPos/) {
|
my $e;
|
my $e;
|
$e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
|
$e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
|
$e .= "if (\$storePos==-1) {\n"; # on another line
|
$e .= "if (\$storePos==-1) {\n"; # on another line
|
$e .= " \$fromLastPos=\$ps->{stored}."; # what was before
|
$e .= " \$fromLastPos=\$ps->{stored}."; # what was before
|
$e .= " substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
|
$e .= " substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
|
$e .= "}\n";
|
$e .= "}\n";
|
$e .= "else {\n";
|
$e .= "else {\n";
|
$e .= " \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
|
$e .= " \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
|
"-\$storePos-length(\$$matchNo));\n";
|
"-\$storePos-length(\$$matchNo));\n";
|
$e .= "}\n";
|
$e .= "}\n";
|
$e .= "\$ps->{storing}=0;\n";
|
$e .= "\$ps->{storing}=0;\n";
|
$e .= "\$ps->{stored}='';\n";
|
$e .= "\$ps->{stored}='';\n";
|
$eval = $e . $eval;
|
$eval = $e . $eval;
|
|
|
}
|
}
|
return $eval;
|
return $eval;
|
}
|
}
|
|
|
sub _check_end_state {
|
sub _check_end_state {
|
my ($self,$file,$line,$ps) = @_;
|
my ($self,$file,$line,$ps) = @_;
|
|
|
if (!exists($ps->{curState})){
|
if (!exists($ps->{curState})){
|
# parse_line was never called, file only contained comments, defines etc
|
# parse_line was never called, file only contained comments, defines etc
|
return;
|
return;
|
}
|
}
|
$ps->{prevState} = $ps->{curState};
|
$ps->{prevState} = $ps->{curState};
|
$ps->{curState} = pop(@{$ps->{nextStateStack}}) or
|
$ps->{curState} = pop(@{$ps->{nextStateStack}}) or
|
$self->_add_confused("$file:$line:".
|
$self->_add_confused("$file:$line:".
|
"No next state after $ps->{prevState} at EOF");
|
"No next state after $ps->{prevState} at EOF");
|
|
|
if ($ps->{curState} ne 'START') {
|
if ($ps->{curState} ne 'START') {
|
$self->_add_confused("$file:$line:".
|
$self->_add_confused("$file:$line:".
|
" at EOF in state $ps->{curState}".
|
" at EOF in state $ps->{curState}".
|
(($ps->{curState} eq 'CONFUSED')?
|
(($ps->{curState} eq 'CONFUSED')?
|
",prevState was $ps->{prevState}":""));
|
",prevState was $ps->{prevState}":""));
|
}
|
}
|
if (@{$ps->{nextStateStack}}) {
|
if (@{$ps->{nextStateStack}}) {
|
$self->_add_confused("$file:$line:".
|
$self->_add_confused("$file:$line:".
|
" at EOF, state stack not empty: ".
|
" at EOF, state stack not empty: ".
|
join(" ",@{$ps->{nextStateStack}}));
|
join(" ",@{$ps->{nextStateStack}}));
|
}
|
}
|
|
|
# at the moment I don't check these:
|
# at the moment I don't check these:
|
# $ps->{storing}= 0;
|
# $ps->{storing}= 0;
|
# $ps->{stored}= "";
|
# $ps->{stored}= "";
|
|
|
}
|
}
|
|
|
sub _check_data_structures {
|
sub _check_data_structures {
|
my ($evalDefs) = @_;
|
my ($evalDefs) = @_;
|
|
|
my %stateNames;
|
my %stateNames;
|
my %statesUnused;
|
my %statesUnused;
|
|
|
foreach my $sp (@$languageDef) {
|
foreach my $sp (@$languageDef) {
|
die "Not hash!" unless ref($sp) eq "HASH";
|
die "Not hash!" unless ref($sp) eq "HASH";
|
if (!exists($sp->{stateName})) { die "State without name!"; }
|
if (!exists($sp->{stateName})) { die "State without name!"; }
|
die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
|
die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
|
$stateNames{$sp->{stateName}} = $sp;
|
$stateNames{$sp->{stateName}} = $sp;
|
}
|
}
|
|
|
%statesUnused = %stateNames;
|
%statesUnused = %stateNames;
|
# check language def first
|
# check language def first
|
foreach my $sp (@$languageDef) {
|
foreach my $sp (@$languageDef) {
|
my %t = %$sp;
|
my %t = %$sp;
|
if (!exists($sp->{search})) { die "State without search!"; }
|
if (!exists($sp->{search})) { die "State without search!"; }
|
die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
|
die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
|
my %arcNames;
|
my %arcNames;
|
foreach my $arc (@{$sp->{search}}) {
|
foreach my $arc (@{$sp->{search}}) {
|
my %a = %$arc;
|
my %a = %$arc;
|
die "arc without regexp in $sp->{stateName}" unless exists $a{regexp};
|
die "arc without regexp in $sp->{stateName}" unless exists $a{regexp};
|
delete $a{regexp};
|
delete $a{regexp};
|
if (exists($a{nextState})) {
|
if (exists($a{nextState})) {
|
die "nextState not array" unless ref($a{nextState}) eq "ARRAY";
|
die "nextState not array" unless ref($a{nextState}) eq "ARRAY";
|
foreach my $n (@{$a{nextState}}) {
|
foreach my $n (@{$a{nextState}}) {
|
next if ($n =~ m/^\$/); #can't check variable ones
|
next if ($n =~ m/^\$/); #can't check variable ones
|
die "Bad Next state $n"
|
die "Bad Next state $n"
|
unless exists $stateNames{$n};
|
unless exists $stateNames{$n};
|
delete($statesUnused{$n}) if exists $statesUnused{$n};
|
delete($statesUnused{$n}) if exists $statesUnused{$n};
|
}
|
}
|
delete $a{nextState};
|
delete $a{nextState};
|
}
|
}
|
if (exists($a{arcName})) {
|
if (exists($a{arcName})) {
|
die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
|
die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
|
$arcNames{$a{arcName}} = 1;
|
$arcNames{$a{arcName}} = 1;
|
delete $a{arcName};
|
delete $a{arcName};
|
}
|
}
|
delete $a{resetPos};
|
delete $a{resetPos};
|
delete $a{storePos};
|
delete $a{storePos};
|
foreach my $k (sort (keys %a)) {
|
foreach my $k (sort (keys %a)) {
|
die "Bad key $k in arc of state $t{stateName}";
|
die "Bad key $k in arc of state $t{stateName}";
|
}
|
}
|
}
|
}
|
delete $t{stateName};
|
delete $t{stateName};
|
delete $t{search};
|
delete $t{search};
|
delete $t{allowAnything} if exists $t{allowAnything};
|
delete $t{allowAnything} if exists $t{allowAnything};
|
|
|
if (exists($t{confusedNextState})) {
|
if (exists($t{confusedNextState})) {
|
die "Bad Next confused state $t{confusedNextState}"
|
die "Bad Next confused state $t{confusedNextState}"
|
unless exists $stateNames{$t{confusedNextState}};
|
unless exists $stateNames{$t{confusedNextState}};
|
delete $t{confusedNextState};
|
delete $t{confusedNextState};
|
}
|
}
|
|
|
foreach my $n (@{$t{failNextState}}) {
|
foreach my $n (@{$t{failNextState}}) {
|
next if ($n =~ m/^\$/); #can't check variable ones
|
next if ($n =~ m/^\$/); #can't check variable ones
|
die "Bad Next fail state $n"
|
die "Bad Next fail state $n"
|
unless exists $stateNames{$n};
|
unless exists $stateNames{$n};
|
delete($statesUnused{$n}) if exists $statesUnused{$n};
|
delete($statesUnused{$n}) if exists $statesUnused{$n};
|
}
|
}
|
delete $t{failNextState} if exists $t{failNextState};
|
delete $t{failNextState} if exists $t{failNextState};
|
delete $t{failStorePos} if exists $t{failStorePos};
|
delete $t{failStorePos} if exists $t{failStorePos};
|
foreach my $k (sort (keys %t)) {
|
foreach my $k (sort (keys %t)) {
|
die "Bad key $k in languageDef state $sp->{stateName}";
|
die "Bad key $k in languageDef state $sp->{stateName}";
|
}
|
}
|
}
|
}
|
|
|
# REVISIT: MODULE PORTS looks like it is unused because it is got to
|
# 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
|
# by setting $nState - should have a flag in language def that turns
|
# off this check on a per state basis.
|
# off this check on a per state basis.
|
foreach my $state (sort (keys %statesUnused)) {
|
foreach my $state (sort (keys %statesUnused)) {
|
#die "State $state was not used";
|
#die "State $state was not used";
|
print "Warning: State $state looks like it was not used\n" if $debug;
|
print "Warning: State $state looks like it was not used\n" if $debug;
|
}
|
}
|
|
|
foreach my $evalDef (@$evalDefs) {
|
foreach my $evalDef (@$evalDefs) {
|
foreach my $state (sort (keys %$evalDef)) {
|
foreach my $state (sort (keys %$evalDef)) {
|
if (!exists($stateNames{$state})) {
|
if (!exists($stateNames{$state})) {
|
die "Couldn't find state $state";
|
die "Couldn't find state $state";
|
}
|
}
|
my $statep = $stateNames{$state};
|
my $statep = $stateNames{$state};
|
|
|
foreach my $arc (sort (keys %{$evalDef->{$state}})) {
|
foreach my $arc (sort (keys %{$evalDef->{$state}})) {
|
my $found = 0;
|
my $found = 0;
|
foreach my $s (@{$statep->{search}}) {
|
foreach my $s (@{$statep->{search}}) {
|
if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
|
if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
|
$found=1;
|
$found=1;
|
last;
|
last;
|
}
|
}
|
}
|
}
|
if ($found == 0) {
|
if ($found == 0) {
|
die "No arc $arc in state $state";
|
die "No arc $arc in state $state";
|
}
|
}
|
if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
|
if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
|
die "No code found for $evalDef->{$state}{$arc}"
|
die "No code found for $evalDef->{$state}{$arc}"
|
unless exists $evalDef->{$1}{$2};
|
unless exists $evalDef->{$1}{$2};
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
sub _check_coverage {
|
sub _check_coverage {
|
|
|
print "\n\nCoverage Information:\n";
|
print "\n\nCoverage Information:\n";
|
foreach my $sp (@$languageDef) {
|
foreach my $sp (@$languageDef) {
|
if (!exists($takenArcs->{$sp->{stateName}})) {
|
if (!exists($takenArcs->{$sp->{stateName}})) {
|
print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
|
print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
|
}
|
}
|
else {
|
else {
|
my $i=0;
|
my $i=0;
|
foreach my $arc (@{$sp->{search}}) {
|
foreach my $arc (@{$sp->{search}}) {
|
$i++;
|
$i++;
|
if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
|
if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
|
my $arcName = $i;
|
my $arcName = $i;
|
$arcName = $arc->{arcName} if exists $arc->{arcName};
|
$arcName = $arc->{arcName} if exists $arc->{arcName};
|
print " Arc $arcName of $sp->{stateName} was never taken\n";
|
print " Arc $arcName of $sp->{stateName} was never taken\n";
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
|
|
###########################################################################
|
###########################################################################
|
|
|
# when doing require or use we must return 1
|
# when doing require or use we must return 1
|
1;
|
1;
|
|
|
|
|