File Coverage

blib/lib/Verilog/EditFiles.pm
Criterion Covered Total %
statement 142 150 94.6
branch 52 88 59.0
condition 17 27 62.9
subroutine 13 15 86.6
pod 5 5 100.0
total 229 285 80.3


line stmt bran cond sub pod time code
1             # See copyright, etc in below POD section.
2             ######################################################################
3              
4             package Verilog::EditFiles;
5 1     1   86953 use Config;
  1         11  
  1         36  
6 1     1   5 use IO::File;
  1         2  
  1         105  
7 1     1   5 use File::Path;
  1         2  
  1         65  
8 1     1   6 use Carp;
  1         2  
  1         53  
9 1     1   5 use strict;
  1         2  
  1         26  
10              
11 1     1   4 use vars qw($VERSION $Debug);
  1     0   1  
  1         2194  
12              
13             ######################################################################
14             #### Configuration Section
15              
16             $VERSION = '3.476';
17              
18             #######################################################################
19             # CONSTRUCTORS
20              
21             sub new {
22 0     2 1 0 my $class = shift;
23 2         1736 my $self = {
24             # Options
25             program => "Verilog::EditFiles",
26             outdir => ".",
27             translate_synthesis => 0, # Name of define or "1"
28             lint_header => undef,
29             celldefine => undef,
30             timescale_header => undef,
31             timescale_removal => undef,
32             lint_command => 'vlint --brief',
33             v_suffix => ".v",
34             verbose => 1,
35             # Internals
36             _files => {}, # Hash of module name, contains list of lines
37             @_,
38             };
39 2 50       18 $self->{verbose} = 1 if $Debug;
40 2 50       7 $self->{debug} = 1 if $Debug;
41 2         5 bless $self, $class;
42 2         3 return $self;
43             }
44              
45             ######################################################################
46              
47             sub read_and_split {
48 2     1 1 5 my $self = shift;
49 1         27 foreach my $filename (@_) {
50 1         3 $self->_read_split_file($filename);
51             }
52             }
53              
54             sub _read_split_file {
55 1     1   3 my $self = shift;
56 1         2 my $filename = shift;
57              
58 1 50       2 print "Reading $filename...\n" if $self->{verbose};
59 1 50       12 my $fh = IO::File->new("<$filename") or die "%Error: $! $filename\n";
60 1         9 (my $basename = $filename) =~ s!^.*/!!;
61 1         79 (my $basemod = $basename) =~ s!\.(v|inc)$!!;
62              
63 1         6 my @header = "// Created by $self->{program} from $basename\n";
64 1         5 my @trailer = "\n";
65              
66 1         2 my @lines = (@header);
67 1         2 my $modname;
68             my $ever_module;
69 1         3 my $commented;
70 1         0 while (defined(my $line = $fh->getline)) {
71 1         29 $line =~ s!\r!!mg;
72 26         595 $line =~ s![ \t]+\n$!\n!;
73 26 50       49 if ($self->{translate_synthesis}) {
74 26         44 my $define = $self->{translate_synthesis};
75 26 50       29 $define = "SYNTHESIS" if $define eq "1";
76 26         49 $line =~ s!^\s*//\s*(ambit|synopsys|synthesis)\s*translate_off\s*$!`ifndef ${define}\n!;
77 26         34 $line =~ s!^\s*//\s*(ambit|synopsys|synthesis)\s*translate_on\s*$!`endif //${define}\n!;
78 26 50       30 if ($line =~ m!(ambit|synopsys|synthesis)\s*translate!) {
79 26         48 die "%Error: Unhandled translate comment: $line\n";
80             }
81             }
82              
83 0         0 while ($line =~ m!.*?(/\*|//|\*/)!g) {
84 26 100 100     72 if (!$commented && $1 eq '//') {
    100 66        
    100 66        
85 7         42 last;
86             } elsif (!$commented && $1 eq '/*') {
87 4         6 $commented = 1;
88             } elsif ($commented && $1 eq '*/') {
89 1         29 $commented = 0;
90             }
91             }
92              
93 1 100 66     3 if (!$commented
    100 66        
    50 33        
    100 33        
      66        
      66        
94             && $line =~ /^\s*(module|primitive)\s+([A-Za-z0-9_]+)/) {
95 26         254 my $newmodname = $2;
96 3 100       8 if ($modname) { # Already in a module
97             # Support code like this
98             # `ifdef x
99             # module x (...)
100             # `else
101             # module x (...)
102 3 50       6 ($newmodname eq $modname)
103             or die "%Error: $filename:$.: module without previous endmodule\n";
104 1 50       4 print "$basename:$.: continue module $1\n" if $self->{debug};
105             } else {
106 1         3 $modname = $newmodname;
107 2         3 $ever_module = 1;
108 2 50       3 print "$basename:$.: module $1\n" if $self->{debug};
109 2         4 my @afterif;
110 2         3 my @oldlines = (@lines);
111 2         4 @lines = (@header);
112             # Insert our new header before any `ifdef's or `includes
113 2         5 my $gotifdef;
114 2         3 foreach my $oline (@oldlines) {
115 2 100       3 $gotifdef = 1 if $oline =~ /`ifdef\b|`include\b/;
116 12 100       28 if (!$gotifdef) {
117 12         65 push @lines, $oline;
118             } else{
119 11         21 push @afterif, $oline;
120             }
121             }
122 1 50       3 push @lines, $self->{include_header} if $self->{include_header};
123 2 50       4 push @lines, $self->{timescale_header} if $self->{timescale_header};
124 2 50       5 push @lines, "`celldefine\n" if $self->{celldefine};
125 2 50       4 push @lines, $self->{lint_header} if $self->{lint_header};
126 2         5 push @lines, @afterif;
127             }
128 2         4 push @lines, $line;
129             }
130             elsif (!$commented && $line =~ /^\s*end(module|primitive)\b/) {
131 3 50       59 print "$basename:$.: endmodule $modname\n" if $self->{debug};
132 2 50       6 $modname or die "%Error: $filename:$.: endmodule without previous module\n";
133 2         5 push @lines, $line;
134 2 50       3 push @lines, "`endcelldefine\n" if $self->{celldefine};
135 2         5 push @lines, @trailer;
136 2         3 $self->{_files}{$modname}{created} = 1;
137 2         5 $self->{_files}{$modname}{modname} = $modname;
138 2         5 $self->{_files}{$modname}{lines} = [@lines];
139 2         7 @lines = ();
140             # Prep for next
141 2         5 $modname = undef;
142             }
143             elsif (!$commented
144             && $line =~ /^\s*\`timescale\s.*/
145             && $self->{timescale_removal}) {
146             # Strip existing timescale
147             }
148             elsif (!$commented
149             && $line =~ /^\s*\`(end)?celldefine\b/
150             && $self->{celldefine}) {
151             # Strip existing celldefine, we'll add a new one
152             }
153             else {
154 2         71 push @lines, $line;
155             }
156             }
157 19         331 $fh->close;
158              
159 1 50       36 if (!$ever_module) {
160 1 0       23 print "$basename:1: No module, must be include file: $basemod\n" if $self->{debug};
161 0         0 push @lines, @trailer;
162 0         0 $self->{_files}{$basemod}{created} = 1;
163 0         0 $self->{_files}{$basemod}{modname} = $basemod;
164 0         0 $self->{_files}{$basemod}{lines} = [@lines];
165 0         0 $self->{_files}{$basemod}{is_include} = 1;
166             }
167             }
168              
169             #######################################################################
170              
171             sub write_files {
172 0     1 1 0 my $self = shift;
173              
174 1         340 mkpath($self->{outdir});
175 1         182 foreach my $file (sort (keys %{$self->{_files}})) {
  1         4  
176 1         7 my $fileref = $self->{_files}{$file};
177 2 50       42 next if !$fileref->{created};
178 2         6 $self->_write_file($self->{outdir}."/".$fileref->{modname}.$self->{v_suffix}, $fileref);
179             }
180             }
181              
182             sub _write_file {
183 2     2   10 my $self = shift;
184 2         4 my $filename = shift;
185 2         3 my $fileref = shift;
186              
187 2 50       2 print "Writing $filename...\n" if $self->{verbose};
188              
189 2 50       71 my $fh = IO::File->new(">$filename") or die "%Error: $! $filename\n";
190 2         19 foreach my $line (@{$fileref->{lines}}) {
  2         205  
191 2         7 print $fh $line;
192             }
193 34         57 $fh->close;
194             }
195              
196             sub write_lint {
197 2     1 1 8 my $self = shift;
198 1         1786 my %params = (filename => $self->{outdir}."/0LINT.sh",
199             @_);
200              
201 1 50       5 print "Writing $params{filename}...\n" if $self->{verbose};
202              
203 1 50       13 my $fh = IO::File->new(">$params{filename}") or die "%Error: $! $params{filename}\n";
204 1         9 print $fh "#!/bin/bash\n";
205 1         105 print $fh "# Created by $self->{program}\n";
206 1         4 foreach my $fileref (sort {$a->{modname} cmp $b->{modname}} values %{$self->{_files}}) {
  1         2  
  1         6  
207 1 50       7 next if $fileref->{is_include};
208 2 50       4 next if $fileref->{skip_lint};
209 2         5 print $fh "echo \"".("*"x70),"\"\n";
210 2         3 print $fh "echo Lint ".$fileref->{modname},"\n";
211 2         5 print $fh $self->{lint_command}." \$* ".$fileref->{modname}.$self->{v_suffix},"\n";
212             }
213 2         6 $fh->close;
214              
215 1         4 chmod 0777, $params{filename};
216             }
217              
218             #######################################################################
219              
220             sub edit_file {
221 1     1 1 57 my $self = shift;
222             my %params = (filename => undef,
223             write_filename => undef,
224       0     cb => sub {},
225             verbose => $self->{verbose},
226 1         285 @_);
227 1 50       11 defined $params{filename} or croak "%Error: edit_file not passed filename=>,";
228 1 50       5 ref $params{cb} or croak "%Error: edit_file cb=> callback is not code,";
229 1 50       4 $params{write_filename} = $params{filename} if !defined $params{write_filename};
230              
231 1         2 my $wholefile;
232             my $origwholefile;
233             { # Read it
234 1 50       2 my $fh = IO::File->new ("<$params{filename}")
  1         2  
235             or croak "%Error: $! $params{filename},";
236 1         8 local $/; undef $/;
  1         106  
237 1         3 $wholefile = <$fh>;
238 1         32 $origwholefile = $wholefile;
239 1         21 $fh->close();
240             }
241              
242             # Edit
243 1         12 $wholefile = &{$params{cb}}($wholefile);
  1         23  
244              
245             # Writeback
246 1 50       4 if ($wholefile ne $origwholefile) {
247 1 50       16 print " $params{write_filename} (Changed)\n" if $params{verbose};
248 1         40 my ($dev,$ino,$mode) = stat($params{write_filename});
249 1         36 chmod 0777, $params{filename};
250              
251 1 50       44 my $fh = IO::File->new (">$params{write_filename}")
252             or croak "%Error: $! writing $params{write_filename},";
253 1         10 print $fh $wholefile;
254 1         132 $fh->close();
255 1 50       5 chmod $mode, $params{write_filename} if $mode; # Preserve mode
256             }
257             }
258              
259              
260             #######################################################################
261             1;
262             __END__