OpenCores
URL https://opencores.org/ocsvn/an-fpga-implementation-of-low-latency-noc-based-mpsoc/an-fpga-implementation-of-low-latency-noc-based-mpsoc/trunk

Subversion Repositories an-fpga-implementation-of-low-latency-noc-based-mpsoc

[/] [an-fpga-implementation-of-low-latency-noc-based-mpsoc/] [trunk/] [mpsoc/] [perl_gui/] [lib/] [perl/] [rvp.pm] - Blame information for rev 25

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 16 alirezamon
###############################################################################
2
#
3
# File:         rvp.pm
4
# RCS:          $Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $
5
# Description:  The Rough Verilog Parser Perl Module
6
# Author:       Costas Calamvokis
7
# Created:      Fri Apr 10 16:59:30 1998
8
# Modified:     Thu Jan 12 10:45:27 2006
9
# Language:     Perl
10
#
11
# Copyright 1998-2006 Costas Calamvokis
12
#
13
#  This file nay be copied, modified and distributed only in accordance
14
#  with the terms of the limited licence contained in the accompanying
15
#  file LICENCE.TXT.
16
#
17
###############################################################################
18
#
19
 
20
=head1 rvp - Rough Verilog Parser Perl Module
21
 
22
The basic idea is that first you call read_verilog will a list of all of your
23
files. The files are parsed and information stored away. You are then
24
handed back a pointer to the information which you can use in calls
25
to the various get_ function to get information about the verilog design.
26
 
27
For Example:
28
 
29
 #!/usr/bin/perl -w
30
 use rvp;   # use the rough verilog parser
31
 
32
 # Read in all the files specified on the command line
33
 $vdata = rvp->read_verilog(\@ARGV,[],{},1,[],[],'');
34
 
35
 # Print out all the modules found
36
 foreach $module ($vdata->get_modules()) { print "$module\n"; }
37
 
38
Unless you are doing something very strange, you can probably ignore all
39
of the functions that have the words 'context' or 'anchors' in them!
40
 
41
=cut
42
 
43
package rvp;
44
 
45
#use strict;
46
#use Tie::IxHash;
47
 
48
use File::Basename;
49
 
50
use vars qw(@verilog_gatetype_keywords $verilog_gatetype_regexp
51
            @verilog_compiler_keywords
52
            @verilog_signal_keywords @verilog_sigs $verilog_sigs_regexp
53
            $quiet $debug $VID $HVID $VNUM
54
            $takenArcs
55
            $baseEval $rvpEval $debugEval $languageDef $vid_vnum_or_string
56
            $version $VERSION);
57
 
58
BEGIN {
59
    # $VERSION is used by 'use', but keep $version for backwards compatibility
60
    $version = '$Header: /home/cc/v2html/build/../RCS/rvp.pm,v 7.61 2006/03/25 22:24:57 cc Exp $'; #'
61
    $version =~ s/^\S+ \S+ (\S+) .*$/$1/;
62
    $VERSION = $version;
63
 
64
    @verilog_signal_keywords = qw(input    output  inout
65
                       wire     tri     tri1   supply0 wand  triand tri0
66
                       supply1  wor     time   trireg  trior
67
                       reg      integer real   realtime
68
 
69
                       genvar
70
                       );
71
    @verilog_sigs = @verilog_signal_keywords; # for backwards compatiblity
72
 
73
    #V2001
74
 
75
    $verilog_sigs_regexp = "\\b(?:" .
76
        join("|",@verilog_signal_keywords) .
77
            ")\\b";
78
 
79
    @verilog_gatetype_keywords = qw(and  nand  or  nor xor xnor  buf  bufif0 bufif1
80
                                    not  notif0 notif1  pulldown  pullup
81
                                    nmos  rnmos pmos rpmos cmos rcmos   tran rtran
82
                                    tranif0  rtranif0  tranif1 rtranif1
83
                                    );
84
 
85
    $verilog_gatetype_regexp = "\\b(?:" .
86
        join("|",@verilog_gatetype_keywords) .
87
            ")\\b";
88
 
89
    # Note: optimisation code in _search() assumes all of
90
    #  these compiler keywords contain a ` 
91
    @verilog_compiler_keywords = qw(
92
     `celldefine            `define
93
     `delay_mode_path       `disable_portfaults
94
     `else                  `enable_portfaults
95
     `endcelldefine         `endif
96
     `ifdef                 `include
97
     `nosuppress_faults     `suppress_faults
98
     `timescale             `undef
99
     `resetall              `delay_mode_distributed
100
 
101
     `default_nettype  `file `line `ifndef `elsif
102
    );    #`
103
 
104
    # a verilog identifier is this reg exp 
105
    #  a non-escaped identifier is A-Z a-z _ 0-9 or $ 
106
    #  an escaped identifier is \ followed by non-whitespace
107
    #   why \\\\\S+ ? This gets \\\S+ in to the string then when it
108
    #   it used we get it searching for \ followed by non-whitespace (\S+)
109
    $VID = '(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+)';
110
 
111
    # hierarchical VID - just $VID(.$VID)+ but can't write it like this
112
    #  because of \ escaping (and must include whitespace after esc.ids.)
113
    $HVID = '(?:(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+)'.
114
           '(?:\.(?:[A-Za-z_][A-Za-z_0-9\$]*|\\\\\S+\s+))+)';
115
  # V2001: added [sS] - is this correct
116
    $VNUM= '(?:(?:[0-9]*\'[sS]?[bBhHdDoO]\s*[0-9A-Fa-f_zZxX?]+)|(?:[-0-9Ee._]+))';
117
 
118
 
119
    $quiet=0;
120
    $debug=0;
121
 
122
}
123
 
124
###########################################################################
125
 
126
=head1 read_verilog
127
 
128
reads in verilog files, parses them and stores results in an internal
129
data structure (which I call a RVP database).
130
 
131
  Arguments:  - reference to array of files to read (can have paths)
132
              - reference to hash of defines with names as keys
133
              - reference to array of global includes - not used anymore,
134
                 just kept for backwards compatibility
135
              - quite flag. 1=be quiet, 0=be chatty.
136
              - reference to array of include directories
137
              - reference to array of library directories
138
              - library extension string (eg '.v') or reference to array of strings
139
 
140
  Returns:    - a pointer to the internal data structure.
141
 
142
  Example:
143
    $defines{'TRUE'}=1;  # same as +define+TRUE=1 on verilog cmd line
144
    $vdata = rvp->read_verilog(\@files,[],\%defines,1,
145
                                     \@inc_dirs,\@lib_dirs,\@lib_exts);
146
 
147
=cut
148
sub read_verilog {
149
    # be backwards compatible with non-OO call
150
    my $class = ("ARRAY" eq ref $_[0]) ? "rvp" : shift;
151
    my ($files,$global_includes,$cmd_line_defines,$local_quiet,$inc_dirs,
152
        $lib_dirs,$lib_ext_arg,$exp)
153
        = @_;
154
    my ($file,$fb,$old_quiet,@search_files,@new_search_files,$lib_exts);
155
 
156
    my $self;
157
 
158
    die "read_verilog needs an array ref as arg 1" unless "ARRAY" eq ref $files;
159
    die "read_verilog needs an hash ref as arg 2" unless "HASH" eq ref $cmd_line_defines;
160
    die "read_verilog needs 0 or 1 as arg 3" unless $local_quiet==0 || $local_quiet==1;
161
 
162
    # be backwards compatible
163
    if (!defined($inc_dirs)) { $inc_dirs=[]; }
164
    if (!defined($lib_dirs)) { $lib_dirs=[]; }
165
 
166
    if (!defined($lib_ext_arg)) {  # no libexts given
167
        $lib_exts=[''];
168
    }
169
    elsif (!ref($lib_ext_arg))  {  # a string given
170
        $lib_exts=[$lib_ext_arg];
171
    }
172
    else {                         # an array ref given
173
        $lib_exts=$lib_ext_arg;
174
    }
175
 
176
 
177
    # make the parser
178
    if (! defined &parse_line) {
179
 
180
        my $perlCode=_make_parser( $debug ? [ $baseEval,$debugEval,$rvpEval ]:
181
                                          [ $baseEval,$rvpEval ] ,
182
                                 $debug );
183
        if ($debug) {
184
            open(PC,">v2html-parser.pl");
185
            print PC $perlCode;
186
        }
187
        eval($perlCode);
188
        print STDERR $@ if ($@);
189
    }
190
 
191
    if (! defined &_parse_line) { die "Parse code generation failed";}
192
 
193
    $old_quiet=$quiet;
194
    $quiet=$local_quiet;
195
    # set up top of main data structure
196
    $self = {};
197
    $self->{files}               = {}; # information on each file
198
    $self->{modules}             = {}; # pointers to module info in {files}
199
    $self->{defines}             = {};
200
    $self->{ignored_modules}     = {}; # list of modules were duplicates were found
201
    $self->{unresolved_modules}  = {}; # modules we have not found yet
202
    $self->{problems}            = []; # warning/confused messages
203
 
204
    bless($self,$class);
205
 
206
    foreach my $d (keys(%$cmd_line_defines)) {
207
        _add_define($self->{defines}, $d , $cmd_line_defines->{$d}, '', 0 );
208
    }
209
 
210
    # go through all the files and find information
211
    @new_search_files = @{$files};
212
    while (@new_search_files) {
213
        @search_files = @new_search_files;
214
        @new_search_files = ();
215
        foreach $file (@search_files) {
216
            $self->_search($file,$inc_dirs);
217
        }
218
        push( @new_search_files , _resolve_modules( $self, $lib_dirs, $lib_exts ) );
219
    }
220
 
221
 
222
    if ($debug) {
223
        _check_coverage();
224
    }
225
 
226
    # cross reference files' information
227
    print "Cross referencing\n" unless $quiet;
228
    $self->_cross_reference();
229
 
230
    $quiet=$old_quiet;
231
 
232
    foreach my $m ( sort (keys %{$self->{unresolved_modules}} )) {
233
        # find somewhere it is instantiated for warning message
234
        my $file="";
235
        my $line="";
236
        foreach my $m2 (sort (keys %{$self->{modules}})) {
237
            foreach my $inst (@{$self->{modules}{$m2}{instances}}) {
238
                if ($inst->{module} eq $m) {
239
                    $file = $inst->{file};
240
                    $line = $inst->{line};
241
                    last;
242
                }
243
            }
244
        }
245 25 alirezamon
        #$self->_add_warning("$file:$line: Could not find module $m");
246 16 alirezamon
    }
247
    return $self;
248
}
249
 
250
###########################################################################
251
 
252
=head1 get_problems
253
 
254
Return any problems that happened during parsing
255
 
256
  Returns:    - array of strings of problems. Each one is:
257
                    "TYPE:FILE:LINE: description"
258
 
259
=cut
260
sub get_problems {
261
    my ($self) = @_;
262
 
263
    return (@{$self->{problems}});
264
}
265
 
266
###########################################################################
267
 
268
=head1 set_debug
269
 
270
Turns on debug printing in the parser.
271
 
272
  Returns:    - nothing
273
 
274
=cut
275
sub set_debug {
276
    $debug=1;
277
}
278
 
279
###########################################################################
280
 
281
=head1 unset_debug
282
 
283
Turns off debug printing in the parser.
284
 
285
  Returns:    - nothing
286
 
287
=cut
288
sub unset_debug {
289
    $debug=0;
290
}
291
 
292
###########################################################################
293
 
294
=head1 get_files
295
 
296
Get a list of all the files in the database.
297
 
298
  Returns:    - list of all the files
299
 
300
  Example:   @all_files = $vdata->get_files();
301
 
302
=cut
303
sub get_files{
304
    my ($self) = @_;
305
 
306
    if (wantarray) {
307
        return sort (keys %{$self->{files}});
308
    }
309
    else { # in a scalar context keys returns the number of elements - sort doesn't
310
        return keys %{$self->{files}};
311
    }
312
}
313
 
314
###########################################################################
315
 
316
=head1 get_files_modules
317
 
318
Get a list of all the modules in a particular file.
319
 
320
  Arguments:  - name of file
321
 
322
  Returns:    - list of module names
323
 
324
  Example:   @modules = $vdata->get_files_modules($file);
325
 
326
=cut
327
sub get_files_modules{
328
    my ($self,$file) = @_;
329
    my (@modules,$m);
330
 
331
    foreach $m (sort (keys %{$self->{files}{$file}{modules}})) {
332
        push(@modules,$m)
333
    }
334
 
335
    return @modules;
336
}
337
 
338
 
339
###########################################################################
340
 
341
=head1 get_files_full_name
342
 
343
Get the full name (including path) of a file.
344
 
345
  Arguments:  - name of file
346
 
347
  Returns:    - full path name
348
 
349
  Example  $full_name = $vdata->get_files_full_name($file);
350
 
351
=cut
352
sub get_files_full_name{
353
    my ($self,$file) = @_;
354
 
355
    return $self->{files}{$file}{full_name};
356
 
357
}
358
 
359
###########################################################################
360
 
361
=head1 get_files_stats
362
 
363
Get statistics about a file
364
 
365
  Arguments:  - name of file
366
 
367
  Returns:    - number of lines in the file (more later...)
368
 
369
  Example  $full_name = $vdata->get_files_stats($file);
370
 
371
=cut
372
sub get_files_stats{
373
    my ($self,$file) = @_;
374
 
375
    return $self->{files}{$file}{lines};
376
 
377
}
378
 
379
###########################################################################
380
 
381
=head1 file_exists
382
 
383
Test if a particular module file  in the database.
384
 
385
  Arguments:  - file name to test.
386
 
387
  Returns:    - 1 if exists otherwise 0
388
 
389
  Example:   if ($vdata->file_exists($file))....
390
 
391
=cut
392
sub file_exists{
393
    my ($self,$file) = @_;
394
    return exists($self->{files}{_ffile($file)});
395
}
396
 
397
###########################################################################
398
 
399
=head1 get_modules
400
 
401
Get a list of all the modules in the database.
402
 
403
 
404
  Returns:   - list of all the modules
405
 
406
  Example:   @all_modules = $vdata->get_modules();
407
 
408
=cut
409
sub get_modules{
410
    my ($self) = @_;
411
 
412
    if (wantarray) {
413
        return sort (keys %{$self->{modules}});
414
    }
415
    else { # in a scalar context keys returns the number of elements - sort doesn't
416
        return keys %{$self->{modules}};
417
    }
418
 
419
}
420
 
421
 
422
###########################################################################
423
 
424
=head1 get_modules_t_and_f
425
 
426
Get a list of all the tasks and functions in a particular module.
427
 
428
  Arguments:  - name of module
429
 
430
  Returns:    - list of tasks and function names
431
 
432
  Example:    if ( @t_and_f = $vdata->get_modules_t_and_f($m))...
433
 
434
=cut
435
# return a list of all the tasks and functions in a module
436
sub get_modules_t_and_f{
437
    my ($self,$module) = @_;
438
 
439
    if (wantarray) {
440
        return sort (keys %{$self->{modules}{$module}{t_and_f}});
441
    }
442
    else { # in a scalar context keys returns the number of elements - sort doesn't
443
        return keys %{$self->{modules}{$module}{t_and_f}};
444
    }
445
 
446
}
447
 
448
###########################################################################
449
 
450
=head1 get_modules_t_or_f
451
 
452
Get information on a task or function in a module.
453
 
454
  Arguments:  - module name
455
              - task or function name
456
 
457
  Returns:    - A 4 element list: type (task or function), definition line,
458
                  file, anchor
459
 
460
  Example:    ($t_type,$t_line ,$t_file,$t_anchor)=
461
                $vdata->get_modules_t_or_f($m,$tf);
462
 
463
=cut
464
sub get_modules_t_or_f{
465
    my ($self,$mod,$t_or_f) = @_;
466
 
467
    if (exists($self->{modules}{$mod}{t_and_f}{$t_or_f})) {
468
        return($self->{modules}{$mod}{t_and_f}{$t_or_f}{type},
469
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{line},
470
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{file},
471
               $self->{modules}{$mod}{t_and_f}{$t_or_f}{anchor});
472
    }
473
    else {
474
        return ();
475
    }
476
}
477
 
478
###########################################################################
479
 
480
=head1 get_modules_signals
481
 
482
Get a list of all the signals in a particular module.
483
 
484
  Arguments:  - name of module
485
 
486
  Returns:    - list of signal names
487
 
488
  Example:    if ( @signs = $vdata->get_modules_signals($m))...
489
 
490
=cut
491
# return a list of all the tasks and functions in a module
492
sub get_modules_signals{
493
    my ($self,$module) = @_;
494
 
495
    if (wantarray) {
496
        return sort (keys %{$self->{modules}{$module}{signals}});
497
    }
498
    else { # in a scalar context keys returns the number of elements - sort doesn't
499
        return keys %{$self->{modules}{$module}{signals}};
500
    }
501
 
502
}
503
 
504
###########################################################################
505
 
506
=head1 get_modules_file
507
 
508
Get the file name (no path) that a module is defined in.
509
 
510
  Arguments:  - module name
511
 
512
  Returns:    - file name without path, and the line number module starts on
513
 
514
  Example:    ($f) = $vdata->get_modules_file($m);
515
 
516
=cut
517
# get the file name that contains a module
518
sub get_modules_file{
519
    my ($self,$module) = @_;
520
 
521
    return ($self->{modules}{$module}{file},$self->{modules}{$module}{line});
522
}
523
 
524
 
525
###########################################################################
526
 
527
=head1 get_modules_type
528
 
529
Get the type of the module - It is one of: module, macromodule or primitive
530
(rvp treats these all as modules).
531
 
532
  Arguments:  - module name
533
 
534
  Returns:    - type
535
 
536
  Example:    $t = $vdata->get_modules_type($m);
537
 
538
=cut
539
# get the file name that contains a module
540
sub get_modules_type{
541
    my ($self,$module) = @_;
542
 
543
    return ($self->{modules}{$module}{type});
544
}
545
 
546
###########################################################################
547
 
548
=head1 get_files_includes
549
 
550
Get the file names (no path) of files included in a file.
551
 
552
  Arguments:  - file name
553
 
554
  Returns:    - list of file names without paths
555
 
556
  Example:    @f = $vdata->get_files_includes($file);
557
 
558
=cut
559
sub get_files_includes {
560
    my ($self,$f) = @_;
561
    my @includes_found = ();
562
 
563
    if (exists($self->{files}{$f})) {
564
        foreach my $inc ( sort ( keys %{$self->{files}{$f}{includes}} )) {
565
            push(@includes_found,$inc);
566
            # do the includes for the included file
567
            push(@includes_found, $self->get_files_includes($inc));
568
        }
569
    }
570
 
571
    return @includes_found;
572
}
573
 
574
###########################################################################
575
 
576
=head1 get_files_included_by
577
 
578
Get the file names (no path) of files that included this file.
579
 
580
  Arguments:  - file name
581
 
582
  Returns:    - list of file names without paths
583
 
584
  Example:    @f = $vdata->get_files_included_by($file);
585
 
586
=cut
587
sub get_files_included_by {
588
    my ($self,$f) = @_;
589
 
590
    return @{$self->{files}{$f}{included_by}};
591
 
592
}
593
 
594
 
595
###########################################################################
596
 
597
=head1 module_ignored
598
 
599
Test if a particular module has been ignored because of duplicates found
600
 
601
  Arguments:  - module name to test
602
 
603
  Returns:    - 1 if ignored otherwise 0
604
 
605
  Example:   if ($vdata->module_ignored($module))....
606
 
607
=cut
608
sub module_ignored {
609
    my ($self,$module) = @_;
610
    return (exists($self->{modules}{$module}) &&
611
            $self->{modules}{$module}{duplicate});
612
}
613
 
614
###########################################################################
615
 
616
=head1 module_exists
617
 
618
Test if a particular module exists in the database.
619
 
620
  Arguments:  - module name to test
621
 
622
  Returns:    - 1 if exists otherwise 0
623
 
624
  Example:   if ($vdata->module_exists($module))....
625
 
626
=cut
627
sub module_exists{
628
    my ($self,$module) = @_;
629
    return exists($self->{modules}{$module});
630
}
631
 
632
###########################################################################
633
 
634
=head1 get_ignored_modules
635
 
636
Return a list of the ignored modules. These are modules where duplicates
637
have been found.
638
 
639
  Returns:    - List of ignored modules
640
 
641
  Example:    - foreach $module ($vdata->get_ignored_modules())....
642
 
643
=cut
644
sub get_ignored_modules {
645
    my ($self) = @_;
646
    my @ig =();
647
    foreach my $m (sort (keys %{$self->{modules}})) {
648
        push(@ig, $m) if ($self->{modules}{$m}{duplicate});
649
    }
650
    return @ig;
651
}
652
 
653
###########################################################################
654
 
655
=head1 get_module_signal
656
 
657
Get information about a particular signal in a particular module.
658
 
659
  Arguments:  - name of module
660
              - name of signal
661
 
662
  Returns:    - A list containing:
663
                 - the line signal is defined
664
                 - the line signal is assigned first (or -1)
665
                 - line in instantiating module where an input
666
                       is driven from (or -1)
667
                 - the type of the signal (input,output,reg etc)
668
                 - the file the signal is in
669
                 - posedge flag (1 if signal ever seen with posedge)
670
                 - negedge flag (1 if signal ever seen with negedge)
671
                 - second type (eg reg for a registered output)
672
                 - signal real source file
673
                 - signal real source line
674
                 - range string if any ( not including [ and ] )
675
                 - the file signal is assigned first (or '')
676
                 - file for the instantiating module where an input
677
                       is driven from (or "")
678
                 - a pointer to an array of dimensions for memories
679
                       each element of the array is a dimension, array
680
                       is empty for non-memories
681
 
682
  Note posedge and negedge information is propagated up the hierarchy to
683
  attached signals. It is not propagated down the hierarchy.
684
 
685
  Example:    ($s_line,$s_a_line,$s_i_line,$s_type,$s_file,$s_p,$s_n,
686
               $s_type2,$s_r_file,$s_r_line,$range,$s_a_file,$s_i_file) =
687
                      $vdata->get_module_signal($m,$sig);
688
 
689
=cut
690
sub get_module_signal{
691
    my ($self,$module,$sig) = @_;
692
 
693
    if (exists( $self->{modules}{$module}{signals}{$sig} )) {
694
        return ($self->{modules}{$module}{signals}{$sig}{line},
695
                $self->{modules}{$module}{signals}{$sig}{a_line},
696
                $self->{modules}{$module}{signals}{$sig}{i_line},
697
                $self->{modules}{$module}{signals}{$sig}{type},
698
                $self->{modules}{$module}{signals}{$sig}{file},
699
                $self->{modules}{$module}{signals}{$sig}{posedge},
700
                $self->{modules}{$module}{signals}{$sig}{negedge},
701
                $self->{modules}{$module}{signals}{$sig}{type2},
702
                $self->{modules}{$module}{signals}{$sig}{source}{file},
703
                $self->{modules}{$module}{signals}{$sig}{source}{line},
704
                $self->{modules}{$module}{signals}{$sig}{range},
705
                $self->{modules}{$module}{signals}{$sig}{a_file},
706
                $self->{modules}{$module}{signals}{$sig}{i_file},
707
                $self->{modules}{$module}{signals}{$sig}{dimensions});
708
    }
709
    else {
710
        return ();
711
    }
712
}
713
 
714
###########################################################################
715
 
716
=head1 get_first_signal_port_con
717
 
718
Get the first port that this signal in this module is connected to.
719
 
720
  Arguments:  - module name
721
              - signal name
722
 
723
  Returns:    - a 5 element list: instantiated module name, instance name
724
                  port name, line number and file
725
 
726
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_first_signal_port_con($m,$s);
727
 
728
=cut
729
sub get_first_signal_port_con{
730
    my ($self,$module,$signal) = @_;
731
 
732
    $self->{current_signal_port_con}       =0;
733
    $self->{current_signal_port_con_module}=$module;
734
    $self->{current_signal_port_con_module_signal}=$signal;
735
 
736
    return $self->get_next_signal_port_con();
737
}
738
 
739
###########################################################################
740
 
741
=head1 get_next_signal_port_con
742
 
743
Get the next port that this signal in this module is connected to.
744
 
745
  Returns:    - a 5 element list: instantiated module name, instance name
746
                  port name, line number and file
747
 
748
  Example:    ($im,$in,$p,$l,$f)=$vdata->get_next_signal_port_con();
749
 
750
=cut
751
sub get_next_signal_port_con{
752
    my ($self) = @_;
753
    my ($module,$signal,$i,$pcref);
754
 
755
    $module = $self->{current_signal_port_con_module};
756
    $signal = $self->{current_signal_port_con_module_signal};
757
    $i      = $self->{current_signal_port_con};
758
 
759
    $pcref = $self->{modules}{$module}{signals}{$signal}{port_con};
760
    if (@{$pcref} > $i ) {
761
        $self->{current_signal_port_con}++;
762
        return ( $pcref->[$i]{module},$pcref->[$i]{inst},$pcref->[$i]{port},
763
                $pcref->[$i]{line},$pcref->[$i]{file});
764
    }
765
    else {
766
        return ();
767
    }
768
}
769
 
770
###########################################################################
771
 
772
=head1 get_first_signal_con_to
773
 
774
Get the first signal that is connected to this port in an
775
instantiation of this module. This only works for instances that use
776
the .port(sig) notation.
777
 
778
  Arguments:  - module name
779
              - signal name
780
 
781
  Returns:    - a 4 element list: signal connected to this port
782
                                  module signal is in
783
                                  instance (of this module) where the connection
784
                                    occurs
785
 
786
  Example:    ($cts,$ctm,$cti)=$vdata->get_first_signal_con_to($m,$s);
787
 
788
=cut
789
sub get_first_signal_con_to{
790
    my ($self,$module,$signal) = @_;
791
 
792
    $self->{current_signal_con_to}       =0;
793
    $self->{current_signal_con_to_module}=$module;
794
    $self->{current_signal_con_to_module_signal}=$signal;
795
 
796
    return $self->get_next_signal_con_to();
797
}
798
 
799
###########################################################################
800
 
801
=head1 get_next_signal_con_to
802
 
803
Get the next signal that is connected to this port in an
804
instantiation of this module. This only works for instances that use
805
the .port(sig) notation.
806
 
807
  Arguments:  - module name
808
              - signal name
809
 
810
  Returns:    - a 4 element list: signal connected to this port
811
                                  module signal is in
812
                                  instance (of this module) where the connection
813
                                    occurs
814
 
815
  Example:    ($cts,$ctm,$cti)=$vdata->get_next_signal_con_to();
816
 
817
=cut
818
sub get_next_signal_con_to{
819
    my ($self) = @_;
820
    my ($module,$signal,$i,$ctref);
821
 
822
    $module = $self->{current_signal_con_to_module};
823
    $signal = $self->{current_signal_con_to_module_signal};
824
    $i      = $self->{current_signal_con_to};
825
 
826
    $ctref = $self->{modules}{$module}{signals}{$signal}{con_to};
827
    if (@{$ctref} > $i ) {
828
        $self->{current_signal_con_to}++;
829
        return ( $ctref->[$i]{signal},$ctref->[$i]{module},$ctref->[$i]{inst});
830
    }
831
    else {
832
        return ();
833
    }
834
}
835
 
836
###########################################################################
837
 
838
=head1 get_first_instantiator
839
 
840
Get the first thing that instantiates this module.
841
 
842
  Arguments:  - module name
843
 
844
  Returns:    - a 4 element list: instantiating module, file, instance name, line
845
 
846
  Example:
847
                ($im,$f,$i) = $vdata->get_first_instantiator($m );
848
 
849
=cut
850
# Get the first thing that instantiates or empty list if none.
851
#  Returns: { module, file, inst }
852
sub get_first_instantiator{
853
    my ($self,$module) = @_;
854
 
855
    if ( exists( $self->{modules}{$module} )) {
856
        $self->{current_instantiator}       =0;
857
        $self->{current_instantiator_module}=$module;
858
        return $self->get_next_instantiator();
859
    }
860
    else {
861
        return ();
862
    }
863
}
864
 
865
###########################################################################
866
 
867
=head1 get_next_instantiator
868
 
869
Get the first thing that instantiates the module specified in
870
get_first_instantiator (or _by_context).
871
 
872
  Returns:    - a 4 element list: instantiating module, file,
873
                                    instance name, line
874
 
875
  Example:
876
                ($im,$f,$i) = $vdata->get_next_instantiator();
877
 
878
=cut
879
sub get_next_instantiator{
880
    my ($self) = @_;
881
    my ($module,$i);
882
 
883
    $module = $self->{current_instantiator_module};
884
    $i      = $self->{current_instantiator};
885
 
886
    if (@{$self->{modules}{$module}{inst_by}} > $i ) {
887
        $self->{current_instantiator}++;
888
        return ($self->{modules}{$module}{inst_by}[$i]{module},
889
                $self->{modules}{$module}{inst_by}[$i]{file},
890
                $self->{modules}{$module}{inst_by}[$i]{inst},
891
                $self->{modules}{$module}{inst_by}[$i]{line} );
892
    }
893
    else {
894
        return ();
895
    }
896
}
897
 
898
###########################################################################
899
 
900
=head1 get_first_instantiation
901
 
902
Get the first thing that this module instantiates.
903
 
904
  Arguments:  - module name
905
 
906
  Returns:    - a 4 element list: instantiated module name, file,
907
                  instance name, and line number
908
 
909
  Example:
910
                ($im,$f,$i,$l) = $vdata->get_first_instantiation($m);
911
 
912
=cut
913
sub get_first_instantiation{
914
    my ($self,$module) = @_;
915
 
916
    if ( exists( $self->{modules}{$module} )) {
917
        $self->{current_instantiation}       =0;
918
        $self->{current_instantiation_module}=$module;
919
        return $self->get_next_instantiation();
920
    }
921
    else {
922
        return ();
923
    }
924
}
925
 
926
###########################################################################
927
 
928
=head1 get_next_instantiation
929
 
930
Get the next thing that this module instantiates.
931
 
932
 
933
  Returns:    - a 4 element list: instantiated module name, file,
934
                  instance name, and line number
935
 
936
  Example:
937
                ($im,$f,$i,$l) = $vdata->get_next_instantiation();
938
 
939
=cut
940
sub get_next_instantiation{
941
    my ($self) = @_;
942
    my ($module,$i);
943
 
944
    $module = $self->{current_instantiation_module};
945
    $i      = $self->{current_instantiation};
946
 
947
    if (@{$self->{modules}{$module}{instances}} > $i ) {
948
        $self->{current_instantiation}++;
949
        return ($self->{modules}{$module}{instances}[$i]{module},
950
                $self->{modules}{$module}{instances}[$i]{file},
951
                $self->{modules}{$module}{instances}[$i]{inst_name},
952
                $self->{modules}{$module}{instances}[$i]{line} );
953
    }
954
    else {
955
        return ();
956
    }
957
}
958
 
959
###########################################################################
960
 
961
=head1 get_current_instantiations_port_con
962
 
963
Gets the port connections for the current instantiations (which is got
964
using get_first_instantiation and get_next_instantiation). If the
965
instantiation does not use .port(...) syntax and rvp does not have the
966
access to the source of the module then the port names will be returned as
967
numbers in connection order starting at 0.
968
 
969
 
970
  Returns:    - A hash (well, really a list that can be assigned to a hash).
971
               The keys of the hash are the port names. The values of the
972
               hash is everything (except comments) that appeared in the
973
               brackets in the verilog.
974
 
975
  Example:    %port_con = $vdata->get_current_instantiations_port_con();
976
              foreach $port (keys %port_con) { ...
977
 
978
=cut
979
sub get_current_instantiations_port_con{
980
    my ($self) = @_;
981
    my ($module,$i);
982
 
983
    $module = $self->{current_instantiation_module};
984
    $i      = $self->{current_instantiation} -  1;
985
 
986
    if (@{$self->{modules}{$module}{instances}} > $i ) {
987
        return (%{$self->{modules}{$module}{instances}[$i]{connections}});
988
    }
989
    else {
990
        return {};
991
    }
992
}
993
 
994
###########################################################################
995
 
996
=head1 get_current_instantiations_parameters
997
 
998
Gets the parameters for the current instantiations (which is set using
999
get_first_instantiation and get_next_instantiation).  If the
1000
instantiation parameters does not use the verilog 2001 .name(...)
1001
syntax and rvp does not have the access to the source of the module
1002
then the parameter names will be returned as numbers reflecting the
1003
order (starting at 0).
1004
 
1005
 
1006
  Returns:    - A hash (well, really a list that can be assigned to a hash).
1007
               The keys of the hash are the parameters names. The values of the
1008
               hash is everything (except comments) in the value.
1009
 
1010
  Example:    %parameters = $vdata->get_current_instantiations_parameters();
1011
              foreach my $p (keys %parameters) { ...
1012
 
1013
=cut
1014
sub get_current_instantiations_parameters{
1015
    my ($self) = @_;
1016
    my ($module,$i);
1017
 
1018
    $module = $self->{current_instantiation_module};
1019
    $i      = $self->{current_instantiation} -  1;
1020
 
1021
    my %r;
1022
    if (@{$self->{modules}{$module}{instances}} > $i ) {
1023
        foreach my $p (keys %{$self->{modules}{$module}{instances}[$i]{parameters}}) {
1024
            $r{$p}=$self->{modules}{$module}{instances}[$i]{parameters}{$p}{value};
1025
        }
1026
    }
1027
 
1028
    return %r;
1029
}
1030
 
1031
###########################################################################
1032
 
1033
=head1 get_modules_parameters
1034
 
1035
Gets the parameters for a module.
1036
 
1037
  Arguments:  - module name
1038
 
1039
  Returns:    - A hash (well, really a list that can be assigned to a hash).
1040
               The keys of the hash are the parameters names. The values of the
1041
               hash is everything (except comments) in the value.
1042
 
1043
  Example:    %parameters = $vdata->get_modules_parameters();
1044
              foreach my $p (keys %parameters) { ...
1045
 
1046
=cut
1047
sub get_modules_parameters{
1048
    my ($self,$module) = @_;
1049
 
1050
    my %r;
1051
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
1052
        $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
1053
    }
1054
    return %r;
1055
}
1056
 
1057
#######################################################
1058
################### Modified ###########################
1059
#######################################################
1060
 
1061
=head1 get_modules_parameters_not_local
1062
 
1063
Gets the parameters for a module.
1064
 
1065
  Arguments:  - module name
1066
 
1067
  Returns:    - A hash (well, really a list that can be assigned to a hash).
1068
               The keys of the hash are the parameters names. The values of the
1069
               hash is everything (except comments) in the value.
1070
 
1071
  Example:    %parameters = $vdata->get_modules_parameters();
1072
              foreach my $p (keys %parameters) { ...
1073
 
1074
=cut
1075
sub get_modules_parameters_not_local{
1076
    my ($self,$module) = @_;
1077
 
1078
    my %r;
1079
    foreach my $p (keys %{$self->{modules}{$module}{parameters}}) {
1080
        if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
1081
                #print "$p\n";
1082
                $r{$p}=$self->{modules}{$module}{parameters}{$p}{value};
1083
        }
1084
    }
1085
    return %r;
1086
}
1087
 
1088
 
1089
 
1090
 
1091
=head1 get_modules_parameters_not_local_in_order
1092
 
1093
Gets the parameter names in_order for a module.
1094
 
1095
 
1096
 
1097
=cut
1098
sub get_modules_parameters_not_local_order{
1099
    my ($self,$module) = @_;
1100
        my @r=@{$self->{modules}{$module}{parameter_order}};#param/localparam inorder
1101
        my @w; #parameter inorder
1102
        foreach my $p (@r) {
1103
                if ($self->{modules}{$module}{parameters}{$p}{ptype} ne "localparam"){
1104
                        push(@w,$p);
1105
                }
1106
 
1107
        }
1108
 
1109
        return @w;
1110
}
1111
 
1112
 
1113
 
1114
 
1115
=head1 get_module_ports_inorder
1116
 
1117
Gets the parameter names in_order for a module.
1118
 
1119
 
1120
 
1121
=cut
1122
sub get_module_ports_order{
1123
    my ($self,$module) = @_;
1124
        return @{$self->{modules}{$module}{port_order}};
1125
}
1126
 
1127
 
1128
 
1129
 
1130
 
1131
 
1132
###########################################################################
1133
 
1134
=head1 get_define
1135
 
1136
Find out where a define is defined and what the value is
1137
 
1138
  Arguments:  - name of the define
1139
             Optional arguments where a you want the correct location and
1140
               value for a particular use of a multiplely defined define:
1141
              - file where define is used
1142
              - line where define is used
1143
 
1144
  Returns:    - list with three elements: file, line, value
1145
                 or if the define does not exist it returns a empty list.
1146
                 if the define was defined on the command line it sets file=""
1147
                  and line=0
1148
 
1149
 
1150
  Example:    ($f,$l,$v) = $vdata->get_define($word,$file,$line);
1151
 
1152
=cut
1153
sub get_define {
1154
    my ($self,$define,$file,$line) = @_;
1155
 
1156
    if ( !defined($self) || !defined($define) ||
1157
         ( defined($file) && !defined($line) ) ) {
1158
        die "Get define takes either two or four arguments";
1159
    }
1160
 
1161
    $define =~ s/^\`// ; # remove the ` if any
1162
 
1163
    if (!exists( $self->{defines}{$define} )) {
1164
        return ();
1165
    }
1166
    my $index = 0;
1167
    my $dh = $self->{defines}{$define};
1168
 
1169
    if (defined($file) &&
1170
        exists($dh->{used}{$file}) &&
1171
        exists($dh->{used}{$file}{$line})) {
1172
        $index = $dh->{used}{$file}{$line};
1173
    }
1174
 
1175
 
1176
    if ($index eq "XX") {   # define has been undefed
1177
        return ();
1178
    }
1179
 
1180
    return ( $dh->{defined}[$index]{file},
1181
             $dh->{defined}[$index]{line},
1182
             $dh->{defined}[$index]{value});
1183
}
1184
 
1185
###########################################################################
1186
 
1187
=head1 get_context
1188
 
1189
Get the context (if any) for a line in a file.
1190
 
1191
  Arguments:  - file name
1192
              - line number
1193
 
1194
  Returns:    - line number if there is a context, zero if there is none.
1195
 
1196
  Example:      $l = $vdata->get_context($filename,$line);
1197
 
1198
=cut
1199
sub get_context{
1200
    my ($self,$file,$line) = @_;
1201
 
1202
    if ( exists( $self->{files}{$file}{contexts}{$line} )) {
1203
        return $line;
1204
    }
1205
    else {
1206
        return 0;
1207
    }
1208
}
1209
 
1210
###########################################################################
1211
 
1212
=head1 get_module_start_by_context
1213
 
1214
Test if the context is a module definition start.
1215
 
1216
  Arguments:  - file name
1217
              - line number
1218
 
1219
  Returns:    - module name if it is a module start, 0 otherwise
1220
 
1221
  Example:     if($vdata->get_module_start_by_context($filename,$line))..
1222
 
1223
=cut
1224
# return true if the context for this line is a module start
1225
sub get_module_start_by_context{
1226
    my ($self,$file,$line) = @_;
1227
 
1228
    if ( exists( $self->{files}{$file}{contexts}{$line}{module_start})) {
1229
        return $self->{files}{$file}{contexts}{$line}{module_start};
1230
    }
1231
    else {
1232
        return 0;
1233
    }
1234
}
1235
 
1236
###########################################################################
1237
 
1238
=head1 get_has_value_by_context
1239
 
1240
Check if the context has a value (ie a new module or something). Contexts
1241
that just turn on and off preprocessor ignoring do not have values.
1242
 
1243
  Arguments:  - file name
1244
              - line number
1245
 
1246
  Returns:    - 1 if there is a value, 0 otherwise
1247
 
1248
  Example:    if ($vdata->get_has_value_by_context($file,$line))..
1249
 
1250
=cut
1251
sub get_has_value_by_context{
1252
    my ($self,$file,$line) = @_;
1253
 
1254
    return exists( $self->{files}{$file}{contexts}{$line}{value});
1255
}
1256
 
1257
###########################################################################
1258
 
1259
=head1 get_context_name_type
1260
 
1261
Find the reason for a new context - is it a module / function or task.
1262
Contexts that just turn on and off preprocessor ignoring do not have values.
1263
 
1264
  Arguments:  - file name
1265
              - line number
1266
 
1267
  Returns:    - name
1268
              - type [ module | function | task ]
1269
 
1270
  Example:    ($n,$t)=$vdata->get_context_name_type($file,$line);
1271
 
1272
=cut
1273
sub get_context_name_type{
1274
    my ($self,$file,$line) = @_;
1275
    my ($name,$type);
1276
 
1277
    $type='';
1278
    if (exists( $self->{files}{$file}{contexts}{$line}{value})) {
1279
        $name= $self->{files}{$file}{contexts}{$line}{value}{name};
1280
        if (exists( $self->{files}{$file}{contexts}{$line}{value}{type})) {
1281
            $type=$self->{files}{$file}{contexts}{$line}{value}{type};
1282
            $type='module' if ($type eq 'primitive' || $type eq 'macromodule');
1283
        }
1284
        return ($name,$type);
1285
    }
1286
    else {
1287
        return ();
1288
    }
1289
}
1290
 
1291
###########################################################################
1292
 
1293
=head1 get_pre_ignore_by_context
1294
 
1295
Test if the context is preprocessor ignore.
1296
 
1297
  Arguments:  - file name
1298
              - line number
1299
 
1300
  Returns:    - 1 if it is, 0 otherwise
1301
 
1302
  Example:    if ($vdata->get_pre_ignore_by_context($file,$line))..
1303
 
1304
=cut
1305
sub get_pre_ignore_by_context{
1306
    my ($self,$file,$line) = @_;
1307
 
1308
    if (exists($self->{files}{$file}{contexts}{$line}{pre_ignore})) {
1309
        return $self->{files}{$file}{contexts}{$line}{pre_ignore};
1310
    }
1311
    else {
1312
        return 0;
1313
    }
1314
 
1315
}
1316
 
1317
###########################################################################
1318
 
1319
=head1 get_first_instantiator_by_context
1320
 
1321
Get the first thing that instantiates this module using the context. The
1322
context must be a module_start.
1323
 
1324
  Arguments:  - file name (for context)
1325
              - line name (for context)
1326
 
1327
  Returns:    - a 4 element list: instantiating module, file, instance name, line
1328
 
1329
  Example:
1330
              @i=$vdata->get_first_instantiator_by_context($f,$l );
1331
 
1332
=cut
1333
sub get_first_instantiator_by_context{
1334
    my ($self,$file,$line) = @_;
1335
 
1336
    # note: the second exists() checks that the module still exists as
1337
    #  it could have been deleted because a duplicate was found
1338
    if (exists($self->{files}{$file}{contexts}{$line}{module_start}) &&
1339
        exists($self->{modules}
1340
               {$self->{files}{$file}{contexts}{$line}{module_start}}) &&
1341
        exists($self->{files}{$file}{contexts}{$line}{value}{inst_by})) {
1342
        $self->{current_instantiator}       =0;
1343
        $self->{current_instantiator_module}=
1344
            $self->{files}{$file}{contexts}{$line}{module_start};
1345
        return $self->get_next_instantiator();
1346
    }
1347
    else {
1348
        return ();
1349
    }
1350
 
1351
}
1352
 
1353
###########################################################################
1354
 
1355
=head1 get_inst_on_line
1356
 
1357
Gets the instance name of a line in a file
1358
 
1359
  Arguments:  - file name
1360
              - line number
1361
 
1362
  Returns:    - name if the line has an instance name, 0 otherwise
1363
 
1364
  Example:    if ( $new_inst = $vdata->get_inst_on_line($file,$line) ) ...
1365
 
1366
=cut
1367
sub get_inst_on_line{
1368
    my ($self,$file,$line) = @_;
1369
 
1370
    if ( exists( $self->{files}{$file}{instance_lines}{$line})){
1371
        return $self->{files}{$file}{instance_lines}{$line};
1372
    }
1373
    else {
1374
        return 0;
1375
    }
1376
}
1377
 
1378
###########################################################################
1379
 
1380
=head1 get_signal_by_context
1381
 
1382
Same as get_module_signal but works by specifying a context.
1383
 
1384
  Arguments:  - context file name
1385
              - context line number
1386
              - signal name
1387
 
1388
  Returns:    same as get_module_signal
1389
 
1390
  Example:
1391
 
1392
=cut
1393
# get a signal by context - returns: line, a_line, i_line, type, file
1394
sub get_signal_by_context{
1395
    my ($self,$file,$cline,$sig) = @_;
1396
 
1397
    my $sigp;
1398
 
1399
    # in tasks and functions signals can come from module (m_signals)
1400
    #  or from the task or function itself (which gets precedence).
1401
    if (exists( $self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig} )) {
1402
        print " found signal $sig\n" if $debug;
1403
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{signals}{$sig};
1404
    }
1405
    elsif (exists( $self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig} )) {
1406
        print " found m_signal $sig\n" if $debug;
1407
        $sigp=$self->{files}{$file}{contexts}{$cline}{value}{m_signals}{$sig};
1408
    }
1409
    else {
1410
        return ();
1411
    }
1412
 
1413
    return ($sigp->{line},
1414
            $sigp->{a_line},
1415
            $sigp->{i_line},
1416
            $sigp->{type},
1417
            $sigp->{file},
1418
            $sigp->{posedge},
1419
            $sigp->{negedge},
1420
            $sigp->{type2},
1421
            $sigp->{source}{file},
1422
            $sigp->{source}{line},
1423
            $sigp->{range},
1424
            $sigp->{a_file},
1425
            $sigp->{i_file},
1426
            $sigp->{dimensions});
1427
}
1428
 
1429
###########################################################################
1430
 
1431
=head1 get_t_or_f_by_context
1432
 
1433
Same as get_modules_t_or_f but works by specifying a context.
1434
 
1435
  Arguments:  - context file name
1436
              - context line number
1437
              - task name
1438
 
1439
  Returns:    - same as get_modules_t_or_f
1440
 
1441
  Example:
1442
 
1443
=cut
1444
sub get_t_or_f_by_context{
1445
    my ($self,$cfile,$cline,$t_or_f) = @_;
1446
 
1447
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f})) {
1448
        return($self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{type},
1449
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{line},
1450
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{file},
1451
               $self->{files}{$cfile}{contexts}{$cline}{value}{t_and_f}{$t_or_f}{anchor});
1452
    }
1453
    else {
1454
        return ();
1455
    }
1456
}
1457
###########################################################################
1458
 
1459
=head1 get_parameter_by_context
1460
 
1461
Return the file and line for a named parameter using context
1462
 
1463
  Arguments:  - context file name
1464
              - context line number
1465
              - parameter name
1466
 
1467
  Returns:    - file and line of definition
1468
 
1469
  Example:
1470
 
1471
=cut
1472
sub get_parameter_by_context{
1473
    my ($self,$cfile,$cline,$parameter) = @_;
1474
 
1475
    if (exists($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter})) {
1476
        return($self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{file},
1477
               $self->{files}{$cfile}{contexts}{$cline}{value}{parameters}{$parameter}{line});
1478
    }
1479
    else {
1480
        return ();
1481
    }
1482
}
1483
###########################################################################
1484
 
1485
=head1 get_anchors
1486
 
1487
Get the anchors for a line in a file.
1488
 
1489
 
1490
  Returns:    - a list of anchors
1491
 
1492
  Example:   foreach $anchor ( $vdata->get_anchors($file,$line) ) ..
1493
 
1494
=cut
1495
sub get_anchors{
1496
    my ($self,$file,$line) = @_;
1497
 
1498
    if (exists($self->{files}{$file}{anchors}{$line})) {
1499
        return @{$self->{files}{$file}{anchors}{$line}};
1500
    }
1501
    else {
1502
        return ();
1503
    }
1504
}
1505
 
1506
###########################################################################
1507
 
1508
=head1 expand_defines
1509
 
1510
Expand the defines in a line of verilog code.  for best use this
1511
should be called line by line, so that the defines get the correct
1512
values when defines are defined multiple times
1513
 
1514
  Arguments:  - a pointer to the string to expand the defines in
1515
              - the file the line is from
1516
              - the line number of the line
1517
 
1518
  Returns:    - nothing
1519
 
1520
  Example:   $vdata->expand_defines(\$line_to_expand,$file,$line);
1521
 
1522
=cut
1523
###############################################################################
1524
#
1525
sub expand_defines {
1526
    my ($self,$bufp,$file,$line) = @_;
1527
 
1528
    if (exists($self->{files}{$file}{define_lines}{$line})) {
1529
        # do not expand on a `define line - it doesn't make sense to do so
1530
        #  as the substitution of defines in the value only occurs at the
1531
        #  time of use when they could have different values!
1532
        return;
1533
    }
1534
 
1535
 
1536
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
1537
        my $b = $1;
1538
        my $d = $2;
1539
        my $dq = quotemeta($d);
1540
        my $v;
1541
        if ((undef,undef,$v) = $self->get_define($d,$file,$line)) {
1542
            $$bufp =~ s/\`$dq/$v/;
1543
        }
1544
        else {
1545
            $$bufp =~ s/\`$dq/_BaCkQuOtE_$dq/;
1546
        }
1547
 
1548
    }
1549
    $$bufp =~ s/_BaCkQuOtE_/\`/g;
1550
}
1551
 
1552
 
1553
###########################################################################
1554
 
1555
=head1 verilog_gatetype_keywords
1556
 
1557
 
1558
  Returns:    - a list of verilog gatetype keywords
1559
 
1560
  Example:   @keywords = rvp->verilog_gatetype_keywords();
1561
 
1562
=cut
1563
sub verilog_gatetype_keywords {
1564
    return (@verilog_gatetype_keywords);
1565
}
1566
###########################################################################
1567
 
1568
=head1 verilog_compiler_keywords
1569
 
1570
  Returns:    - a list of verilog compiler keywords
1571
 
1572
  Example:   @keywords = rvp->verilog_compiler_keywords();
1573
 
1574
=cut
1575
sub verilog_compiler_keywords {
1576
    return (@verilog_compiler_keywords);
1577
}
1578
###########################################################################
1579
 
1580
=head1 verilog_signal_keywords
1581
 
1582
  Returns:    - a list of verilog signal keywords
1583
 
1584
  Example:   @keywords = rvp->verilog_signal_keywords();
1585
 
1586
=cut
1587
sub verilog_signal_keywords {
1588
    return (@verilog_signal_keywords);
1589
}
1590
 
1591
 
1592
###########################################################################
1593
 
1594
=head1 chunk_read_init
1595
 
1596
Initialise a file for chunk reading (see chunk_read for more
1597
details). It actually reads the whole file into a string, which
1598
chunk_read then reads a chunk at a time. The file is closed before
1599
chuck_read_init returns.
1600
 
1601
  Arguments:  - the file to read (with path if needed)
1602
              - tabstop: 0 = leave tabs alone
1603
                         N = turn tabs spaces with each tabstop=N
1604
  Returns:    - a handle to pass to chunk_read or 0 if file open fails
1605
 
1606
  Example:
1607
            my $chunkRead = rvp->chunkr_read_init($f,$opts{tabstop});
1608
 
1609
=cut
1610
sub chunk_read_init {
1611
 
1612
    my ($class,$f,$tabstop) = @_;
1613
    local (*F);
1614
 
1615
    open(F,"<$f") || return 0;
1616
 
1617
    my $chunk = { type => "",
1618
                  text => "",
1619
                  isANewLine => 0,
1620
                  isStart => 0,
1621
                  isEnd => 1 ,
1622
                  line => 0 };
1623
 
1624
    my $this = { chunk => $chunk ,
1625
                 tabstop => $tabstop ,
1626
                 linebuf => "" ,
1627
                 state => 0 ,
1628
                 fh => *F };
1629
    return $this;
1630
}
1631
 
1632
###########################################################################
1633
 
1634
=head1 chunk_read
1635
 
1636
Reads verilog a chunk at a time. The file is opened using
1637
chunk_read_init. Then chunk_read is used to read the file a chunk at a
1638
time.  A chunk is a line or part of a line that is all the same type.
1639
 
1640
  The types are:
1641
              comment   - either // or /* */ comment
1642
              attribute - verilog 2001 (* *) atribute
1643
              include   - a line containing `include "file"
1644
              string    - a string
1645
              code      - anything else (verilog code, defines, compliler keywords)
1646
 
1647
Nothing is removed from the file, so if each chunk is printed after being read
1648
you will end up with exactly the same file as you put in.
1649
 
1650
  Arguments:  - handle (from chunk_read_init)
1651
 
1652
  Returns:    - 0 at the end of file, or a hash ref with the following keys:
1653
              type       - one of the types (see above)
1654
              text       - the text read from the file
1655
              line       - the line number the text is on
1656
              isANewLine - true if chunk is the first chunk of the line
1657
              isStart    - true if the chunk is the start (eg "/*..." for
1658
                             a comment )
1659
              isEnd      - true if the chunk is the end ( eg "*/" )
1660
                      NOTE: isEnd is set to undefined for a
1661
                       type="code" that ends in a newline. This is
1662
                       because chunk_read doesn't know if the code is
1663
                       ending or not. If you need to know in this case
1664
                       you can read the next chunk and see what type it is.
1665
 
1666
  Example:
1667
            my $chunkRead = rvp->chunk_read_init($f,0);
1668
            while ($chunk = rvp->chunk_read($chunkRead)) {
1669
                    print $chunk->{text} unless $chunk->{type} eq "comment";
1670
            }
1671
 
1672
=cut
1673
sub chunk_read {
1674
   my ($class,$this) = @_;
1675
 
1676
   my $chunk = $this->{chunk};
1677
   $chunk->{isStart} = $chunk->{isEnd};
1678
   $chunk->{isEnd}  = 0;
1679
   $chunk->{isANewLine} = 0;
1680
 
1681
   if ( $this->{linebuf} eq "" ) {
1682
       if (!defined($this->{linebuf} = readline($this->{fh}))) {
1683
           close($this->{fh});
1684
           return 0;
1685
       }
1686
       $chunk->{isANewLine} = 1;
1687
       $chunk->{line}++;
1688
       if ($this->{tabstop}!=0) {
1689
           # 1 while is some stupid perl thing meaning while (cond) {} may be a bit faster?
1690
           1 while ($this->{linebuf} =~ s/(^|\n)([^\t\n]*)(\t+)/
1691
                    $1. $2 . (" " x ($this->{tabstop} * length($3) -
1692
                                     (length($2) % $this->{tabstop})))
1693
                    /gsex);
1694
       }
1695
   }
1696
 
1697
 STATE_SWITCH:
1698
   if ( $this->{state} == 0 ) {
1699
       $chunk->{type} = "code";
1700
       if ( $this->{linebuf} =~
1701
            s%^(.*?)((/\*)|           # anything followed by /* comment
1702
                     (//)|            #    or // comment
1703
                     (\(\*(?!\s*\)))| #    or (* attribute (but not (*)
1704
                     (\`include\s)|   #    or `include
1705
                     (\"))            #    or start of string
1706
            %$2%ox ) {
1707
           $chunk->{isEnd} = 1;
1708
           $chunk->{text} = $1;
1709
           if (defined($3)) {
1710
               $this->{state} = 1;  # long comment
1711
           }
1712
           elsif (defined($4)) {
1713
               $this->{state} = 2;  # short comment
1714
           }
1715
           elsif (defined($5)) {
1716
               $this->{state} = 3;  # attribute
1717
           }
1718
           elsif (defined($6)) {
1719
               $this->{state} = 4;  # include
1720
           }
1721
           elsif (defined($7)) {
1722
               $this->{state} = 5;  # string
1723
           }
1724
           else {
1725
               die "chunk_read internal error!";
1726
           }
1727
           if (!$chunk->{text}) {
1728
               # this happens if we are in state code and a new line
1729
               #  starts with something that isn't code. So we change
1730
               #  and go back to the top.
1731
               $chunk->{isStart} = 1;
1732
               $chunk->{isEnd}  = 0;
1733
               goto STATE_SWITCH;
1734
           }
1735
       }
1736
       else {
1737
           $chunk->{text} = $this->{linebuf};
1738
           $this->{linebuf} = "";
1739
           # in this case we might be at end, but we don't really know!
1740
           $chunk->{isEnd}  = undef;
1741
       }
1742
   }
1743
   elsif ( $this->{state} == 1 ) {
1744
       $chunk->{type} = "comment";
1745
       # this first test is needed to work so /*/  */ works
1746
       if ( $chunk->{isStart} && $this->{linebuf} =~ s%^/\*%% ) {
1747
           $chunk->{text} = "/*";
1748
       }
1749
       else {
1750
           $chunk->{text} = "";
1751
       }
1752
       if ( $this->{linebuf} =~ s%^(.*?\*/)%% ) {          # anything followed by */
1753
           $chunk->{text} .= $1;
1754
           $this->{state} = 0;
1755
           $chunk->{isEnd} = 1;
1756
       }
1757
       else {
1758
           $chunk->{text} .= $this->{linebuf};
1759
           $this->{linebuf} = "";
1760
       }
1761
   }
1762
   elsif ( $this->{state} == 2 ) {
1763
       $chunk->{type} = "comment";
1764
       $chunk->{text} = $this->{linebuf};
1765
       $chunk->{isEnd} = 1;
1766
       $this->{linebuf} = "";
1767
       if ( $chunk->{text} =~ s/\n$// ) {
1768
           $this->{linebuf} = "\n";
1769
       }
1770
       $this->{state} = 0;
1771
   }
1772
   elsif ( $this->{state} == 3 ) {
1773
       $chunk->{type} = "attribute";
1774
       if ( $this->{linebuf} =~ s%^(.*?\*\))%% ) {          # anything followed by *)
1775
           $chunk->{text} = $1;
1776
           $this->{state} = 0;
1777
           $chunk->{isEnd} = 1;
1778
       }
1779
       else {
1780
           $chunk->{text} = $this->{linebuf};
1781
           $this->{linebuf} = "";
1782
       }
1783
   }
1784
   elsif ( $this->{state} == 4 ) {
1785
       $chunk->{type} = "include";
1786
       $chunk->{isEnd} = 1;
1787
       if ( $this->{linebuf} =~ s%^(\`include\s+\".*?\")%% ) {
1788
           $chunk->{text} = $1;
1789
           $this->{state} = 0;
1790
       }
1791
       else {
1792
           # this is an error - just return the line as code - the parser will
1793
           #  report the error
1794
           $chunk->{type} = 0;
1795
           $chunk->{text} = $this->{linebuf};
1796
           $this->{linebuf} = "";
1797
       }
1798
   }
1799
   elsif ( $this->{state} == 5 ) {
1800
       $chunk->{type} = "string";
1801
       # string all on one line
1802
       if ( $this->{linebuf} =~ s%^(\"(?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
1803
           $chunk->{text} = $1;
1804
           $this->{state} = 0;
1805
           $chunk->{isEnd} = 1;
1806
       }
1807
       # end of multiline string (doesn't start with quote)
1808
       elsif ( $this->{linebuf} =~ s%^([^\"](?:(?:\\\\)|(?:\\\")|(?:[^\"]))*?\")%% ) {
1809
           $chunk->{text} = $1;
1810
           $this->{state} = 0;
1811
           $chunk->{isEnd} = 1;
1812
       }
1813
       # middle of multiline string
1814
       else {
1815
           $chunk->{text} = $this->{linebuf};
1816
           $this->{linebuf} = "";
1817
       }
1818
   }
1819
 
1820
   return $chunk;
1821
}
1822
 
1823
###############################################################################
1824
#  RVP internal functions from now on.... (they all start with _ to
1825
#   let you know they are internal
1826
###############################################################################
1827
 
1828
###############################################################################
1829
# search a file, putting the data in $self
1830
#   Note: be careful coding in the main loop... there are a few optimisations
1831
#    which result in big chunks of code being skipped if the line does not
1832
#    contain certain characters (eg ' " / *)
1833
sub _search {
1834
    my ($self,$f,$inc_dirs) = @_;
1835
 
1836
    my $verilog_compiler_keywords_regexp = "(?:" .
1837
        join("|",@verilog_compiler_keywords) .
1838
            ")";
1839
 
1840
 
1841
    my $file=_ffile($f);
1842
    _init_file($self->{files},$f);
1843
 
1844
    print "Searching $f " unless $quiet;
1845
    my $chunkRead= rvp->chunk_read_init($f,0) ||
1846
        die "Error: can not open file $f to read: $!\n";
1847
    my $file_dir = dirname($f);
1848
 
1849
    my $rs = {};
1850
    $rs->{modules}   = $self->{modules};
1851
    $rs->{files}     = $self->{files};
1852
    $rs->{unres_mod} = $self->{unresolved_modules};
1853
 
1854
    $rs->{module}   = '';
1855
    $rs->{function} = '';
1856
    $rs->{task}     = '';
1857
    $rs->{t}        = undef; # temp store
1858
    $rs->{p}        = undef;
1859
 
1860
    my $printline = 1000;
1861
 
1862
    my $ps = {};
1863
    my $nest=0;
1864
    my $nest_at_ignore;
1865
    my @ignore_from_elsif;
1866
    my $ignoring=0;
1867
    my @fileStack =();
1868
    my $pp_ignore;
1869
    my $chunk;
1870
    while (1) {
1871
        while ($chunk = rvp->chunk_read($chunkRead)) {
1872
            $self->{files}{$file}{lines} = $chunk->{line};
1873
            if ($chunk->{line}>$printline && !$quiet) {
1874
                $printline+=1000;
1875
                $|=1; # turn on autoflush
1876
                print ".";
1877
                $|=0 unless $debug; # turn off autoflush
1878
            }
1879
 
1880
            # deal quickly with blank lines
1881
            if ( $chunk->{text} =~ m/^\s*\n/ ) {
1882
                next;
1883
            }
1884
 
1885
 
1886
            if ( $chunk->{type} eq "code" ) {
1887
 
1888
 
1889
                ####################################################
1890
                # Optimisation: if there are no ` 
1891
                #  we can parse the line now
1892
                if ( $chunk->{text} !~ m|[\`]| ) {
1893
                    if ($nest && $ignoring) {
1894
                        next;
1895
                    }
1896
                    $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
1897
                    next;
1898
                }
1899
 
1900
                # handle ifdefs
1901
                if ($nest && $ignoring) {
1902
                    if ( $chunk->{text} =~ m/^\s*\`(?:ifdef|ifndef)\s+($VID)/ ) {
1903
                        print " Found at line $chunk->{line} : if[n]def (nest=$nest)\n" if $debug;
1904
                        $nest++;
1905
                    }
1906
                    elsif ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
1907
                        print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
1908
                        if ($1 eq 'else' ||
1909
                            _parsing_is_defined($self->{defines},$2,
1910
                                                $file,$chunk->{line})) {
1911
                            # true elsif or plain else
1912
                            if ($nest == $nest_at_ignore &&
1913
                                !$ignore_from_elsif[$nest]) {
1914
                                $ignoring=0;
1915
                                $$pp_ignore = $chunk->{line};
1916
                            }
1917
                        }
1918
                    }
1919
                    elsif ( $chunk->{text} =~ m/^\s*\`endif/ ) {
1920
                        print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
1921
                        if ($nest == $nest_at_ignore) {
1922
                            $ignoring=0;
1923
                            $$pp_ignore = $chunk->{line};
1924
                        }
1925
                        $nest--;
1926
                    }
1927
                    next;
1928
                }
1929
                # handle the case where the endif is on the same line as the ifdef
1930
                #  (note: generally I only accept endif at the start of a line)
1931
                if ( $chunk->{text} =~ m/\`(ifdef|ifndef)\s+($VID).*\`endif/ ) {
1932
                    print "$file: ifdef and endif on same line\n" if $debug;
1933
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
1934
                                                         $file,$chunk->{line});
1935
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
1936
                         (($1 eq 'ifndef') &&  $is_defined)) {
1937
                        # replace ifdef with nothing
1938
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif//;
1939
                    }
1940
                    else {
1941
                        # replace ifdef with what is between the ifdef and endif
1942
                        $chunk->{text} =~ s/\`(ifdef|ifndef)\s+($VID)(.*)\`endif/$3/;
1943
                    }
1944
                }
1945
                if ( $chunk->{text} =~ m/^\s*\`(ifdef|ifndef)\s+($VID)/ ) {
1946
                    $nest++;
1947
                    print " Found at line $chunk->{line} : $1 $2 (nest=$nest)\n" if $debug;
1948
                    my $is_defined = _parsing_is_defined($self->{defines},$2,
1949
                                                         $file,$chunk->{line});
1950
                    if ( (($1 eq 'ifdef' ) && !$is_defined) ||
1951
                         (($1 eq 'ifndef') &&  $is_defined)) {
1952
                        $ignoring=1;
1953
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
1954
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
1955
                        $nest_at_ignore=$nest;
1956
                        $ignore_from_elsif[$nest]=0;
1957
                    }
1958
                    next;
1959
                }
1960
                if ( $chunk->{text} =~ m/^\s*\`(else|(?:elsif\s+($VID)))/ ) {
1961
                    print " Found at line $chunk->{line} : $1 (nest=$nest)\n" if $debug;
1962
                    if ($nest) {
1963
                        $ignoring=1;
1964
                        $self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore} = 'XX';
1965
                        $pp_ignore = \$self->{files}{$file}{contexts}{$chunk->{line}}{pre_ignore};
1966
                        $nest_at_ignore=$nest;
1967
                        # an ignore from an elsif means you will never stop ignoring
1968
                        #   at this nest level
1969
                        $ignore_from_elsif[$nest]=($1 ne 'else');
1970
                    }
1971
                    else {
1972
                        $self->_add_warning("$file:$chunk->{line}: found $1 without \`ifdef");
1973
                    }
1974
                    next;
1975
                }
1976
                if ( $chunk->{text} =~ m/^\s*\`endif/ ) {
1977
                    print " Found at line $chunk->{line} : endif (nest=$nest)\n" if $debug;
1978
                    if ($nest) {
1979
                        $nest--;
1980
                    }
1981
                    else {
1982
                        $self->_add_warning("$file:$chunk->{line}: found \`endif without \`ifdef");
1983
                    }
1984
                    next;
1985
                }
1986
 
1987
                # match define. Note: /s makes the .* match the \n too
1988
                if ( $chunk->{text} =~ m/^\s*\`define\s+($VID)(.*)/s ) {
1989
                    my $def = $1;
1990
                    my $rest = defined($2)?$2:'';
1991
                    my $defLine = $chunk->{line};
1992
                    $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
1993
 
1994
                    # _parsing_expand_defines is called to register the use
1995
                    #  of any multiplely defined defines in the value part of
1996
                    #  the define
1997
                    my $tmpValue=$rest;
1998
                    $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
1999
 
2000
                    # handle multiline defines: read more stuff if line ends in backslash
2001
                    #  (revisit: verilog spec says leave the newline in the value)
2002
                    # also keep adding stuff to value until it ends in a newline or comment
2003
                    #  because strings are seperated out, `define T $display("test")
2004
                    #  is delivered as chunks '`define T $display(' ,'"test"', ')\n'
2005
                    while ( (($rest =~ s|\\\n|| ) ||  ($rest !~ m/\n$/) )
2006
                            && ($chunk = rvp->chunk_read($chunkRead))) {
2007
                        last if $chunk->{type} eq "comment";
2008
                        $rest .= $chunk->{text};
2009
                        $self->{files}{$file}{define_lines}{$chunk->{line}} = 1;
2010
                        # _parsing_expand_defines call: see comment ~15 lines back
2011
                        my $tmpValue=$chunk->{text};
2012
                        $self->_parsing_expand_defines(\$tmpValue,$file,$chunk->{line});
2013
                    }
2014
                    my $value = $rest;
2015
                    $value =~ s/^\s+(.*)(\n)?/$1/;
2016
 
2017
                    print " Found in $file line $defLine : define $def = $value\n"
2018
                        if $debug;
2019
                    _add_define($self->{defines}, $def , $value , $file, $defLine );
2020
                    _add_anchor($self->{files}{$file}{anchors},$defLine,"");
2021
                    # Don't substitute now: [defines] shall be substituted after the 
2022
                    # original macro is substituted, not when it is defined(1364-2001 pg353)
2023
                    next;
2024
                }
2025
 
2026
                if ( $chunk->{text} =~ m/^\s*\`undef\s+($VID)/ ) {
2027
                    _undef_define($self->{defines},$1);
2028
                    print " Found at line $chunk->{line} : undef $1\n" if $debug;
2029
                    next;
2030
                }
2031
 
2032
                if ( $chunk->{text} =~ m/^\s*$verilog_compiler_keywords_regexp/ ) {
2033
                    next;
2034
                }
2035
                $self->_parsing_expand_defines(\$chunk->{text},$file,$chunk->{line});
2036
 
2037
                # Note this is called from two other places (optimisations)
2038
                $self->_parse_line($chunk->{text},$file,$chunk->{line},$ps,$rs);
2039
            }
2040
            elsif ( $chunk->{type} eq "include" ) {
2041
                if ($nest && $ignoring) {
2042
                    next;
2043
                }
2044
 
2045
                $chunk->{text} =~ m/^\s*\`include\s+\"(.*?)\"/ ;
2046
                # revisit - need to check for recursive includes
2047
                print " Found at line $chunk->{line} : include $1\n" if $debug;
2048
                $self->{files}{$file}{includes}{_ffile($1)}=$chunk->{line};
2049
                my $inc_file = $1;
2050
                my $inc_file_and_path = _scan_dirs($inc_file,$inc_dirs,$file_dir);
2051
                if ($inc_file_and_path) {
2052
                    push(@fileStack,$chunkRead,$f);
2053
                    $f = $inc_file_and_path;
2054
                    $file=_ffile($f);
2055
                    $file_dir = dirname($f);
2056
 
2057
                    if (!exists($self->{files}{$file})) {
2058
                        _init_file($self->{files},$f);
2059
                        if (exists($rs->{modules}{$rs->{module}})) {
2060
                            $self->{files}{$file}{contexts}{"1"}{value} =
2061
                                $rs->{modules}{$rs->{module}};
2062
                        }
2063
                    }
2064
                    print "\n Include: $f " unless $quiet;
2065
                    $chunkRead=rvp->chunk_read_init($f,0);
2066
                }
2067
                else {
2068
                    $self->_add_warning("$file:$chunk->{line}: Include file $inc_file not found");
2069
                }
2070
                next;
2071
            }
2072
 
2073
            if (defined($pp_ignore) && $pp_ignore eq "XX") { # no endif
2074
                $$pp_ignore = $chunk->{line};
2075
            }
2076
        }
2077
        # check if we were included from another file
2078
        if (0==scalar(@fileStack)) {
2079
            print "Stack is empty\n" if $debug;
2080
            last;
2081
        }
2082
        else {
2083
            $f    = pop(@fileStack);
2084
            $chunkRead = pop(@fileStack);
2085
            $file = _ffile($f);
2086
            $file_dir = dirname($f);
2087
            print "\n Back to $f" unless $quiet;
2088
        }
2089
    }
2090
 
2091
    print "\n" unless $quiet;
2092
 
2093
    $self->_check_end_state($file,$self->{files}{$file}{lines},$ps);
2094
 
2095
}
2096
 
2097
sub _open_file {
2098
    my ($f) = @_;
2099
    local (*F);
2100
 
2101
    print "Searching $f " unless $quiet;
2102
    open(F,"<$f") || die "Error: can not open file $f to read: $!\n ";
2103
    return *F;
2104
}
2105
 
2106
# only for use while parsing - returns the last defined value
2107
#  in a multiple define case, and also sets up the {used} info
2108
#  for use later when querying the database
2109
# returns ($value,$errcode)
2110
#  where $errcode = 0  value ok
2111
#                   1  value never defined
2112
#                   2  value has been undefined
2113
sub _parsing_get_define_value {
2114
    my ($defines,$define,$file,$line) = @_;
2115
 
2116
    if (!exists( $defines->{$define} )) {
2117
        return ('',1);
2118
    }
2119
    my $index = 0;
2120
    my $dh = $defines->{$define};
2121
 
2122
    if ( 1 < @{$dh->{defined}} ) {
2123
        $index = $#{$dh->{defined}};
2124
 
2125
        $dh->{used}{$file}{$line} = $index;
2126
    }
2127
 
2128
    if ($dh->{defined}[$index]{undefed}) {
2129
        $dh->{used}{$file}{$line} = "XX";
2130
        return ('',2);
2131
    }
2132
 
2133
    return  ( $dh->{defined}[$index]{value} , 0 );
2134
}
2135
 
2136
sub _parsing_is_defined {
2137
    my ($defines,$define,$file,$line) = @_;
2138
 
2139
    my $v;
2140
    my $errcode;
2141
    ($v,$errcode) = _parsing_get_define_value($defines,$define,$file,$line);
2142
    if ( ($errcode == 1)  ||   # never defined
2143
         ($errcode == 2) ) {   # defined then undefed
2144
        return 0;
2145
    }
2146
    elsif ($errcode == 0) {
2147
        return 1;
2148
    }
2149
    else {
2150
        die "parsing_is_defined internal error code=$errcode";
2151
    }
2152
}
2153
 
2154
sub _undef_define {
2155
    my ($defines,$define) = @_;
2156
 
2157
    if (exists( $defines->{$define} )) {
2158
        my $index = $#{$defines->{$define}{defined}};
2159
        $defines->{$define}{defined}[$index]{undefed} = 1;
2160
    }
2161
}
2162
 
2163
###############################################################################
2164
# for best use this should be called line by line, so that the
2165
#  defines get the correct values when defines are defined multiple
2166
#  times
2167
# - this function is only used during the initial parsing of the files
2168
#  (it has the error reproting code in it), use expand_defines() other times
2169
#  it also expands on define lines (used to register the use of multiple
2170
#   define defines) which expand_defines doesn't
2171
#
2172
sub _parsing_expand_defines {
2173
    my ($self,$bufp,$file,$line) = @_;
2174
 
2175
    my $defines = $self->{defines};
2176
    while ( $$bufp =~ m/^(.*?)\`($VID)/ ) {
2177
        my $b = $1;
2178
        my $d = $2;
2179
        my $dq = quotemeta($d);
2180
        my $v;
2181
        my $errCode=0;
2182
        ($v,$errCode)=_parsing_get_define_value($defines,$d,$file,$line);
2183
 
2184
        if ($errCode == 0) {  # no error
2185
            $$bufp =~ s/\`$dq/$v/;
2186
        }
2187
        else {
2188
            if ($errCode == 2) {  # defined but then undefed
2189
                $self->_add_warning("$file:$line: define `$d used after undef");
2190
                $$bufp =~ s/\`$dq//;
2191
            }
2192
            elsif ($b =~ m/^\s*$/) {
2193
                $self->_add_warning("$file:$line: unknown define: `$d, guessing it is a compiler directive");
2194
                $$bufp='';
2195
            }
2196
            else {
2197
                $self->_add_warning("$file:$line: found undefined define `$d");
2198
                $$bufp =~ s/\`$dq//;
2199
            }
2200
        }
2201
    }
2202
}
2203
 
2204
###############################################################################
2205
# Look through all the include/library directories for an include/library file
2206
#  optional $file_dir is used when including - here a relative path is
2207
#   relative to the file doing the including, so check this it checks this
2208
sub _scan_dirs {
2209
    my ($fname,$inc_dirs,$file_dir) = @_;
2210
    my ($dir);
2211
 
2212
    if ( $fname =~ m|^/| ) { # an absolute path
2213
      return "$fname" if ( -r "$fname" && ! -d "$fname");
2214
    }
2215
    if (defined($file_dir) && -r "$file_dir/$fname" && ! -d "$file_dir/$fname") {
2216
        return "$file_dir/$fname";
2217
    }
2218
    else {
2219
      foreach $dir (@{$inc_dirs}) {
2220
          $dir =~ s|/$||;
2221
          return "$dir/$fname" if ( -r "$dir/$fname" && ! -d "$dir/$fname");
2222
      }
2223
    }
2224
    return '';
2225
}
2226
 
2227
###############################################################################
2228
# Take a look through the unresolved modules , delete any that have already
2229
#  been found, and for the others look on the search path
2230
#
2231
sub _resolve_modules {
2232
    my ($self,$lib_dirs, $lib_exts)= @_;
2233
    my ($m,$file,@resolved,$lib_ext);
2234
 
2235
    @resolved=();
2236
    foreach $m (sort (keys %{$self->{unresolved_modules}})) {
2237
        if ( exists( $self->{modules}{$m} )) {
2238
            delete( $self->{unresolved_modules}{$m} );
2239
        }
2240
        else {
2241
            foreach $lib_ext (@{$lib_exts}) {
2242
                if ($file = _scan_dirs("$m$lib_ext",$lib_dirs)){
2243
                    delete( $self->{unresolved_modules}{$m} );
2244
                    print "resolve_modules: found $m in $file\n" if $debug;
2245
                    push(@resolved,$file);
2246
                    last;
2247
                }
2248
            }
2249
        }
2250
    }
2251
    return @resolved;
2252
}
2253
 
2254
 
2255
###############################################################################
2256
# Initialize fdata->{files}{FILE} which stores file data
2257
#
2258
sub _init_file {
2259
    my ($fdataf,$file) = @_;
2260
    my ($fb);
2261
    $fb = _ffile($file);
2262
    $fdataf->{$fb} = {};                 # set up hash for each file
2263
    $fdataf->{$fb}{full_name} = $file;
2264
    $fdataf->{$fb}{anchors}  = {};
2265
    $fdataf->{$fb}{modules}  = {};
2266
    $fdataf->{$fb}{contexts} = {};
2267
    $fdataf->{$fb}{includes} = {};
2268
    $fdataf->{$fb}{inc_done} = 0;
2269
    $fdataf->{$fb}{lines}    = 0;
2270
    $fdataf->{$fb}{instance_lines} = {};
2271
    $fdataf->{$fb}{define_lines} = {};
2272
    $fdataf->{$fb}{included_by} = [];
2273
 
2274
}
2275
 
2276
###############################################################################
2277
# Initialize fdata->{FILE}{modules}{MODULE} which stores 
2278
#  module (or macromodule or primitive) data
2279
#
2280
sub _init_module {
2281
    my ($modules,$module,$file,$line,$type) = @_;
2282
 
2283
 
2284
    die "Error: attempt to reinit module" if (exists($modules->{$module}));
2285
 
2286
    $modules->{$module}{line}     = $line;
2287
    $modules->{$module}{name}     = $module;
2288
    $modules->{$module}{type}     = $type;
2289
    $modules->{$module}{end}       = -1;
2290
    $modules->{$module}{file}      = $file;
2291
    $modules->{$module}{t_and_f}   = {}; # tasks and functions
2292
    $modules->{$module}{signals}   = {};
2293
    $modules->{$module}{parameter_order}= [];
2294
    $modules->{$module}{parameters}= {};
2295
    $modules->{$module}{instances} = []; # things that this module instantiates
2296
    $modules->{$module}{inst_by}   = []; # things that instantiated this module
2297
    $modules->{$module}{port_order} = [];
2298
    $modules->{$module}{named_ports} = 1; # assume named ports in instantiations
2299
    $modules->{$module}{duplicate} = 0;   # set if another definition is found
2300
 
2301
}
2302
 
2303
###############################################################################
2304
# Initialize fdata->{FILE}{modules}{MODULE}{t_and_f}{TF} which
2305
#  stores tasks and functions' data
2306
#
2307
sub _init_t_and_f {
2308
    my ($self,$module,$type,$tf,$file,$line,$anchor) = @_;
2309
 
2310
    if (exists($module->{t_and_f}{$tf})) {
2311
        $self->_add_warning("$file:$line new definition of $tf ".
2312
                    "(discarding previous from ".
2313
                    "$module->{t_and_f}{$tf}{file}:$module->{t_and_f}{$tf}{line})");
2314
    }
2315
    $module->{t_and_f}{$tf} = {};
2316
    $module->{t_and_f}{$tf}{type}      = $type;
2317
    $module->{t_and_f}{$tf}{name}      = $tf;
2318
    $module->{t_and_f}{$tf}{line}      = $line;
2319
    $module->{t_and_f}{$tf}{end}       = -1;
2320
    $module->{t_and_f}{$tf}{file}      = $file;
2321
    $module->{t_and_f}{$tf}{signals}   = {};
2322
    $module->{t_and_f}{$tf}{anchor}    = $anchor;
2323
    # point up at things to share with module:
2324
    #  - task and functions
2325
    #  - module signals
2326
    $module->{t_and_f}{$tf}{t_and_f}    = $module->{t_and_f};
2327
    $module->{t_and_f}{$tf}{parameters} = $module->{parameters};
2328
    $module->{t_and_f}{$tf}{parameter_order} = $module->{parameter_order};
2329
    $module->{t_and_f}{$tf}{m_signals}  = $module->{signals};
2330
}
2331
 
2332
# note returns 1 if a signal is added (and an anchor needs to be dropped)
2333
sub _init_signal  {
2334
    my ($self,$signals,$name,$type,$type2,$range,$file,$line,$warnDuplicate,$dims) = @_;
2335
 
2336
    if (exists( $signals->{$name} )) {
2337
        if ($warnDuplicate) {
2338
            if (($signals->{$name}{type} eq "output")||
2339
                ($signals->{$name}{type} eq "inout")||
2340
                ($signals->{$name}{type} eq "input")) {
2341
                if (($signals->{$name}{type} eq "input")
2342
                    && ($type eq "reg")) {
2343
                    $self->_add_warning("$file:$line: ignoring definition".
2344
                                " of input $name as reg (defined as input at".
2345
                                " $signals->{$name}{file}:$signals->{$name}{line})");
2346
                }
2347
                else {
2348
                    $signals->{$name}{type2}=$type;
2349
                }
2350
            }
2351
            elsif (($signals->{$name}{type} eq "reg")&&  # reg before output
2352
                   (($type eq "output") ||
2353
                    ($type eq "inout"))) {
2354
                $signals->{$name}{type}=$type;
2355
                $signals->{$name}{type2}="reg";
2356
            }
2357
            else {
2358
                $self->_add_warning("$file:$line: ignoring another definition".
2359
                            " of signal $name ($type) first seen as".
2360
                            " $signals->{$name}{type} at".
2361
                            " $signals->{$name}{file}:$signals->{$name}{line}");
2362
            }
2363
        }
2364
        return 0;
2365
    }
2366
    else {
2367
        $signals->{$name} = { type     => $type,
2368
                              file     => $file,
2369
                              line     => $line,
2370
                              a_line   => -1,
2371
                              a_file   => "",
2372
                              i_line   => -1,
2373
                              i_file   => "",
2374
                              port_con => [],
2375
                              con_to   => [],
2376
                              posedge  => 0,
2377
                              negedge  => 0,
2378
                              type2    => $type2,
2379
                              source   => { checked => 0, file => "" ,
2380
                                            line => "" },
2381
                              range    => $range,
2382
                              dimensions => $dims,
2383
                              };
2384
        return 1;
2385
    }
2386
}
2387
 
2388
###############################################################################
2389
# Add an anchor to the list of anchors that need to be put in
2390
#  the file
2391
#
2392
sub _add_anchor {
2393
    my ($anchors,$line,$name) = @_;
2394
 
2395
    my ($a,$no_name_exists);
2396
 
2397
    if (! exists($anchors->{$line}) ) {
2398
        $anchors->{$line} = [];
2399
    }
2400
 
2401
    if ( $name ) {
2402
        push( @{$anchors->{$line}} , $name );
2403
    }
2404
    else {
2405
        # if no name is specified then you'll get the line number
2406
        #  as the name, but make sure this only happens once
2407
        $no_name_exists = 0;
2408
        foreach $a ( @{$anchors->{$line}} ) {
2409
            if ($a eq $line) {
2410
                $no_name_exists=1;
2411
                last;
2412
            }
2413
        }
2414
        push( @{$anchors->{$line}} , $line ) unless ($no_name_exists);
2415
    }
2416
}
2417
 
2418
sub _add_define {
2419
    my ($defines,$def_name,$def_value,$file,$line) = @_;
2420
 
2421
    $def_value = '' if (!defined($def_value));
2422
    $def_value =~ s/\s+$//; # remove whitespace from end of define
2423
 
2424
    if (!exists($defines->{$def_name})) {
2425
        $defines->{$def_name} = { defined => [] , used => {} };
2426
    }
2427
 
2428
    if ( (1 == @{$defines->{$def_name}{defined}}) &&
2429
         ($defines->{$def_name}{defined}[0]{file} eq $file) &&
2430
         ($defines->{$def_name}{defined}[0]{line} == $line) ) {
2431
        # if the define is already defined once (and only once) and that 
2432
        #  was the same def (file & line the same - for instance in included
2433
        #   file) then there is no need to do anything
2434
    }
2435
    else {
2436
        push (@{$defines->{$def_name}{defined}},
2437
              { line => $line, file => $file ,
2438
                value => $def_value, undefed => 0 });
2439
    }
2440
}
2441
 
2442
###############################################################################
2443
#   Cross referencing
2444
###############################################################################
2445
 
2446
###############################################################################
2447
# Cross-reference all the files:
2448
#  - find the modules and set up $self->{modules}
2449
#  - store the data about where it is instatiated with each module
2450
#  - check for self instantiation
2451
#  - check for files with modules + instances outside modules
2452
#  - set a_line for signals driven by output and i_line
2453
#
2454
sub _cross_reference {
2455
    my ($self) = @_;
2456
    my ($f,$m,$fr,$mr,$m2,$inst,$sig,$sigp,$port_con,$param,$i,$port,$con_to);
2457
 
2458
    # stores the instantiation data in an 
2459
    #  array so that we can easily tell which modules
2460
    #  are disconnected and which are the tops of the
2461
    #  hierarchy and makes it easier to go up
2462
    foreach $m (sort (keys %{$self->{modules}})) {
2463
        print " Making inst_by for $m\n" if $debug;
2464
        foreach $m2 (sort (keys %{$self->{modules}})) {
2465
            foreach $inst (@{$self->{modules}{$m2}{instances}}) {
2466
                if (($inst->{module} eq $m) &&
2467
                    exists($self->{modules}{$m})) {
2468
                    print "    inst by $m2\n" if $debug;
2469
                    push( @{$self->{modules}{$m}{inst_by}},
2470
                           { module => $m2,
2471
                             file   => $inst->{file},
2472
                             inst   => $inst->{inst_name} ,
2473
                             line   => $inst->{line} } );
2474
                }
2475
            }
2476
        }
2477
    }
2478
 
2479
    # Find any modules that appear to instantiate themselves
2480
    #  (to prevent getting into infinite recursions later on)
2481
    foreach $m (sort (keys %{$self->{modules}})) {
2482
        print " Checking  self instantiations for $m\n" if $debug;
2483
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
2484
            if ($inst->{module} eq $m) {
2485
                $self->_add_warning("$inst->{file}:$inst->{line}: $m ".
2486
                            "instantiates itself");
2487
                $inst->{module} = '_ERROR_SELF_INSTANTIATION_';
2488
                # remove the port con for all signals not attached
2489
                foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
2490
                    $sigp = $self->{modules}{$m}{signals}{$sig};
2491
                    my $port_con_ok=[];
2492
                    foreach $port_con (@{$sigp->{port_con}}) {
2493
                        if ($port_con->{module} ne $m) { push(@$port_con_ok,$port_con); }
2494
                        else {  print " Deleting connection for $sig\n" if $debug; }
2495
                    }
2496
                    $sigp->{port_con} = $port_con_ok;
2497
                }
2498
            }
2499
        }
2500
    }
2501
 
2502
    # Go through instances without named ports (port will be a number instead) and
2503
    #  resolve name if you can, otherwise delete. These can appear in signal's port_con
2504
    #  lists and in instances connections lists.
2505
    foreach $m (sort (keys %{$self->{modules}})) {
2506
        if (0 == $self->{modules}{$m}{named_ports}) {
2507
            $f = $self->{modules}{$m}{file}; # for error messages
2508
            print " Resolving numbered port connections in $m\n" if $debug;
2509
            foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
2510
                print "   doing $sig\n" if $debug;
2511
                $sigp = $self->{modules}{$m}{signals}{$sig};
2512
 
2513
                foreach $port_con (@{$sigp->{port_con}}) {
2514
                    if ($port_con->{port} =~ m/^[0-9]/ ) {
2515
                        if ( exists( $self->{modules}{$port_con->{module}}) ) {
2516
                            $m2 = $self->{modules}{$port_con->{module}};
2517
                            if (defined($m2->{port_order}[$port_con->{port}])) {
2518
                                $port_con->{port}=$m2->{port_order}[$port_con->{port}];
2519
                            }
2520
                            else {
2521
                                $self->_add_warning("$port_con->{file}:$port_con->{line}:".
2522
                                            " could not resolve port number to name");
2523
                            }
2524
                        }
2525
                    }
2526
                }
2527
            }
2528
 
2529
            foreach $inst (@{$self->{modules}{$m}{instances}}) {
2530
                if ( exists( $self->{modules}{$inst->{module}}) ) {
2531
                    $m2 = $self->{modules}{$inst->{module}};
2532
                    foreach $port (sort (keys %{$inst->{connections}})) {
2533
                        last if ($port !~ m/^[0-9]/); # if any are named, all are named
2534
                        if (defined($m2->{port_order}[$port])) {
2535
                            # move old connection to named port
2536
                            $inst->{connections}{$m2->{port_order}[$port]} =
2537
                                $inst->{connections}{$port};
2538
                            # remove old numbered port from hash
2539
                            delete($inst->{connections}{$port});
2540
                        }
2541
                        else {
2542
                            $self->_add_warning("$inst->{file}:$inst->{line}:".
2543
                                        "could not resolve port number $port to name)");
2544
                        }
2545
                    }
2546
                }
2547
            }
2548
        }
2549
    }
2550
 
2551
    # Go through all instances with parameter lists and try to resolve names parameter
2552
    #  
2553
    foreach $m (sort (keys %{$self->{modules}})) {
2554
        foreach $inst (@{$self->{modules}{$m}{instances}}) {
2555
            if ($inst->{parameters}) {
2556
                if ( exists( $self->{modules}{$inst->{module}}) ) {
2557
                    my $mp=$self->{modules}{$inst->{module}};
2558
                    foreach my $p (sort (keys %{$inst->{parameters}})){
2559
                        last if ( $p !~ m/^[0-9]+$/ );
2560
                        my $pn = $mp->{parameter_order}[$p];
2561
                        if ($pn) {
2562
                            $inst->{parameters}{$pn} =
2563
                                $inst->{parameters}{$p};
2564
                            delete($inst->{parameters}{$p});
2565
                            print "$inst->{parameters}{$pn}{file}:".
2566
                                "$inst->{parameters}{$pn}{line}: ".
2567
                                "Resolved $p to $pn = $inst->{parameters}{$pn}{value}\n"
2568
                                  if $debug;
2569
                        }
2570
                        else {
2571
                            $self->_add_warning("$inst->{parameters}{$p}{file}:".
2572
                                        "$inst->{parameters}{$p}{line} ".
2573
                                        "could not resolve parameter number $p to name");
2574
                        }
2575
                    }
2576
                }
2577
            }
2578
        }
2579
    }
2580
 
2581
    # Go through all the modules and each signal inside
2582
    #  looking at whether the signal is connected to any outputs
2583
    #   (set the a_line on the first one if it is not already set)
2584
    #  Also, when you see a signal connected to an input (and that
2585
    #   submod is only instantiated once) reach down into the submod
2586
    #   and set the i_line of that signal, so that clicking on the
2587
    #   input can pop you up to the line that input is driven in
2588
    #   one of the instantiations
2589
    foreach $m (sort (keys %{$self->{modules}})) {
2590
        print " Finding port connections in $m\n" if $debug;
2591
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
2592
            print "   checking signal $sig\n" if $debug;
2593
            $sigp = $self->{modules}{$m}{signals}{$sig};
2594
 
2595
            foreach $port_con (@{$sigp->{port_con}}) {
2596
                if ( exists( $self->{modules}{$port_con->{module}}) ) {
2597
                    print "    connection to $port_con->{module}\n" if $debug;
2598
                    $m2 = $self->{modules}{$port_con->{module}};
2599
                    if (exists( $m2->{signals}{$port_con->{port}})) {
2600
                        push(@{$m2->{signals}{$port_con->{port}}{con_to}},
2601
                             { signal => $sig , module => $m , inst => $port_con->{inst}});
2602
                        if ( ($m2->{signals}{$port_con->{port}}{type} eq
2603
                              'output') &&
2604
                            ($sigp->{a_line} == -1)) {
2605
                            $sigp->{driven_by_port}=1;
2606
                            $sigp->{a_line} = $port_con->{line};
2607
                            $sigp->{a_file} = $port_con->{file};
2608
                            _add_anchor($self->{files}{$port_con->{file}}{anchors},
2609
                                       $port_con->{line},'');
2610
                        }
2611
                        elsif ($m2->{signals}{$port_con->{port}}{type} eq
2612
                               'input') {
2613
                            $m2->{signals}{$port_con->{port}}{driven_by_port}=1;
2614
                            if (scalar(@{$m2->{inst_by}}) &&
2615
                                ($m2->{signals}{$port_con->{port}}{i_line}==-1)) {
2616
                                $m2->{signals}{$port_con->{port}}{i_line}=
2617
                                  $port_con->{line};
2618
                                $m2->{signals}{$port_con->{port}}{i_file}=
2619
                                  $port_con->{file};
2620
                                _add_anchor($self->{files}{$port_con->{file}}{anchors},
2621
                                           $port_con->{line},'');
2622
                                print "    set i_line $port_con->{port} ".
2623
                                    "$port_con->{file}:$port_con->{line}\n" if $debug;
2624
                            }
2625
                        }
2626
                    }
2627
                }
2628
            }
2629
        }
2630
    }
2631
 
2632
    # find all signal sources
2633
    foreach $m (sort (keys %{$self->{modules}})) {
2634
        print " Finding signal sources in $m\n" if $debug;
2635
        foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
2636
            $sigp = $self->{modules}{$m}{signals}{$sig};
2637
            next if $sigp->{source}{checked};
2638
            print "   finding signal source for $sig of $m\n" if $debug;
2639
            $sigp->{source} = $self->_find_signal_source($sigp);
2640
        }
2641
    }
2642
 
2643
    # propagate the posedge, negedge stuff up the hierarchy
2644
    foreach $m (sort (keys %{$self->{modules}})) {
2645
        # only do the recursion for top level modules
2646
        if ( 0== @{$self->{modules}{$m}{inst_by}} ) {
2647
            $self->_prop_edges($m);
2648
        }
2649
    }
2650
 
2651
    # get included_by information
2652
    foreach $f ( sort (keys %{$self->{files}} )) {
2653
        foreach $i ($self->get_files_includes($f)) {
2654
            if (exists $self->{files}{$i}) {
2655
                push( @{$self->{files}{$i}{included_by}} , $f );
2656
            }
2657
        }
2658
    }
2659
}
2660
 
2661
sub _find_signal_source {
2662
    my ($self,$sigp) = @_;
2663
    my ($con_to,$port_con,$ret_val);
2664
 
2665
    if ($sigp->{source}{checked}) {
2666
        print "     source already found\n" if $debug;
2667
        $ret_val = $sigp->{source};
2668
    }
2669
    else {
2670
        $ret_val =  { checked => 1, file => '' , line => '' };
2671
        if (exists($sigp->{driven_by_port})) {
2672
            print "     drive by port\n" if $debug;
2673
            foreach $con_to (@{$sigp->{con_to}}) {
2674
#               if ($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{type} eq 'input') {
2675
                if ($sigp->{type} eq 'input') {
2676
                    print "       following input $con_to->{signal} $con_to->{module} $con_to->{inst}\n" if $debug;
2677
                    if (!exists($self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}}{i_line})) { die "Error: $con_to->{signal} does not exist $!"; }
2678
                    $ret_val = $self->_find_signal_source(
2679
                                              $self->{modules}{$con_to->{module}}{signals}{$con_to->{signal}});
2680
                }
2681
            }
2682
            foreach $port_con (@{$sigp->{port_con}}) {
2683
                if (exists ($self->{modules}{$port_con->{module}})) {
2684
                    if (exists($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}})) {
2685
                        if ($self->{modules}{$port_con->{module}}{signals}{$port_con->{port}}{type} eq 'output') {
2686
                            print "       following output $port_con->{port} $port_con->{module} $port_con->{inst}\n" if $debug;
2687
                            $ret_val = $self->_find_signal_source(
2688
                                                          $self->{modules}{$port_con->{module}}{signals}{$port_con->{port}});
2689
                        }
2690
                    }
2691
                    else {
2692
                        $self->_add_warning("$port_con->{file}:$port_con->{line}:".
2693
                                    " Connection to nonexistent port ".
2694
                                    " $port_con->{port} of module $port_con->{module}");
2695
                    }
2696
                }
2697
            }
2698
        }
2699
        else {
2700
            if ($sigp->{a_line}==-1) {
2701
                if ($sigp->{type} eq 'input') {
2702
                    print "     signal is an input not driven at higher level\n" if $debug;
2703
                    $ret_val =  { checked => 1, file => $sigp->{file} , line => $sigp->{line} };
2704
                }
2705
                else {
2706
                    print "     signal has unknown source\n" if $debug;
2707
                }
2708
            }
2709
            else {
2710
                print "     signal is driven in this module\n" if $debug;
2711
                $ret_val =  { checked => 1 , file => $sigp->{a_file} , line => $sigp->{a_line} };
2712
            }
2713
        }
2714
    }
2715
 
2716
    $sigp->{source} = $ret_val;
2717
    return $ret_val;
2718
}
2719
 
2720
###############################################################################
2721
# Propagate posedge and negedge attributes of signals up the hierarchy
2722
#
2723
sub _prop_edges {
2724
    my ($self,$m) = @_;
2725
    my ($imod,@inst,$sig,$sigp,$port_con,$m2);
2726
 
2727
    print "Prop_edges $m\n" if $debug;
2728
 
2729
    for ( ($imod) = $self->get_first_instantiation($m) ;
2730
          $imod;
2731
          ($imod) = $self->get_next_instantiation()) {
2732
        push(@inst,$imod) if (exists( $self->{modules}{$imod}));
2733
    }
2734
    foreach $imod (@inst) { $self->_prop_edges($imod); }
2735
 
2736
    # Propagate all the edges up the hierarchy
2737
    foreach $sig (sort (keys %{$self->{modules}{$m}{signals}})) {
2738
        print "   checking signal $sig\n" if $debug;
2739
        $sigp = $self->{modules}{$m}{signals}{$sig};
2740
 
2741
        foreach $port_con (@{$sigp->{port_con}}) {
2742
            if ( exists( $self->{modules}{$port_con->{module}}) ) {
2743
                print "    connection to $port_con->{module}\n" if $debug;
2744
                $m2 = $self->{modules}{$port_con->{module}};
2745
                if (exists( $m2->{signals}{$port_con->{port}})) {
2746
                    print "Propagating posedge on $sig from $port_con->{module} to $m\n"
2747
                        if ($debug && (!$sigp->{posedge})  && $m2->{signals}{$port_con->{port}}{posedge});
2748
                    $sigp->{posedge} |= $m2->{signals}{$port_con->{port}}{posedge};
2749
                    $sigp->{negedge} |= $m2->{signals}{$port_con->{port}}{negedge};
2750
                }
2751
            }
2752
        }
2753
    }
2754
}
2755
 
2756
 
2757
###############################################################################
2758
# given a source file name work out the file without the path
2759
#
2760
sub _ffile {
2761
    my ($sfile) = @_;
2762
 
2763
    $sfile =~ s/^.*[\/\\]//;
2764
 
2765
    return $sfile;
2766
}
2767
 
2768
sub _add_warning {
2769
    my ($self,$p) = @_;
2770
 
2771
    print "Warning:$p\n" if $debug;
2772
    push (@{$self->{problems}},"Warning:$p");
2773
}
2774
sub _add_confused {
2775
    my ($self,$p) = @_;
2776
 
2777
    print "Confused:$p\n" if $debug;
2778
    push (@{$self->{problems}},"Confused:$p");
2779
}
2780
 
2781
###############################################################################
2782
# 
2783
BEGIN {
2784
$baseEval = {
2785
  START => {
2786
    MODULE => '$rs->{t}={ type=>$match, line=>$line };',
2787
  },
2788
  MODULE => {
2789
    SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
2790
    # if you add to this also edit {AFTER_INST}{COMMA}
2791
    INST => '$rs->{t}={ mod=>$match, line=>$line, name=>"" , port=>0 ,
2792
                        params=>{}, param_number=>0 , portName=>"" , vids=>[]};',
2793
  },
2794
  MODULE_NAME => {
2795
    NAME => 'my $nState="MODULE_PPL";
2796
             my $type = $rs->{t}{type};  $rs->{t}=undef;',
2797
  },
2798
  IN_CONCAT => {
2799
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line}) if (exists($rs->{t}{vids}));',
2800
  },
2801
  IN_BRACKET => {
2802
    VID => 'IN_CONCAT:VID',
2803
  },
2804
  SCALARED_OR_VECTORED => {
2805
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }'
2806
  },
2807
  SIGNAL_NAME => {
2808
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
2809
  },
2810
  SIGNAL_AFTER_EQUALS => {
2811
    END => '$rs->{t}=undef;',
2812
  },
2813
  INST_PARAM_BRACKET => {
2814
    NO_BRACKET => '$self->_add_warning("$file:$line: possible missing brackets after \# in instantiation");',
2815
  },
2816
  INST_NAME => {
2817
    VID => '$rs->{t}{name}=$match;',
2818
  },
2819
  INST_PORTS => {
2820
    COMMA => '$rs->{t}{port}++;',
2821
  },
2822
  INST_PORT_NAME => {
2823
    NAME => '$rs->{t}{portName}=$match;
2824
             $rs->{t}{vids} = [];', # throw away any instance parameters picked up
2825
  },
2826
  INST_NAMED_PORT_CON => {
2827
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
2828
  },
2829
  INST_NAMED_PORT_CON_AFTER => {
2830
    COMMA => 'if ($rs->{t}{portName} eq "") { $rs->{t}{portName}=$rs->{t}{port}++; }
2831
                 my @vids = @{$rs->{t}{vids}};
2832
                 my $portName = $rs->{t}{portName};
2833
                 $rs->{t}{portName}="";
2834
                 $rs->{t}{vids}=[];',
2835
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2836
  },
2837
  INST_NUMBERED_PORT => {
2838
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2839
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2840
    VID => 'push(@{$rs->{t}{vids}},{name=>$match,line=>$line});',
2841
  },
2842
  AFTER_INST => {
2843
    SEMICOLON => '$rs->{t}=undef;',
2844
    COMMA     => '$rs->{t}{line}=$line;
2845
                  $rs->{t}{name}="";
2846
                  $rs->{t}{port}=0;
2847
                  $rs->{t}{portName}="";
2848
                  $rs->{t}{vids}=[];',
2849
  },
2850
  SIGNAL_AFTER_NAME => {
2851
    SEMICOLON => '$rs->{t}=undef;',
2852
  },
2853
  IN_EVENT_BRACKET => {
2854
    EDGE => '$rs->{t}={ type=>$match };',
2855
  },
2856
  IN_EVENT_BRACKET_EDGE => {
2857
    VID => 'my $edgeType = $rs->{t}{type}; $rs->{t}=undef;',
2858
  },
2859
  STMNT => {
2860
    ASSIGN_OR_TASK => '$rs->{t}={ vids=>[{name=>$match,line=>$line}]};',
2861
    HIER_ASSIGN_OR_TASK => '$rs->{t}={ vids=>[]};',
2862
    CONCAT             => '$rs->{t}={ vids=>[]};',
2863
  },
2864
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
2865
    EQUALS    => 'my @vids = @{$rs->{t}{vids}}; $rs->{t}=undef;',
2866
# Revisit: this arc doesn't exist anymore - put this into smnt_semicolon
2867
#    SEMICOLON => '$rs->{t}=undef;', 
2868
    BRACKET   => '$rs->{t}=undef;',
2869
  },
2870
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
2871
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
2872
  },
2873
  IN_SIG_RANGE => {
2874
    END => '$rs->{t}{range}=$fromLastPos;',
2875
  },
2876
  IN_MEM_RANGE => {
2877
    END => 'push(@{$rs->{t}{dimensions}},$fromLastPos);',
2878
  },
2879
  ANSI_PORTS_TYPE => { # V2001 ansi ports
2880
    TYPE =>  '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
2881
  },
2882
  ANSI_PORTS_TYPE2 => { # V2001 ansi ports
2883
    TYPE => 'if ($match eq "reg") { $rs->{t}{type2} = "reg"; }',
2884
  },
2885
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
2886
    VID => '$rs->{t}{name}=$match; $rs->{t}{line}=$line;',
2887
  },
2888
};
2889
 
2890
############################################################
2891
# debugEval
2892
############################################################
2893
$debugEval = {
2894
  ANSI_PORTS_SIGNAL_NAME => {
2895
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
2896
  },
2897
  SIGNAL_NAME => {
2898
    VID => 'print "Found $rs->{t}{type} $rs->{t}{name} $rs->{t}{range} [$line]\n";',
2899
  },
2900
  INST_BRACKET => {
2901
    PORTS => 'print "found instance $rs->{t}{name} of $rs->{t}{mod} [$rs->{t}{line}]\n";',
2902
  },
2903
  INST_NAMED_PORT_CON_AFTER => {
2904
    COMMA => 'my @vidnames;
2905
            foreach my $vid (@vids) {push @vidnames,$vid->{name};}
2906
            print " Port $portName connected to ".join(",",@vidnames)."\n";',
2907
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2908
  },
2909
  INST_NUMBERED_PORT => {
2910
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2911
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
2912
  },
2913
};
2914
 
2915
 
2916
############################################################
2917
# rvpEval
2918
############################################################
2919
 
2920
$rvpEval = {
2921
  MODULE => {
2922
    ENDMODULE => 'if ((($rs->{p}{type} eq "primitive")&&($match ne "endprimitive"))||
2923
                         (($rs->{p}{type} ne "primitive")&&($match eq "endprimitive"))){
2924
                     $self->_add_warning("$file:$line: module of type".
2925
                                 " $rs->{p}{type} ended by $match");
2926
                  }
2927
                  $rs->{modules}{$rs->{module}}{end} = $line;
2928
                  $rs->{module}   = "";
2929
                  $rs->{files}{$file}{contexts}{$line}{value}= { name=>"",type=>"" };
2930
                  $rs->{p}= undef;',
2931
    PARAM => '$rs->{t} = { ptype => $match };', # parameter of localparam
2932
  },
2933
  MODULE_NAME => {
2934
    NAME => 'if (exists($rs->{modules}{$match})) {
2935
                 $nState = "IGNORE_MODULE";
2936
                 $rs->{modules}{$match}{duplicate} = 1;
2937
                 $self->_add_warning("$file:$line ignoring new definition of ".
2938
                          "module $match, previous was at ".
2939
                          "$rs->{modules}{$match}{file}:$rs->{modules}{$match}{line})");
2940
             }
2941
             else {
2942
               $rs->{module}=$match;
2943
               _init_module($rs->{modules},$rs->{module},$file,$line,$type);
2944
               $rs->{files}{$file}{modules}{$rs->{module}} = $rs->{modules}{$rs->{module}};
2945
               _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module});
2946
               $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};
2947
               $rs->{files}{$file}{contexts}{$line}{module_start}= $rs->{module};
2948
             }',
2949
  },
2950
  MODULE_PORTS => {
2951
    VID => 'push(@{$rs->{p}{port_order}},$match);',
2952
  },
2953
  FUNCTION => {
2954
    NAME => '$rs->{function}=$match;
2955
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"function",
2956
                      $rs->{function},$file,$line,$rs->{module}."_".$rs->{function});
2957
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}."_".$rs->{function});
2958
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}};',
2959
  },
2960
  TASK => {
2961
    NAME => '$rs->{task}=$match;
2962
                      $self->_init_t_and_f($rs->{modules}{$rs->{module}},"task",
2963
                                   $rs->{task},$file,$line,$rs->{module}. "_" .$rs->{task});
2964
                      _add_anchor($rs->{files}{$file}{anchors},$line,$rs->{module}. "_" . $rs->{task});
2965
                      $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}};',
2966
  },
2967
  ENDTASK => {
2968
    ENDTASK => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{task}}{end} = $line;
2969
                $rs->{task}="";
2970
                $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
2971
  },
2972
  T_SIGNAL => {
2973
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>0};',
2974
     ENDTASK => 'ENDTASK:ENDTASK',
2975
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
2976
  },
2977
  ENDFUNCTION => {
2978
      ENDFUNCTION => '$rs->{modules}{$rs->{module}}{t_and_f}{$rs->{function}}{end} = $line;
2979
                     $rs->{function}="";
2980
                     $rs->{files}{$file}{contexts}{$line}{value}= $rs->{p}= $rs->{modules}{$rs->{module}};',
2981
  },
2982
  F_SIGNAL => {
2983
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"",block=>0};',
2984
     ENDFUNCTION => 'ENDFUNCTION:ENDFUNCTION',
2985
     PARAM => 'MODULE:PARAM', # not realy needed yet because T/F parameters are ignored
2986
  },
2987
  BLOCK_SIGNAL => {
2988
     SIGNAL => '$rs->{t}={ type=>$match, range=>"", dimensions=>[], name=>"" , type2=>"" , block=>1};',
2989
  },
2990
  PARAM_NAME => {
2991
    NAME => 'if ( ($rs->{function} eq "") && ($rs->{task} eq "")) { # ignore parameters in tasks and functions
2992
              $rs->{t}= { file => $file, line => $line , value => "" ,
2993
                          ptype => $rs->{t}{ptype}}; # ptype is same as the last one
2994
              push(@{$rs->{p}{parameter_order}}, $match)
2995
                    unless ($rs->{t}{ptype} eq "localparam");
2996
              $rs->{p}{parameters}{$match}=$rs->{t};
2997
              _add_anchor($rs->{files}{$file}{anchors},$line,""); }',
2998
  },
2999
  PPL_PARAM => {
3000
     PARAM => '$rs->{t} = { ptype => "parameter" };', # this can't be a localparam
3001
  },
3002
  PPL_NAME => {
3003
     NAME => 'PARAM_NAME:NAME',
3004
  },
3005
  PARAM_AFTER_EQUALS => {
3006
    COMMA     => '$rs->{t}{value} = $fromLastPos;',
3007
    SEMICOLON => 'PARAM_AFTER_EQUALS:COMMA',
3008
  },
3009
  PPL_AFTER_EQUALS => {
3010
     COMMA   => 'PARAM_AFTER_EQUALS:COMMA',
3011
     END     => 'PARAM_AFTER_EQUALS:COMMA',
3012
  },
3013
  ASSIGN => {
3014
    VID => 'if ( exists($rs->{p}{signals}{$match}) &&
3015
                              ($rs->{p}{signals}{$match}{a_line} == -1)) {
3016
               $rs->{p}{signals}{$match}{a_line} = $line;
3017
               $rs->{p}{signals}{$match}{a_file} = $file;
3018
               _add_anchor($rs->{files}{$file}{anchors},$line,"");
3019
            }',
3020
  },
3021
  SIGNAL_NAME => { # note skip signals local to a block ({block}==1)
3022
    VID => 'if ($rs->{t}{block} != 1) {
3023
              $self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
3024
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions})
3025
               && _add_anchor($rs->{files}{$file}{anchors},$line,"");
3026
            }',
3027
  },
3028
  SIGNAL_AFTER_NAME => { # don't assign a_line for reg at definition, as this is 
3029
                         #   only the initial value
3030
    ASSIGN => 'if ($rs->{t}{block} != 1) {
3031
                if ( $rs->{p}{signals}{$rs->{t}{name}}{type} ne "reg" ) {
3032
                  $rs->{p}{signals}{$rs->{t}{name}}{a_line}=$rs->{t}{line};
3033
                  $rs->{p}{signals}{$rs->{t}{name}}{a_file}=$file;
3034
                  _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},"");
3035
                }
3036
               }',
3037
  },
3038
  INST_PARAM_VALUE => {
3039
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
3040
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
3041
    #   and the second uses $match to capture the parameter value
3042
    COMMA => 'my $inst_num= $#{$rs->{p}{instances}};
3043
              $rs->{t}{params}{$rs->{t}{param_number}} =
3044
                     { file => $file , line => $line , value => $fromLastPos };
3045
              $rs->{t}{param_number}++;',
3046
    END   => 'INST_PARAM_VALUE:COMMA',
3047
  },
3048
  INST_PARAM_BRACKET => {
3049
    # Note: the code is nearly the same in INST_PARAM_VALUE:COMMA,
3050
    #   and INST_PARAM_BRACKET:NO_BRACKET, but the first uses $fromLastPos
3051
    #   and the second uses $match to capture the parameter value
3052
    NO_BRACKET => 'my $inst_num= $#{$rs->{p}{instances}};
3053
              $rs->{t}{params}{$rs->{t}{param_number}} =
3054
                     { file => $file , line => $line , value => $match };
3055
              $rs->{t}{param_number}++;',
3056
  },
3057
  INST_BRACKET => {
3058
    PORTS => '$rs->{unres_mod}{$rs->{t}{mod}}=$rs->{t}{mod};
3059
              $rs->{files}{$file}{instance_lines}{$rs->{t}{line}} = $rs->{t}{mod};
3060
              push( @{$rs->{p}{instances}} , { module => $rs->{t}{mod} ,
3061
                                               inst_name => $rs->{t}{name} ,
3062
                                               file => $file,
3063
                                               line => $rs->{t}{line},
3064
                                               parameters => $rs->{t}{params},
3065
                                               connections => {} });
3066
              _add_anchor($rs->{files}{$file}{anchors},$rs->{t}{line},
3067
                         $rs->{module}."_".$rs->{t}{name});',
3068
  },
3069
  INST_NAMED_PORT_CON_AFTER => {
3070
    COMMA =>   'my $inst_num= $#{$rs->{p}{instances}};
3071
              $rs->{p}{instances}[$inst_num]{connections}{$portName}=$fromLastPos;
3072
              if ($portName =~ /^[0-9]/ ) { # clear named_ports flag if port is a number
3073
                 $rs->{p}{named_ports} = 0;
3074
              }
3075
              else { # remove the bracket from the end if a named port
3076
                 $rs->{p}{instances}[$inst_num]{connections}{$portName}=~s/\)\s*$//s;
3077
              }
3078
              foreach my $s (@vids) {
3079
                $self->_init_signal($rs->{p}{signals},$s->{name},"wire","","",$file,$s->{line},0,$rs->{t}{dimensions})
3080
                    && _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
3081
                 push( @{$rs->{p}{signals}{$s->{name}}{port_con}},
3082
                        { port   => $portName ,
3083
                          line   => $s->{line},
3084
                          file   => $file,
3085
                          module => $rs->{t}{mod} ,
3086
                          inst   => $rs->{t}{name} });
3087
              }',
3088
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
3089
  },
3090
  INST_NUMBERED_PORT => {
3091
    COMMA   => 'INST_NAMED_PORT_CON_AFTER:COMMA',
3092
    BRACKET => 'INST_NAMED_PORT_CON_AFTER:COMMA',
3093
  },
3094
  IN_EVENT_BRACKET_EDGE => {
3095
    VID => 'if (exists($rs->{p}{signals}{$match})) {
3096
               $rs->{p}{signals}{$match}{$edgeType}=1; };',
3097
  },
3098
 
3099
  STMNT_ASSIGN_OR_TASK => { # copy of STMNT_ASSIGN
3100
    EQUALS => 'foreach my $s (@vids) {
3101
                 my $sigp = undef;
3102
                 if ( exists($rs->{p}{signals}{$s->{name}} )) {
3103
                      $sigp = $rs->{p}{signals}{$s->{name}};
3104
                 }
3105
                 elsif ( exists($rs->{p}{m_signals}) &&
3106
                         exists($rs->{p}{m_signals}{$s->{name}}) ) {
3107
                      $sigp = $rs->{p}{m_signals}{$s->{name}};
3108
                 }
3109
                 if (defined($sigp) && ($sigp->{a_line}==-1)) {
3110
                      $sigp->{a_line}=$s->{line};
3111
                      $sigp->{a_file}=$file;
3112
                      _add_anchor($rs->{files}{$file}{anchors},$s->{line},"");
3113
                 }
3114
               }',
3115
  },
3116
  STMNT_ASSIGN => { # copy of STMNT_ASSIGN_OR_TASK
3117
    EQUALS => 'STMNT_ASSIGN_OR_TASK:EQUALS',
3118
  },
3119
  ANSI_PORTS_SIGNAL_NAME => { # V2001 ansi ports
3120
    VID => '$self->_init_signal($rs->{p}{signals},$match,$rs->{t}{type},$rs->{t}{type2},
3121
                        $rs->{t}{range},$file,$line,1,$rs->{t}{dimensions});
3122
            push(@{$rs->{p}{port_order}},$match) if exists $rs->{p}{port_order};
3123
            _add_anchor($rs->{files}{$file}{anchors},$line,"");',
3124
  },
3125
};
3126
 
3127
############################################################
3128
# language definition
3129
############################################################
3130
 
3131
$vid_vnum_or_string =
3132
[ { arcName=> 'HVID',   regexp=> '$HVID', nextState=> ['$ps->{curState}'] ,}, # hier id
3133
  { arcName=> 'VID',    regexp=> '$VID' , nextState=> ['$ps->{curState}'] ,},
3134
  { arcName=> 'NUMBER', regexp=> '$VNUM', nextState=> ['$ps->{curState}'] ,},
3135
  { arcName=> 'STRING', regexp=> '\\"',   nextState=> ['IN_STRING','$ps->{curState}'],},
3136
];
3137
 
3138
$languageDef =
3139
[
3140
 {
3141
 stateName =>     'START',
3142
 confusedNextState => 'START',
3143
 search =>
3144
  [
3145
   { arcName   => 'MODULE' ,        regexp => '\b(?:module|macromodule|primitive)\b',
3146
     nextState => ['MODULE_NAME'] ,},
3147
   { arcName   => 'CONFIG',        regexp => '\bconfig\b', # V2001
3148
     nextState => ['CONFIG'] , },
3149
   { arcName   => 'LIBRARY',        regexp => '\blibrary\b', # V2001
3150
     nextState => ['LIBRARY'] , },
3151
  ],
3152
 },
3153
 {
3154
 stateName =>     'MODULE',
3155
 confusedNextState => 'MODULE',
3156
 search =>
3157
  [
3158
   { arcName   => 'ENDMODULE' ,     regexp => '\b(?:end(?:module|primitive))\b',
3159
     nextState => ['START'] ,  },
3160
   { arcName   => 'FUNCTION',       regexp => '\bfunction\b',
3161
     nextState => ['FUNCTION'] , },
3162
   { arcName   => 'TASK',           regexp => '\btask\b',
3163
     nextState => ['TASK'] ,  },
3164
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
3165
     nextState => ['PARAM_TYPE','MODULE'] ,  },
3166
   { arcName   => 'SPECIFY',        regexp => '\bspecify\b',
3167
     nextState => ['SPECIFY'] , },
3168
   { arcName   => 'TABLE',          regexp => '\btable\b',
3169
     nextState => ['TABLE'] ,  },
3170
   { arcName   => 'EVENT_DECLARATION' ,    regexp => '\bevent\b' ,
3171
     nextState => ['EVENT_DECLARATION'] ,  },
3172
   { arcName   => 'DEFPARAM' ,       regexp => '\bdefparam\b' ,
3173
     nextState => ['DEFPARAM'] , },
3174
   { arcName   => 'GATE' ,           regexp => "$verilog_gatetype_regexp" ,
3175
     nextState => ['GATE'] ,   },
3176
   { arcName   => 'ASSIGN' ,         regexp => '\bassign\b' ,
3177
     nextState => ['ASSIGN'] , },
3178
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
3179
     nextState => ['DRIVE_STRENGTH','MODULE'] , },
3180
   { arcName   => 'INITIAL_OR_ALWAYS', regexp => '\b(?:initial|always)\b' ,
3181
     nextState => ['STMNT','MODULE'] , },
3182
   { arcName   => 'GENERATE',       regexp => '\bgenerate\b', # V2001
3183
     nextState => ['GENERATE'] , },
3184
 
3185
 
3186
   { arcName   => 'INST',          regexp    => '$VID' ,
3187
     nextState => ['INST_PARAM'] , },
3188
   # don't put any more states here because $VID matches almost anything
3189
   ],
3190
 },################ END OF MODULE STATE
3191
 {
3192
 stateName =>     'MODULE_NAME',
3193
 search =>   # $nState is usually MODULE_PPL, but is set to
3194
             #   IGNORE_MODULE when a duplicate module is found
3195
  [ { arcName   => 'NAME',  regexp => '$VID' , nextState => ['$nState'] , }, ],
3196
 },
3197
 {
3198
 stateName =>     'IGNORE_MODULE' ,  # just look for endmodule
3199
 allowAnything => 1,
3200
 search => [
3201
   { arcName   => 'ENDMODULE' , regexp    => '\bendmodule\b',
3202
     nextState => ['START'], },
3203
   @$vid_vnum_or_string,
3204
  ],
3205
 },
3206
 {
3207
 stateName =>     'MODULE_PPL' ,  # v2001 module_parameter_port_list (A.1.3)
3208
 failNextState => ['MODULE_PORTS'],
3209
 search => [ { regexp    => '#',  nextState => ['PPL_BRACKET'], }, ],
3210
 },
3211
 {
3212
 stateName =>     'MODULE_PORTS' ,  # just look for signals until ;
3213
 allowAnything => 1,
3214
 search => [
3215
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',  # V2001 ansi ports
3216
     nextState => ['ANSI_PORTS_TYPE','MODULE'], resetPos => 1, },
3217
   { arcName   => 'END', regexp    => ';' , nextState => ['MODULE'] , },
3218
   @$vid_vnum_or_string,
3219
  ],
3220
 },
3221
 {
3222
 stateName =>     'FUNCTION' ,
3223
 search => [
3224
    { arcName => 'RANGE', regexp => '\[', nextState => ['IN_RANGE','FUNCTION'] , },
3225
    { arcName => 'TYPE',  regexp => '\b(?:real|integer|time|realtime)\b',
3226
      nextState => ['FUNCTION'] ,  },
3227
    { arcName => 'SIGNED', regexp => '\bsigned\b' ,nextState => ['FUNCTION'] ,  }, # V2001
3228
    { arcName => 'AUTO',   regexp => '\bautomatic\b' ,nextState => ['FUNCTION'] ,  }, # V2001
3229
    { arcName => 'NAME',  regexp => '$VID' , nextState => ['FUNCTION_AFTER_NAME'] ,
3230
    },
3231
   ],
3232
 },
3233
 {
3234
 stateName =>     'FUNCTION_AFTER_NAME' ,
3235
 search => [
3236
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['F_SIGNAL'] , },
3237
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
3238
      nextState => ['ANSI_PORTS_TYPE','F_SIGNAL'] ,  },
3239
  ],
3240
 },
3241
 {
3242
 stateName =>     'TASK' ,
3243
 search => [
3244
   { arcName => 'AUTO', regexp => '\bautomatic\b', nextState => ['TASK'],}, # V2001
3245
   { arcName => 'NAME', regexp => '$VID', nextState => ['TASK_AFTER_NAME'],},],
3246
 },
3247
 {
3248
 stateName =>     'TASK_AFTER_NAME' ,
3249
 search => [
3250
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['T_SIGNAL'] , },
3251
    { arcName => 'BRACKET',  regexp => '\(' ,   # V2001
3252
      nextState => ['ANSI_PORTS_TYPE','T_SIGNAL'] ,  },
3253
  ],
3254
 },
3255
 {
3256
 stateName =>     'T_SIGNAL' ,
3257
 failNextState => ['STMNT','ENDTASK'],
3258
 search => [
3259
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
3260
     nextState => ['MODULE'] , },
3261
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
3262
     nextState => ['DRIVE_STRENGTH','T_SIGNAL'] , },
3263
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
3264
     nextState => ['PARAM_TYPE','T_SIGNAL'] ,  },
3265
   ],
3266
 },
3267
 {
3268
 stateName =>     'ENDTASK',
3269
 search => [
3270
   { arcName   => 'ENDTASK',        regexp => '\bendtask\b',
3271
     nextState => ['MODULE'] , },
3272
   ],
3273
 },
3274
 {
3275
 stateName =>     'F_SIGNAL' ,
3276
 failNextState => ['STMNT','ENDFUNCTION'],
3277
 search => [
3278
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
3279
     nextState => ['MODULE'] , },
3280
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
3281
     nextState => ['DRIVE_STRENGTH','F_SIGNAL'] , },
3282
   { arcName   => 'PARAM',      regexp => '\b(?:parameter|localparam)\b', # v2001: localparm
3283
     nextState => ['PARAM_TYPE','F_SIGNAL'] ,  },
3284
   ],
3285
 },
3286
 {
3287
 stateName =>     'ENDFUNCTION',
3288
 search => [
3289
   { arcName   => 'ENDFUNCTION',     regexp => '\bendfunction\b',
3290
     nextState => ['MODULE'] , },
3291
   ],
3292
 },
3293
 {
3294
 stateName =>     'PARAM_TYPE',
3295
 failNextState => ['PARAM_NAME'],
3296
 search => [
3297
    { arcName   => 'RANGE', regexp    => '\[' ,
3298
      nextState => ['IN_RANGE','PARAM_NAME'] , },
3299
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
3300
      nextState => ['PARAM_TYPE'] , },  # may be followed by a range
3301
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
3302
      nextState => ['PARAM_NAME'] , },
3303
   ],
3304
 },
3305
 {
3306
 stateName =>     'PARAM_NAME',
3307
 search => [
3308
    { arcName   => 'NAME',  regexp    => '$VID' ,
3309
      nextState => ['PARAMETER_EQUAL','PARAM_AFTER_EQUALS'] , },
3310
   ],
3311
 },
3312
 {
3313
 stateName =>     'PARAMETER_EQUAL',
3314
  search => [ { regexp    => '=' , storePos => 1, }, ]
3315
 },
3316
 {
3317
 stateName =>     'PARAM_AFTER_EQUALS',
3318
 allowAnything => 1,
3319
 search =>
3320
  [
3321
   { arcName   => 'CONCAT',      regexp    => '{' ,
3322
     nextState => ['IN_CONCAT','PARAM_AFTER_EQUALS'] ,  },
3323
   { arcName   => 'COMMA',       regexp    => ',' ,
3324
     nextState => ['PARAM_NAME'] ,    },
3325
   { arcName   => 'SEMICOLON',   regexp    => ';' , },
3326
   @$vid_vnum_or_string,
3327
  ]
3328
 },
3329
 {
3330
 stateName =>     'IN_CONCAT',
3331
 allowAnything => 1,
3332
 search =>
3333
  [
3334
   { arcName   => 'CONCAT' ,   regexp    => '{' ,
3335
     nextState => ['IN_CONCAT','IN_CONCAT'] ,     },
3336
   { arcName   => 'END' ,      regexp    => '}' , }, # pop up
3337
   @$vid_vnum_or_string,
3338
  ]
3339
 },
3340
 {
3341
 stateName =>     'IN_RANGE',
3342
 allowAnything => 1,
3343
 search =>
3344
  [
3345
   { arcName   => 'RANGE' , regexp    => '\[' ,
3346
     nextState => ['IN_RANGE','IN_RANGE'] , },
3347
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
3348
   @$vid_vnum_or_string,
3349
  ]
3350
 },
3351
 {
3352
 stateName =>     'IN_SIG_RANGE', # just like in range, but stores
3353
 allowAnything => 1,
3354
 search =>
3355
  [
3356
   { arcName   => 'RANGE' , regexp    => '\[' ,
3357
     nextState => ['IN_SIG_RANGE','IN_SIG_RANGE'] , },
3358
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
3359
   @$vid_vnum_or_string,
3360
  ]
3361
 },
3362
 {
3363
 stateName =>     'IN_MEM_RANGE', # just like in range, but stores
3364
 allowAnything => 1,
3365
 search =>
3366
  [
3367
   { arcName   => 'RANGE' , regexp    => '\[' ,
3368
     nextState => ['IN_MEM_RANGE','IN_MEM_RANGE'] , },
3369
   { arcName   => 'END' ,   regexp    => '\]' , }, # pop up
3370
   @$vid_vnum_or_string,
3371
  ]
3372
 },
3373
 {
3374
 stateName =>     'IN_BRACKET',
3375
 allowAnything => 1,
3376
 search =>
3377
  [
3378
   { arcName   => 'BRACKET' ,  regexp    => '\(' ,
3379
     nextState => ['IN_BRACKET','IN_BRACKET'] ,   },
3380
   { arcName   => 'END' ,      regexp    => '\)' ,  }, # pop up
3381
   @$vid_vnum_or_string,
3382
  ]
3383
 },
3384
 {
3385
 stateName =>     'IN_STRING',
3386
 allowAnything => 1,
3387
 search =>
3388
  [ # note: put \" in regexp so that emacs colouring doesn't get confused
3389
   { arcName   => 'ESCAPED_QUOTE' ,  regexp => '\\\\\\"' , # match \"
3390
     nextState => ['IN_STRING'] , },
3391
   # match \\ (to make sure that \\" does not match \"
3392
   { arcName   => 'ESCAPE' ,         regexp => '\\\\\\\\' ,
3393
     nextState => ['IN_STRING'] , },
3394
   { arcName   => 'END' ,            regexp => '\\"' , }, # match " and pop up
3395
  ]
3396
 },
3397
 {
3398
 stateName =>     'SPECIFY',
3399
 allowAnything => 1,
3400
 search => [ { regexp => '\bendspecify\b' , nextState => ['MODULE'] ,},
3401
               @$vid_vnum_or_string,],
3402
 },
3403
 {
3404
 stateName =>     'TABLE',
3405
 allowAnything => 1,
3406
 search => [ { regexp => '\bendtable\b'   , nextState => ['MODULE'] ,},
3407
             @$vid_vnum_or_string,],
3408
 },
3409
 {
3410
 stateName =>     'EVENT_DECLARATION' ,  # just look for ;
3411
 allowAnything => 1,
3412
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
3413
             @$vid_vnum_or_string,],
3414
 },
3415
 {
3416
 stateName =>     'DEFPARAM' ,  # just look for ;
3417
 allowAnything => 1,
3418
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
3419
             @$vid_vnum_or_string,],
3420
 },
3421
 {
3422
  # REVISIT: could find signal driven by gate here (is output always the first one??)
3423
 stateName =>     'GATE' ,
3424
 allowAnything => 1,
3425
 search => [ {  regexp    => ';' ,    nextState => ['MODULE'] , },
3426
             @$vid_vnum_or_string,],
3427
 },
3428
 {
3429
 stateName =>     'ASSIGN',
3430
 allowAnything => 1,
3431
 search =>
3432
  [
3433
   { arcName   => 'RANGE' ,   regexp    => '\[' ,
3434
     nextState => ['IN_RANGE','ASSIGN'] ,      },
3435
   { arcName   => 'EQUALS' ,  regexp    => '=' ,
3436
     nextState => ['ASSIGN_AFTER_EQUALS'] ,    },
3437
   @$vid_vnum_or_string,
3438
  ]
3439
 },
3440
 {
3441
 stateName =>     'ASSIGN_AFTER_EQUALS' ,
3442
 allowAnything => 1,
3443
  search =>
3444
   [
3445
    { arcName=>'COMMA',     regexp => ',',
3446
      nextState => ['ASSIGN'],},
3447
    { arcName=>'CONCAT',    regexp => '{',
3448
      nextState => ['IN_CONCAT','ASSIGN_AFTER_EQUALS'],},
3449
    # don't get confused by function calls (which can also contain commas)
3450
    {   arcName=>'BRACKET',   regexp => '\(',
3451
        nextState => ['IN_BRACKET','ASSIGN_AFTER_EQUALS'],},
3452
    {   arcName=>'END',       regexp => ';',
3453
        nextState => ['MODULE'],},
3454
    @$vid_vnum_or_string,
3455
   ],
3456
 },
3457
 {
3458
 stateName =>     'DRIVE_STRENGTH',  # signal defs - drive strength or charge strength
3459
 failNextState => ['SCALARED_OR_VECTORED'],
3460
 search => [ { regexp => '\(', nextState => ['IN_BRACKET','SCALARED_OR_VECTORED'],}],
3461
 },
3462
 { # REVISIT: V2001 - the name of this is misleading now
3463
 stateName =>     'SCALARED_OR_VECTORED',  # for signal defs
3464
 failNextState => ['SIGNAL_RANGE'],
3465
 search => [ { regexp => '\b(?:scalared|vectored)\b', nextState => ['SIGNAL_RANGE'],},
3466
             { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp", # V2001
3467
               nextState => ['SCALARED_OR_VECTORED'],},
3468
             { regexp => '\b(?:signed)\b', nextState => ['SCALARED_OR_VECTORED'],},], # V2001
3469
 },
3470
 {
3471
 stateName =>     'SIGNAL_RANGE',          # for signal defs
3472
  failNextState => ['SIGNAL_DELAY'],
3473
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','SIGNAL_DELAY'],
3474
               storePos => 1,}, ],
3475
 },
3476
 {
3477
 stateName =>     'SIGNAL_DELAY',          # for signal defs
3478
 failNextState => ['SIGNAL_NAME'],
3479
 search => [ { regexp => '\#', nextState => ['DELAY_VALUE','SIGNAL_NAME'],},  ],
3480
 },
3481
 {
3482
 stateName =>     'SIGNAL_NAME',           # for signal defs
3483
  search => [ { arcName   => 'VID' , regexp    => '$VID',
3484
               nextState => ['SIGNAL_AFTER_NAME'], }, ],
3485
 },
3486
 { # for signal defs
3487
 stateName =>     'SIGNAL_AFTER_NAME',
3488
 search =>
3489
  [
3490
   { regexp => ',',  nextState => ['SIGNAL_NAME'],},
3491
   { regexp => '\[', nextState => ['IN_MEM_RANGE','SIGNAL_AFTER_NAME'],
3492
     storePos => 1 , }, # memories
3493
   { arcName => 'SEMICOLON' , regexp => ';',},  # pop up
3494
   { arcName => 'ASSIGN',     regexp => '=', nextState => ['SIGNAL_AFTER_EQUALS'],}
3495
  ],
3496
 },
3497
 {
3498
 stateName =>     'SIGNAL_AFTER_EQUALS' ,
3499
 allowAnything => 1,
3500
 search =>
3501
   [
3502
    { regexp => ',',    nextState => ['SIGNAL_NAME'],},
3503
    { regexp => '{',    nextState => ['IN_CONCAT','SIGNAL_AFTER_EQUALS'],},
3504
    { regexp => '\(',   nextState => ['IN_BRACKET','SIGNAL_AFTER_EQUALS'],},
3505
    { arcName => 'END', regexp => ';', }, # pop up
3506
    @$vid_vnum_or_string,
3507
   ],
3508
 },
3509
 {
3510
 stateName =>     'INST_PARAM',
3511
 failNextState => ['INST_NAME'],
3512
 search => [ { regexp => '\#', nextState=> ['INST_PARAM_BRACKET'],},],
3513
 },
3514
 {
3515
 stateName =>     'INST_PARAM_BRACKET',
3516
 search => [ { arcName => 'BRACKET' ,
3517
               regexp => '\(',
3518
               storePos => 1,
3519
               nextState=> ['INST_PARAM_VALUE'],},
3520
             # this is here to catch and illegal case which DC accepts
3521
             { arcName => 'NO_BRACKET' ,
3522
               regexp => '($VID|$VNUM)',
3523
               nextState=> ['INST_NAME'],}, ],
3524
 },
3525
 {
3526
 stateName =>     'INST_PARAM_VALUE',
3527
 allowAnything => 1,
3528
 search => [
3529
   { regexp => '\(', nextState=> ['IN_BRACKET','INST_PARAM_VALUE'],},
3530
   { regexp => '\[', nextState => ['IN_RANGE','INST_PARAM_VALUE'],},
3531
   { regexp => '\{', nextState => ['IN_CONCAT','INST_PARAM_VALUE'],},
3532
   { arcName => 'COMMA' ,
3533
     regexp => ',',
3534
     storePos => 1,
3535
     nextState=> ['INST_PARAM_VALUE'],},
3536
   { arcName => 'END' ,
3537
     regexp => '\)',
3538
     nextState=> ['INST_NAME'],},
3539
  ],
3540
 },
3541
 {
3542
 stateName =>     'INST_NAME',
3543
 failNextState => ['INST_BRACKET'],
3544
 search =>
3545
  [
3546
   { arcName   => 'VID' ,       regexp => '$VID',
3547
     nextState => ['INST_RANGE'],      },
3548
  ],
3549
 },
3550
 {
3551
 stateName =>     'INST_NO_NAME' ,
3552
 allowAnything => 1,
3553
 search => [ { regexp => ';' , }, @$vid_vnum_or_string,],
3554
 },
3555
 {
3556
 stateName =>     'INST_RANGE',
3557
 failNextState => ['INST_BRACKET'],
3558
 search => [ { regexp => '\[', nextState => ['IN_RANGE','INST_BRACKET'],}, ],
3559
 },
3560
 {
3561
 stateName =>     'INST_BRACKET',
3562
 search => [ { arcName => 'PORTS' , regexp => '\(', nextState => ['INST_PORTS'],},],
3563
 },
3564
 {
3565
 stateName =>     'INST_PORTS',
3566
 failNextState => ['INST_NUMBERED_PORT'],
3567
 failStorePos => 1,
3568
 search =>
3569
  [
3570
   { arcName => 'COMMA', regexp => ',',   nextState => ['INST_PORTS'], },
3571
   { regexp => '\.',  nextState => ['INST_PORT_NAME'],  },
3572
   { regexp => '\)',  nextState => ['AFTER_INST'], },
3573
  ],
3574
 },
3575
 {
3576
 stateName =>     'INST_PORT_NAME',
3577
 search => [ { arcName   => 'NAME' , regexp => '$VID',
3578
               nextState => ['INST_NAMED_PORT_BRACKET','INST_NAMED_PORT_CON',
3579
                             'INST_NAMED_PORT_CON_AFTER'], }, ],
3580
 },
3581
 {
3582
   stateName => 'INST_NAMED_PORT_BRACKET',
3583
   search => [ { regexp => '\(' , storePos => 1, },]
3584
 },
3585
 {
3586
 stateName =>     'INST_NAMED_PORT_CON',
3587
 allowAnything => 1,
3588
 search =>
3589
  [
3590
   { regexp => '\[' , nextState => ['IN_RANGE','INST_NAMED_PORT_CON'] , },
3591
   { regexp => '\{' , nextState => ['IN_CONCAT','INST_NAMED_PORT_CON'] , },
3592
   { regexp => '\(' ,
3593
     nextState => ['INST_NAMED_PORT_CON','INST_NAMED_PORT_CON'], },
3594
   { arcName => 'END', regexp    => '\)' , },   # pop up 
3595
   @$vid_vnum_or_string,
3596
  ]
3597
 },
3598
 {
3599
 stateName =>     'INST_NAMED_PORT_CON_AFTER',
3600
 search =>
3601
  [
3602
   { arcName => 'BRACKET', regexp => '\)' ,
3603
     nextState => ['AFTER_INST']},
3604
   { arcName => 'COMMA' ,  regexp => ',' ,
3605
     nextState => ['INST_DOT']},
3606
  ]
3607
 },
3608
 { stateName => 'INST_DOT',
3609
   search =>
3610
    [
3611
     { regexp => '\.' , nextState => ['INST_PORT_NAME']},
3612
     { regexp => ','  , nextState => ['INST_DOT']},   # blank port
3613
    ]
3614
 },
3615
 {
3616
 stateName =>     'INST_NUMBERED_PORT',
3617
 allowAnything => 1,
3618
 search =>
3619
  [
3620
   { regexp => '\[', nextState => ['IN_RANGE','INST_NUMBERED_PORT'],},
3621
   { regexp => '\{', nextState => ['IN_CONCAT','INST_NUMBERED_PORT'],},
3622
   { regexp => '\(', nextState => ['IN_BRACKET','INST_NUMBERED_PORT'],},
3623
   { arcName => 'BRACKET' , regexp => '\)', nextState => ['AFTER_INST'], },
3624
   { arcName => 'COMMA' ,   regexp => ',' , nextState => ['INST_NUMBERED_PORT'],
3625
     storePos => 1, },
3626
     @$vid_vnum_or_string,
3627
  ]
3628
 },
3629
 { stateName => 'AFTER_INST',
3630
   search => [
3631
    { arcName => 'SEMICOLON', regexp => ';', nextState => ['MODULE'], },
3632
    { arcName => 'COMMA',     regexp => ',', nextState => ['INST_NAME'], },
3633
   ]
3634
 },
3635
 {
3636
 stateName =>     'STMNT',
3637
 search =>
3638
  [
3639
   { arcName   => 'IF',                     regexp => '\bif\b' ,
3640
     nextState => ['BRACKET','IN_BRACKET','STMNT','MAYBE_ELSE'] ,},
3641
   { arcName   => 'REPEAT_WHILE_FOR_WAIT',  regexp => '\b(?:repeat|while|for|wait)\b' ,
3642
     nextState => ['BRACKET','IN_BRACKET','STMNT'] ,  },
3643
   { arcName   => 'FOREVER',                regexp => '\bforever\b' ,
3644
     nextState => ['STMNT'] , },
3645
   { arcName   => 'CASE',                   regexp => '\bcase[xz]?\b' ,
3646
     nextState => ['BRACKET','IN_BRACKET','CASE_ITEM'] , },
3647
   { arcName   => 'BEGIN',                  regexp => '\bbegin\b' ,
3648
     nextState => ['BLOCK_NAME','IN_SEQ_BLOCK'] , },
3649
   { arcName   => 'FORK',                   regexp => '\bfork\b' ,
3650
     nextState => ['BLOCK_NAME','IN_PAR_BLOCK'] , },
3651
   { arcName   => 'DELAY',                  regexp => '\#' ,
3652
     nextState => ['DELAY_VALUE','STMNT'] , },
3653
   { arcName   => 'EVENT_CONTROL',          regexp => '\@' ,
3654
     nextState => ['EVENT_CONTROL'] , },
3655
   { arcName   => 'SYSTEM_TASK',            regexp    => '\$$VID' ,
3656
     nextState => ['SYSTEM_TASK'] , },
3657
   { arcName   => 'DISABLE_ASSIGN_DEASSIGN_FORCE_RELEASE',
3658
     regexp    => '\b(?:disable|assign|deassign|force|release)\b',
3659
     nextState => ['STMNT_JUNK_TO_SEMICOLON'] , }, # just throw stuff away
3660
   # a assignment to a hierarchical thing mustn't collect the vid
3661
   #  like a normal assign as hierarchical nets/signals will confuse downstream code
3662
   { arcName   => 'HIER_ASSIGN_OR_TASK',           regexp => '$HVID' ,
3663
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
3664
   { arcName   => 'ASSIGN_OR_TASK',        regexp => '$VID' ,
3665
     nextState => ['STMNT_ASSIGN_OR_TASK'] , },
3666
   { arcName   => 'CONCAT',                regexp => '{' ,
3667
     nextState => ['IN_CONCAT','STMNT_ASSIGN'] ,  },
3668
   { arcName   => 'NULL',                  regexp => ';' ,
3669
     }, # pop up
3670
   { arcName   => 'POINTY_THING',          regexp    => '->' , # not sure what this is!
3671
     nextState => ['POINTY_THING_NAME'] ,  },
3672
  ],
3673
 },
3674
 {
3675
 stateName =>     'MAYBE_ELSE',
3676
 failNextState => [] , # don't get confused, just pop the stack for the next state
3677
 search => [{ arcName => 'ELSE', regexp => '\belse\b' , nextState => ['STMNT'],},]
3678
 },
3679
 {
3680
 stateName =>     'BLOCK_NAME',
3681
 failNextState => [] , # don't get confused, just pop the stack for the next state
3682
 search => [{ arcName => 'COLON', regexp    => ':' ,
3683
              nextState => ['BLOCK_NAME_AFTER_COLON'] ,},]
3684
 },
3685
 {
3686
 stateName =>     'BLOCK_NAME_AFTER_COLON',
3687
 search => [ { arcName   => 'VID', regexp => '$VID' , nextState => ['BLOCK_SIGNAL'],}, ]
3688
 },
3689
 {
3690
 stateName =>     'BLOCK_SIGNAL' ,
3691
 failNextState => [], # don't get confused, just pop the stack for the next state
3692
 search => [
3693
   { arcName   => 'SIGNAL' ,         regexp => "$verilog_sigs_regexp" ,
3694
     nextState => ['DRIVE_STRENGTH','BLOCK_SIGNAL'] , },
3695
   ],
3696
 },
3697
 
3698
 
3699
 {
3700
 stateName =>     'IN_SEQ_BLOCK',
3701
 failNextState => ['STMNT','IN_SEQ_BLOCK'] ,
3702
 search => [{ arcName   => 'END', regexp    => '\bend\b' , }, ]
3703
 },
3704
 {
3705
 stateName =>     'IN_PAR_BLOCK',
3706
 failNextState => ['STMNT','IN_PAR_BLOCK'] ,
3707
 search => [{ arcName   => 'JOIN', regexp => '\bjoin\b' , }, ]
3708
 },
3709
 {
3710
 stateName =>     'DELAY_VALUE',
3711
 search =>
3712
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON1'] },
3713
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON1'], },
3714
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON1'],},]
3715
 },
3716
 {
3717
 stateName =>     'DELAY_COLON1',
3718
 failNextState => [] , # popup
3719
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE2'] },]
3720
 },
3721
 {
3722
 stateName =>     'DELAY_VALUE2',
3723
 search =>
3724
  [{ arcName => 'NUMBER',  regexp => '$VNUM', nextState => ['DELAY_COLON2'] },
3725
   { arcName => 'ID',      regexp => '$VID',  nextState => ['DELAY_COLON2'], },
3726
   { arcName => 'BRACKET', regexp => '\(',    nextState => ['IN_BRACKET','DELAY_COLON2'],},]
3727
 },
3728
 {
3729
 stateName =>     'DELAY_COLON2',
3730
 search => [{ arcName   => 'COLON', regexp => ':' , nextState => ['DELAY_VALUE3'] },]
3731
 },
3732
 {
3733
 stateName =>     'DELAY_VALUE3',
3734
 search =>
3735
  [{ arcName => 'NUMBER',  regexp => '$VNUM', },
3736
   { arcName => 'ID',      regexp => '$VID',  },
3737
   { arcName => 'BRACKET', regexp => '\(',  nextState => ['IN_BRACKET'],}, ]
3738
 },
3739
 {
3740
 stateName =>     'EVENT_CONTROL',
3741
 search =>
3742
  [
3743
   { arcName => 'ID',      regexp => '(?:$HVID|$VID)', nextState => ['STMNT'], },
3744
   { arcName => 'STAR',    regexp => '\*', nextState => ['STMNT'], }, # V2001
3745
   { arcName => 'BRACKET', regexp => '\(',
3746
     nextState => ['IN_EVENT_BRACKET','STMNT'], },
3747
  ]
3748
 },
3749
 {
3750
 stateName =>     'IN_EVENT_BRACKET',
3751
 allowAnything => 1,
3752
 search =>
3753
  [
3754
   # must go before vid_vnum_or_string as posedge and negedge look like VIDs
3755
   { arcName => 'EDGE' ,           regexp    => '\b(?:posedge|negedge)\b' ,
3756
     nextState => ['IN_EVENT_BRACKET_EDGE'] , },
3757
   { arcName   => 'BRACKET' ,      regexp    => '\(' ,
3758
     nextState => ['IN_EVENT_BRACKET','IN_EVENT_BRACKET'] , },
3759
   { arcName => 'STAR',    regexp => '\*', nextState => ['IN_EVENT_BRACKET'], }, # V2001
3760
   { arcName   => 'END' ,          regexp    => '\)' , }, # popup
3761
   @$vid_vnum_or_string,
3762
  ]
3763
 },
3764
 { # in theory there could be an expression here, I just take the first VID
3765
 stateName =>     'IN_EVENT_BRACKET_EDGE',
3766
 failNextState => ['IN_EVENT_BRACKET'] ,
3767
 search => [{ arcName => 'VID', regexp => '$VID', nextState => ['IN_EVENT_BRACKET'],},],
3768
 },
3769
 {
3770
 stateName =>     'STMNT_ASSIGN_OR_TASK',
3771
 failNextState => ['STMNT_SEMICOLON'],
3772
 search =>
3773
  [
3774
   { arcName => 'EQUALS',          regexp => '[<]?=',
3775
     nextState => ['STMNT_JUNK_TO_SEMICOLON'], },
3776
   { arcName => 'RANGE',           regexp => '\[',
3777
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
3778
   { arcName => 'BRACKET',         regexp => '\(',     # task with params
3779
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'],  },
3780
  ]
3781
 },
3782
 {
3783
 stateName =>     'STMNT_ASSIGN',
3784
 search =>
3785
  [
3786
   { arcName => 'EQUALS', regexp => '[<]?=',
3787
     nextState => ['STMNT_JUNK_TO_SEMICOLON'],},
3788
   { arcName => 'RANGE',           regexp => '\[',
3789
     nextState => ['IN_RANGE','STMNT_ASSIGN'],},
3790
  ],
3791
 },
3792
 {
3793
 stateName =>     'SYSTEM_TASK',
3794
 failNextState => ['STMNT_SEMICOLON'],
3795
 search =>
3796
  [
3797
   { arcName => 'BRACKET',           regexp => '\(',
3798
     nextState => ['IN_BRACKET','STMNT_SEMICOLON'], },    ],
3799
 },
3800
 {
3801
 stateName =>     'POINTY_THING_NAME',
3802
 search => [{ arcName => 'VID', regexp => '(?:$HVID|$VID)', nextState => ['STMNT_SEMICOLON'], }, ],
3803
 },
3804
 {
3805
 stateName =>     'CASE_ITEM',
3806
 allowAnything => 1,
3807
 search =>
3808
  [
3809
   { arcName => 'END',             regexp => '\bendcase\b',  },
3810
   { arcName => 'COLON',           regexp => ':',
3811
     nextState => ['STMNT','CASE_ITEM'], },
3812
   { arcName => 'DEFAULT',         regexp => '\bdefault\b',
3813
     nextState => ['MAYBE_COLON','STMNT','CASE_ITEM'], },
3814
   # don't get confused by colons in ranges
3815
   { arcName => 'RANGE',           regexp => '\[',
3816
     nextState => ['IN_RANGE','CASE_ITEM'], },
3817
    @$vid_vnum_or_string,
3818
  ],
3819
 },
3820
 {
3821
 stateName =>     'MAYBE_COLON',
3822
 failNextState => [],
3823
 search => [ { regexp    => ':' , }, ]
3824
 },
3825
 { # look for ;  but also allow the ending of a statement with an end 
3826
   #   even though it is not really legal (verilog seems to accept it, so I do too)
3827
 stateName =>     'STMNT_JUNK_TO_SEMICOLON' ,
3828
 allowAnything => 1,
3829
 search => [
3830
             { regexp => ';' , },
3831
             # popup and reset pos to  before the end/join cope with nosemicolon case
3832
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
3833
             @$vid_vnum_or_string,
3834
           ],
3835
 },
3836
 {
3837
 stateName => 'STMNT_SEMICOLON',
3838
 search => [ { regexp => ';'  , },
3839
             # popup and reset pos to  before the end/join cope with nosemicolon case
3840
             { regexp => '\b(?:end|join|endtask|endfunction)\b' , resetPos => 1, },
3841
           ],
3842
 },
3843
 { stateName => 'BRACKET',   search => [ { regexp => '\(' , },] },
3844
 { stateName => 'SEMICOLON', search => [ { regexp => ';'  , },] },
3845
 # V2001
3846
 {
3847
 stateName =>     'CONFIG',
3848
 allowAnything => 1,
3849
 search => [ { regexp => '\bendconfig\b' , nextState => ['START'] ,},
3850
               @$vid_vnum_or_string,],
3851
 },
3852
 {
3853
 stateName =>     'LIBRARY' ,  # just look for ;
3854
 allowAnything => 1,
3855
 search => [ {  regexp    => ';' ,    nextState => ['START'] , },
3856
             @$vid_vnum_or_string,],
3857
 },
3858
 {
3859
 stateName =>     'GENERATE',
3860
 allowAnything => 1,
3861
 search => [ { regexp => '\bendgenerate\b' , nextState => ['MODULE'] ,},
3862
               @$vid_vnum_or_string,],
3863
 },
3864
 
3865
 
3866
 
3867
 { # V2001 ansi module ports
3868
 stateName =>     'ANSI_PORTS_TYPE',
3869
 failNextState => ['ANSI_PORTS_TYPE2'],
3870
 search => [ { arcName => 'TYPE' , regexp => '\b(?:input|output|inout)\b',
3871
               nextState => ['ANSI_PORTS_TYPE2'],},
3872
             # a null list. note this is only possible for a task or function
3873
             #  (a null module port list can't look like an ansi port list)
3874
             #  but it is not legal acording to the BNF. I allow it any way.
3875
             { regexp => '\)', nextState => ['SEMICOLON'], },
3876
             ],
3877
 },
3878
 { # V2001 ansi module ports
3879
 stateName =>     'ANSI_PORTS_TYPE2',
3880
 failNextState => ['ANSI_PORTS_SIGNAL_RANGE'],
3881
 search => [ { arcName => 'TYPE' , regexp => "$verilog_sigs_regexp",
3882
               nextState => ['ANSI_PORTS_TYPE2'],},
3883
             { regexp => '\b(?:signed)\b', nextState => ['ANSI_PORTS_TYPE2'],},],
3884
 },
3885
 { # V2001 ansi module ports
3886
 stateName =>     'ANSI_PORTS_SIGNAL_RANGE',          # for signal defs
3887
  failNextState => ['ANSI_PORTS_SIGNAL_NAME'],
3888
 search => [ { regexp => '\[', nextState => ['IN_SIG_RANGE','ANSI_PORTS_SIGNAL_NAME'],
3889
               storePos => 1,}, ],
3890
 },
3891
 { # V2001 ansi module ports
3892
 stateName =>     'ANSI_PORTS_SIGNAL_NAME',
3893
  search => [
3894
   { arcName   => 'TYPE' , regexp    => '\b(?:input|output|inout)\b',
3895
     nextState => ['ANSI_PORTS_TYPE'], resetPos => 1, },
3896
   { arcName   => 'VID' , regexp    => '$VID',
3897
     nextState => ['ANSI_PORTS_SIGNAL_AFTER_NAME'], },
3898
  ],
3899
 },
3900
 { # V2001 ansi module ports
3901
 stateName =>     'ANSI_PORTS_SIGNAL_AFTER_NAME',
3902
 search =>
3903
  [
3904
   { regexp => ',',  nextState => ['ANSI_PORTS_SIGNAL_NAME'],},
3905
   { regexp => '\[', nextState => ['IN_MEM_RANGE','ANSI_PORTS_SIGNAL_AFTER_NAME'],}, # memories
3906
   { regexp => '\)', nextState => ['SEMICOLON'], } # semicolon, then pop up
3907
  ],
3908
 },
3909
 { # v2001 module_parameter_port_list (A.1.3)
3910
 stateName =>     'PPL_BRACKET' ,
3911
 search => [ { regexp    => '\(',  nextState => ['PPL_PARAM'], }, ],
3912
 },
3913
 { # v2001 module_parameter_port_list (A.1.3)
3914
 stateName =>     'PPL_PARAM' ,
3915
 search => [ { arcName=>'PARAM', regexp=>'\bparameter\b', nextState => ['PPL_TYPE'],},],
3916
 },
3917
 { # v2001 module_parameter_port_list (A.1.3)
3918
 stateName =>     'PPL_TYPE',
3919
 failNextState => ['PPL_NAME'],
3920
 search => [
3921
    { arcName   => 'RANGE', regexp    => '\[' ,
3922
      nextState => ['IN_RANGE','PPL_NAME'] , },
3923
    { arcName   => 'SIGNED', regexp    => '\bsigned\b' ,
3924
      nextState => ['PPL_TYPE'] , },  # may be followed by a range
3925
    { arcName   => 'OTHER', regexp    => '\b(?:integer|real|realtime|time)\b' ,
3926
      nextState => ['PPL_NAME'] , },
3927
   ],
3928
 },
3929
 { # v2001 module_parameter_port_list (A.1.3)
3930
 stateName =>     'PPL_NAME',
3931
 search => [
3932
    { arcName   => 'NAME',  regexp    => '$VID' ,
3933
      nextState => ['PARAMETER_EQUAL','PPL_AFTER_EQUALS'] , },
3934
   ],
3935
 },
3936
 { # v2001 module_parameter_port_list (A.1.3)
3937
 stateName =>     'PPL_AFTER_EQUALS',
3938
 allowAnything => 1,
3939
 search =>
3940
  [
3941
   { arcName   => 'CONCAT',      regexp    => '{' ,
3942
     nextState => ['IN_CONCAT','PPL_AFTER_EQUALS'] ,  },
3943
   { arcName   => 'BRACKET',      regexp    => '\(' ,
3944
     nextState => ['IN_BRACKET','PPL_AFTER_EQUALS'] ,  },
3945
   { arcName   => 'COMMA',       regexp    => ',' ,
3946
     nextState => ['PPL_PARAM_OR_NAME'] ,    },
3947
   { arcName   => 'END',       regexp    => '\)' ,
3948
     nextState => ['MODULE_PORTS'] ,    },
3949
   @$vid_vnum_or_string,
3950
  ]
3951
 },
3952
 { # v2001 module_parameter_port_list (A.1.3)
3953
 stateName =>     'PPL_PARAM_OR_NAME' ,
3954
 failNextState => ['PPL_NAME'],
3955
 search => [ { regexp    => '\bparameter\b',  nextState => ['PPL_TYPE'], }, ],
3956
 },
3957
];
3958
}
3959
 
3960
 
3961
############################################################
3962
# make the parser, and return it as a string
3963
############################################################
3964
 
3965
 
3966
sub _make_parser {
3967
    my ($evalDefs,$genDebugCode) = @_;
3968
 
3969
    _check_data_structures($evalDefs);
3970
 
3971
    my $perlCode; # the perl code we are making
3972
 
3973
    my $debugPrint =  $genDebugCode ? 'print "---- $ps->{curState} $file:$line (".pos($code).")\\n" if defined $ps->{curState} && defined pos($code);':'';
3974
#    vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
3975
    $perlCode .= <<EOF;
3976
sub _parse_line {
3977
 
3978
  my (\$self,\$code,\$file,\$line,\$ps,\$rs) = \@_;
3979
 
3980
  if (!exists(\$ps->{curState})){
3981
      \$ps->{curState} = undef;
3982
      \$ps->{prevState}= undef;
3983
      \$ps->{nextStateStack}= ["START"];
3984
      \$ps->{storing}= 0;
3985
      \$ps->{stored}= "";
3986
      \$ps->{confusedNextState}= "START";
3987
  }
3988
 
3989
  my \$storePos = -1;
3990
  my \$lastPos = 0;
3991
  my \$posMark;
3992
  my \$fromLastPos;
3993
  PARSE_LINE_LOOP: while (1) {
3994
 
3995
    \$lastPos = pos(\$code) if (defined(pos(\$code)));
3996
 
3997
    if ( \$code =~ m/\\G\\s*\\Z/gs ) {
3998
        last PARSE_LINE_LOOP;
3999
    }
4000
    else {
4001
        pos(\$code) = \$lastPos;
4002
    }
4003
 
4004
    \$code =~ m/\\G\\s*/gs ; # skip any whitespace
4005
 
4006
    \$ps->{prevState} = \$ps->{curState};
4007
    \$ps->{curState} = pop(\@{\$ps->{nextStateStack}}) or
4008
        die "Error: No next state after \$ps->{prevState} ".
4009
            "\$file line \$line :\n \$code";
4010
    $debugPrint
4011
 
4012
    goto \$ps->{curState};
4013
    die \"Confused: Bad state \$ps->{curState}\";
4014
 
4015
    CONFUSED:
4016
        \$posMark = '';
4017
        # make the position marker: tricky because code can contain tabs
4018
        #  which we want to match in the blank space before the ^
4019
        \$posMark = substr(\$code,0,\$lastPos);
4020
        \$posMark =~ tr/\t/ /c ; # turn anything that isn't a tab into a space
4021
        \$posMark .= "^" ;
4022
        if (substr(\$code,length(\$code)-1,1) ne "\\n") { \$posMark="\\n".\$posMark; }
4023
        \$self->_add_confused("\$file:\$line: in state \$ps->{prevState}:\\n".
4024
                    "\$code".\$posMark);
4025
        \@{\$ps->{nextStateStack}} = (\$ps->{confusedNextState});
4026
       return; # ignore the rest of the line
4027
EOF
4028
#    ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
4029
 
4030
 
4031
  foreach my $state (@$languageDef) {
4032
      my $stateName = $state->{stateName};
4033
      my $allowAnything    = exists($state->{allowAnything}) && $state->{allowAnything};
4034
      my $re = $allowAnything ? '' : '\G'; # allowAnything==0 forces a match 
4035
      #  where we left off last time
4036
      $perlCode.= "    $stateName:\n";
4037
 
4038
      if (exists($state->{confusedNextState})) {
4039
          $perlCode.= "      \$ps->{confusedNextState}=\"$state->{confusedNextState}\";\n";
4040
      }
4041
 
4042
      if (exists($state->{search})) {
4043
          my @searchTerms=();
4044
          foreach my $search (@{$state->{search}}) {
4045
              push @searchTerms, $search->{regexp};
4046
          }
4047
          $re .= "(?:(". join(")|(",@searchTerms)."))";
4048
 
4049
          my $failNextState='';
4050
 
4051
          if (exists($state->{failNextState})) {
4052
              if (scalar(@{$state->{failNextState}}) != 0) {
4053
                  $failNextState="\"".
4054
                      join('","',reverse(@{$state->{failNextState}})).
4055
                          "\"";
4056
              }
4057
              # else leave it set at nothing - means just popup
4058
          }
4059
          else {
4060
              $failNextState='"CONFUSED"';
4061
          }
4062
          $perlCode.= "        if (\$code =~ m/$re/gos) {\n";
4063
 
4064
          my $elsif2="if";
4065
          my $i=0;
4066
          foreach my $search (@{$state->{search}}) {
4067
              $i++;
4068
 
4069
              my $arcName = exists($search->{arcName}) ? $search->{arcName} : '';
4070
 
4071
              $perlCode.= "          $elsif2 (defined(\$$i)) {\n";
4072
              if ($genDebugCode) {
4073
                  $perlCode.="           print \"----  -$arcName (\$$i)->\\n\";\n";
4074
                  $perlCode.="           \$takenArcs->{'$stateName'}{$i}++;\n";
4075
              }
4076
              $elsif2="elsif";
4077
              if (exists($search->{resetPos}) && $search->{resetPos}) {
4078
                  $perlCode.="           pos(\$code)=pos(\$code)-length(\$$i);\n";
4079
              }
4080
              if (exists($search->{arcName})) {
4081
                  $perlCode.=  # "            " . 
4082
                      _make_eval_code($evalDefs,$stateName,
4083
                                   $search->{arcName},$i,$genDebugCode);
4084
              }
4085
              if (exists $search->{nextState}) {
4086
                  $perlCode.= "       push (\@{\$ps->{nextStateStack}}, \"".
4087
                      join('","',reverse(@{$search->{nextState}}))."\");\n";
4088
              }
4089
              if (exists($search->{storePos}) && $search->{storePos}) {
4090
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
4091
                  $perlCode.= "            die \"Setting storing ".
4092
                      "flag when it is already set: $stateName:$arcName\";\n";
4093
                  $perlCode.= "       \$storePos       = pos(\$code);\n";
4094
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
4095
                  $perlCode.= "       \$ps->{stored}   = '';\n";
4096
              }
4097
              $perlCode.= "       }\n";
4098
          }
4099
          $perlCode.= "      }\n";
4100
 
4101
          if ($allowAnything) {
4102
              $perlCode.= "      else { ".
4103
                  "push(\@{\$ps->{nextStateStack}},\"$stateName\"); last  PARSE_LINE_LOOP; }\n";
4104
          }
4105
          else {
4106
              $perlCode.= "      else {\n";
4107
              if (exists($state->{failStorePos}) && $state->{failStorePos}) {
4108
                  $perlCode.= "       \$ps->{storing} == 0 or\n";
4109
                  $perlCode.= "            die \"Setting storing ".
4110
                      "flag when it is already set: $stateName:fail\";\n";
4111
                  #NB:uses lastPos here because there was no match, so can't 
4112
                  #  use pos(code)
4113
                  $perlCode.= "       \$storePos       = \$lastPos;\n";
4114
                  $perlCode.= "       \$ps->{storing}  = 1;\n";
4115
                  $perlCode.= "       \$ps->{stored}   = '';\n";
4116
              }
4117
              if ($failNextState) {
4118
                  $perlCode.="push(\@{\$ps->{nextStateStack}},$failNextState);";
4119
              }
4120
              $perlCode.= " pos(\$code)=\$lastPos; }\n";
4121
          }
4122
      }
4123
      $perlCode.= "    next PARSE_LINE_LOOP;\n";
4124
  }
4125
  $perlCode.= "  }\n";
4126
  $perlCode.= "  if (\$storePos!=-1) { \$ps->{stored}=substr(\$code,\$storePos);}\n";
4127
  $perlCode.= "  elsif ( \$ps->{storing} ) {   \$ps->{stored} .= \$code; }\n";
4128
  $perlCode.= "}\n";
4129
 
4130
  return $perlCode;
4131
}
4132
 
4133
sub _make_eval_code {
4134
    my ($evalDefs,$stateName,$arcName,$matchNo,$genDebugCode) = @_;
4135
 
4136
    my $eval='';
4137
 
4138
    foreach my $evalDef (@$evalDefs) {
4139
 
4140
        if (exists($evalDef->{$stateName}{$arcName})) {
4141
            if ( $evalDef->{$stateName}{$arcName} =~ m/^(\w+?):(\w+?)$/ ) {
4142
                $eval.=$evalDef->{$1}{$2};
4143
            }
4144
            else {
4145
                $eval.=$evalDef->{$stateName}{$arcName};
4146
            }
4147
            $eval.="\n";
4148
        }
4149
    }
4150
    # replace $match variable with the actual number of the match
4151
    $eval=~ s/\$match/\$$matchNo/g;
4152
 
4153
    # if fromLastPos is used then generate the code to work it out
4154
    if ($eval =~ /\$fromLastPos/) {
4155
        my $e;
4156
        $e .= "\$ps->{storing}==1 or die \"fromLastPos used and storing was not set\";\n";
4157
        $e .= "if (\$storePos==-1) {\n"; # on another line
4158
        $e .= "   \$fromLastPos=\$ps->{stored}."; # what was before
4159
        $e .= "       substr(\$code,0,pos(\$code)-length(\$$matchNo));\n"; # some of this line
4160
        $e .= "}\n";
4161
        $e .= "else {\n";
4162
        $e .= "   \$fromLastPos=substr(\$code,\$storePos,pos(\$code)".
4163
            "-\$storePos-length(\$$matchNo));\n";
4164
        $e .= "}\n";
4165
        $e .= "\$ps->{storing}=0;\n";
4166
        $e .= "\$ps->{stored}='';\n";
4167
        $eval = $e . $eval;
4168
 
4169
    }
4170
    return $eval;
4171
}
4172
 
4173
sub _check_end_state {
4174
  my ($self,$file,$line,$ps) = @_;
4175
 
4176
  if (!exists($ps->{curState})){
4177
      # parse_line was never called, file only contained comments, defines etc
4178
      return;
4179
  }
4180
  $ps->{prevState} = $ps->{curState};
4181
  $ps->{curState} = pop(@{$ps->{nextStateStack}}) or
4182
      $self->_add_confused("$file:$line:".
4183
                          "No next state after $ps->{prevState} at EOF");
4184
 
4185
  if ($ps->{curState} ne 'START') {
4186
      $self->_add_confused("$file:$line:".
4187
                          " at EOF in state $ps->{curState}".
4188
                          (($ps->{curState} eq 'CONFUSED')?
4189
                                           ",prevState was $ps->{prevState}":""));
4190
  }
4191
  if (@{$ps->{nextStateStack}}) {
4192
      $self->_add_confused("$file:$line:".
4193
                          " at EOF, state stack not empty: ".
4194
                          join(" ",@{$ps->{nextStateStack}}));
4195
  }
4196
 
4197
  # at the moment I don't check these:
4198
  # $ps->{storing}= 0;  
4199
  # $ps->{stored}= "";
4200
 
4201
}
4202
 
4203
sub _check_data_structures {
4204
    my ($evalDefs) = @_;
4205
 
4206
    my %stateNames;
4207
    my %statesUnused;
4208
 
4209
    foreach my $sp (@$languageDef) {
4210
        die "Not hash!" unless ref($sp) eq "HASH";
4211
        if (!exists($sp->{stateName})) {  die "State without name!"; }
4212
        die "Duplicate state$sp->{stateName}" if exists $stateNames{$sp->{stateName}};
4213
        $stateNames{$sp->{stateName}} = $sp;
4214
    }
4215
 
4216
    %statesUnused = %stateNames;
4217
    # check language def first
4218
    foreach my $sp (@$languageDef) {
4219
        my %t = %$sp;
4220
        if (!exists($sp->{search})) {  die "State without search!"; }
4221
        die "search $sp->{stateName} not array" unless ref($t{search}) eq "ARRAY";
4222
        my %arcNames;
4223
        foreach my $arc (@{$sp->{search}}) {
4224
            my %a = %$arc;
4225
            die "arc without regexp in $sp->{stateName}" unless exists $a{regexp};
4226
            delete $a{regexp};
4227
            if (exists($a{nextState})) {
4228
                die "nextState not array"  unless ref($a{nextState}) eq "ARRAY";
4229
                foreach my $n (@{$a{nextState}}) {
4230
                    next if ($n =~ m/^\$/); #can't check variable ones
4231
                    die "Bad Next state $n"
4232
                        unless exists $stateNames{$n};
4233
                    delete($statesUnused{$n}) if exists $statesUnused{$n};
4234
                }
4235
                delete $a{nextState};
4236
            }
4237
            if (exists($a{arcName})) {
4238
                die "Duplicate arc $a{arcName}" if exists $arcNames{$a{arcName}};
4239
                $arcNames{$a{arcName}} = 1;
4240
                delete $a{arcName};
4241
            }
4242
            delete $a{resetPos};
4243
            delete $a{storePos};
4244
            foreach my $k (sort (keys %a)) {
4245
                die "Bad key $k in arc of state $t{stateName}";
4246
            }
4247
        }
4248
        delete $t{stateName};
4249
        delete $t{search};
4250
        delete $t{allowAnything} if exists $t{allowAnything};
4251
 
4252
        if (exists($t{confusedNextState})) {
4253
            die "Bad Next confused state $t{confusedNextState}"
4254
                unless exists $stateNames{$t{confusedNextState}};
4255
            delete $t{confusedNextState};
4256
        }
4257
 
4258
        foreach my $n (@{$t{failNextState}}) {
4259
            next if ($n =~ m/^\$/); #can't check variable ones
4260
            die "Bad Next fail state $n"
4261
                unless exists $stateNames{$n};
4262
            delete($statesUnused{$n}) if exists $statesUnused{$n};
4263
        }
4264
        delete $t{failNextState} if exists $t{failNextState};
4265
        delete $t{failStorePos}  if exists $t{failStorePos};
4266
        foreach my $k (sort (keys %t)) {
4267
            die "Bad key $k in languageDef state $sp->{stateName}";
4268
        }
4269
    }
4270
 
4271
    # REVISIT: MODULE PORTS looks like it is unused because it is got to
4272
    #  by setting $nState - should have a flag in language def that turns
4273
    #  off this check on a per state basis.
4274
    foreach my $state (sort (keys %statesUnused)) {
4275
        #die "State $state was not used";
4276
        print "Warning: State $state looks like it was not used\n" if $debug;
4277
    }
4278
 
4279
    foreach my $evalDef (@$evalDefs) {
4280
        foreach my $state (sort (keys %$evalDef)) {
4281
            if (!exists($stateNames{$state})) {
4282
                die "Couldn't find state $state";
4283
            }
4284
            my $statep = $stateNames{$state};
4285
 
4286
            foreach my $arc (sort (keys %{$evalDef->{$state}})) {
4287
                my $found = 0;
4288
                foreach my $s (@{$statep->{search}}) {
4289
                    if (exists($s->{arcName}) && ($s->{arcName} eq $arc)) {
4290
                        $found=1;
4291
                        last;
4292
                    }
4293
                }
4294
                if ($found == 0) {
4295
                    die "No arc $arc in state $state";
4296
                }
4297
                if ( $evalDef->{$state}{$arc} =~ m/^(\w+?):(\w+?)$/ ) {
4298
                    die "No code found for $evalDef->{$state}{$arc}"
4299
                        unless exists $evalDef->{$1}{$2};
4300
                }
4301
            }
4302
        }
4303
    }
4304
}
4305
 
4306
 
4307
sub _check_coverage {
4308
 
4309
    print "\n\nCoverage Information:\n";
4310
    foreach my $sp (@$languageDef) {
4311
        if (!exists($takenArcs->{$sp->{stateName}})) {
4312
            print " State $sp->{stateName}: no arcs take (except fail maybe)\n";
4313
        }
4314
        else {
4315
            my $i=0;
4316
            foreach my $arc (@{$sp->{search}}) {
4317
                $i++;
4318
                if (!exists( $takenArcs->{$sp->{stateName}}{$i} )) {
4319
                    my $arcName = $i;
4320
                    $arcName = $arc->{arcName} if exists $arc->{arcName};
4321
                    print " Arc $arcName of $sp->{stateName} was never taken\n";
4322
                }
4323
            }
4324
        }
4325
    }
4326
}
4327
 
4328
 
4329
###########################################################################
4330
 
4331
# when doing require or use we must return 1
4332
1;
4333
 

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.