File Coverage

blib/lib/spice.pm
Criterion Covered Total %
statement 224 296 75.6
branch 82 136 60.2
condition 22 36 61.1
subroutine 19 21 90.4
pod 0 16 0.0
total 347 505 68.7


line stmt bran cond sub pod time code
1             package spice ;
2             require 5.001 ;
3              
4             ##################################################################
5             # Copyright (c) 2000 Rohit Sharma. All rights reserved.
6             # This program is free software; you can redistribute it and/or
7             # modify it under the same terms as Perl itself.
8             ##################################################################
9              
10             #############
11             #Author : Rohit Sharma
12             #Date : 21 August, 2000.
13             #Description : SPICE netlist interface
14             #
15             #
16             #
17             #############
18              
19              
20              
21             BEGIN {
22 1     1   5 require Exporter;
23 1     1   684 use Carp ;
  1         2  
  1         100  
24 1     1   5 use vars qw(@ISA @EXPORT @EXPORT_OK $VERSION) ;
  1         1  
  1         213  
25 1         19 @ISA = qw(Exporter);
26 1         4 @EXPORT = qw(&spiceInit &getTopSubckts &getSubcktList &getSubckt &getResistors &getCapacitors &getTransistors &getInstances &getBulkConnections) ;
27 1         2 $VERSION = 0.01 ;
28              
29 1         29 $SIG{INT} = sub { die "... wait wait. one sec, huh?\n" } ;
  0         0  
30             #initilize global variables ;
31 1         3 $spice::error = "" ;
32 1         1 $spice::warn = "" ;
33 1         2 $spice::verbose = 0 ;
34 1         1 $spice::DEBUG_ = 0 ;
35 1         2 $spice::tmpFile = "" ;
36 1         1 $spice::topSubckt = "top" ;
37 1         27 %spice::subckts = ( ) ;
38             }
39              
40 1     1   5 use strict ;
  1         2  
  1         3162  
41              
42             sub spiceInit {
43 1     1 0 31 my ( $file ) = @_ ;
44 1         2 $spice::error = "" ;
45 1         3 $spice::warn = "" ;
46              
47 1 50       4 do {
48 0         0 carp "no spice file given." ;
49 0         0 $spice::error = "no spice file given." ;
50 0         0 return "-1";
51             } unless ( defined $file ) ;
52 1 50 33     96 do {
53 0         0 carp "spice file $file is not a plain text file." ;
54 0         0 $spice::error = "spice file $file is not a plain text file." ;
55 0         0 return "-1";
56             }unless ( -f $file && -T $file ) ;
57              
58 1 50       5 Log ( "Processing spice file $file: phase1\n" )
59             if ( $spice::verbose ) ;
60 1         1 my $retValue ;
61 1         5 $retValue = processSpice ( $file ) ;
62 1 50       7 return "-1" if ( $retValue == "-1" ) ;
63              
64 1 50       3 Log ( "Processing spice file $file: phase2\n" )
65             if ( $spice::verbose ) ;
66 1         6 $retValue = readSpice ( $spice::tmpFile ) ;
67 1 50       6 return "-1" if ( $retValue == "-1" ) ;
68 1         4 return 0; # Initialization sucessful.
69             }
70              
71             sub processSpice {
72 1     1 0 2 my ( $file ) = @_ ;
73 1 50       7 do {
74 1 50       7 $spice::tmpFile = "${file}.tmp" if ($file) ;
75             } unless ( -f $spice::tmpFile ) ;
76 1 50       123 do {
77 0         0 carp "Could not open new spice File $spice::tmpFile for writing." ;
78 0         0 $spice::error = "Could not open new spice File $spice::tmpFile for writing." ;
79 0         0 return "-1" ;
80             } unless open ( TMPSPICE, ">$spice::tmpFile" ) ;
81 1 50       28 do {
82 0         0 carp "Could not open spice File $file for reading." ;
83 0         0 $spice::error = "Could not open spice File $file for reading." ;
84 0         0 return "-1" ;
85             } unless open ( SPICE, "<$file" ) ;
86              
87 1 50       4 Log ( "reading spice file ..." ) if ( $spice::verbose ) ;
88 1         1 my $line ;
89             my $prevLine ;
90 1         3 my $lineNo = 0;
91              
92 1         37 while ( $line = ) {
93 45         37 $lineNo++ ;
94 45 0 33     87 Log ( "." ) if ( $lineNo/1000==int($lineNo/1000) && $spice::verbose) ;
95              
96 45         84 $line =~ s/\n//g ;
97 45 100       85 next unless ( length $line ) ;# ignore blank lines.
98 38 100       66 next if ( $line =~ m/^\s*\*/ );# weed out comments.
99 37 100       60 if ( $line =~ m/^\s*\+/ ) {
100 3         11 $line =~ s/^\s*\+/ /g ; # eat up continuation character +.
101 3         13 $prevLine .= $line ;
102             }
103             else {
104 34 100       89 print TMPSPICE "$prevLine\n" if ( $prevLine ) ;
105 34         77 $prevLine = $line ;
106             }
107             }
108 1 50       5 print TMPSPICE "$prevLine\n" if ( $prevLine ) ;
109 1 50       11 Log ( "... done.\n" ) if ( $spice::verbose ) ;
110 1         11 close SPICE ;
111 1         62 close TMPSPICE ;
112 1         3 return 0; #phase 1 successful.
113             }
114              
115             sub readSpice ( ) {
116 1     1 0 3 my ( $file ) = @_ ;
117 1         3 my $subcktName = "" ;
118            
119 1 50       32 do {
120 0         0 carp "Could not open new spice File $file for reading." ;
121 0         0 $spice::error = "Could not open new spice File $file for reading." ;
122 0         0 return "-1" ;
123             } unless open ( TMPSPICE, "<$file" ) ;
124              
125 1         3 my $line ;
126 1         12 while ( $line = ) {
127 34 50       61 if( $line =~ m/^\s*\+/ ) { # self validation.
128 0         0 Log ( "processSpice subroutine didnt work correctly. Bug in the spice.pm\n" ) ;
129 0         0 return "-1" ;
130             }
131              
132 34 100 100     258 next unless ( $line =~ m/^\s*x/i ||
      100        
      100        
      100        
      100        
133             $line =~ m/^\s*r/i ||
134             $line =~ m/^\s*c/i ||
135             $line =~ m/^\s*m/i ||
136             $line =~ m/^\s*\.subckt/i ||
137             $line =~ m/^\s*\.end/i
138             ) ;
139              
140 33 100       123 if ( $line =~ m/^\s*\.subckt/i ) {
    100          
    100          
    100          
    100          
    100          
    50          
141 6         12 $subcktName = getSubcktName ( $line ) ;
142 6 50       20 do {
143 0         0 carp "WARN: incorrect .subckt definition: $line.\n" ;
144 0         0 $spice::warn = "WARN: incorrect .subckt definition: $line.\n" ;
145 0         0 next ;
146             } if ( $subcktName eq "-1" ) ;
147 6         13 $spice::subckts{$subcktName} = $line ;
148 6         19 next ;
149             }
150             elsif ( $line =~ m/^\s*\.ends/i ) {
151 6 50       10 do {
152 0         0 carp "WARN:.ends statment without subckt definition. $line.\n" ;
153 0         0 $spice::warn = "WARN:.ends statment without subckt definition. $line.\n";
154 0         0 next ;
155             }unless ( $subcktName ) ;
156 6         8 $spice::subckts{$subcktName} .= $line ;
157 6         7 $subcktName = "" ;
158 6         14 next ;
159             }
160             elsif ( $line =~ m/^\s*x/i ) {
161 12 50       20 $subcktName = $spice::topSubckt unless ( $subcktName ) ;
162 12         20 $spice::subckts{$subcktName} .= $line ;
163 12         30 next ;
164             }
165             elsif ( $line =~ m/^\s*r/i ) {
166 1 50       3 $subcktName = $spice::topSubckt unless ( $subcktName ) ;
167 1         2 $spice::subckts{$subcktName} .= $line ;
168 1         3 next ;
169             }
170             elsif ( $line =~ m/^\s*c/i ) {
171 1 50       4 $subcktName = $spice::topSubckt unless ( $subcktName ) ;
172 1         1 $spice::subckts{$subcktName} .= $line ;
173 1         3 next ;
174             }
175             elsif ( $line =~ m/^\s*m/i ) {
176 6 50       9 $subcktName = $spice::topSubckt unless ( $subcktName ) ;
177 6         10 $spice::subckts{$subcktName} .= $line ;
178 6         13 next ;
179             }
180 1         1 elsif ( $line =~ m/^\s*\.end[\s+|\n]/i ) { last; }
181             }
182              
183 1         10 close TMPSPICE ;
184 1 50       96 unlink ( $spice::tmpFile ) if ( -f $spice::tmpFile ) ;
185 1         4 return 0 ; # mission successful :=)
186             }
187              
188             sub getBulkConnections {
189 0     0 0 0 my ($txName) = @_ ;
190 0         0 $spice::error = "" ;
191 0         0 $spice::warn = "" ;
192 0         0 $spice::warn = "This subroutine has not been implemented yet.\n" ;
193 0         0 return "-1";
194             }
195              
196             sub getSubcktName {
197 6     6 0 8 my ( $stmt ) = @_ ;
198 6         8 $spice::error = "" ;
199 6         3 $spice::warn = "" ;
200 6         17 my @parts ;
201 6         18 $stmt =~ s/^\s*\.subckt\s+//i ;
202 6         23 @parts = split /\s+/, $stmt ;
203 6 50       13 if ($spice::DEBUG_ ) { print "\t\tsubckt Name : $parts[0].\n" ; }
  0         0  
204 6 50       19 if ( $parts[0] ) { return $parts[0]; }
  6         16  
205 0         0 else { return "-1" ; }
206             }
207              
208             sub getSubckt {
209 1     1 0 12 my ($subckt) = @_ ;
210 1         2 $spice::error = "" ;
211 1 50 33     8 if ( $subckt && $spice::subckts{$subckt} ) {
212 1         3 return $spice::subckts{$subckt} ;
213             }
214             else {
215 0         0 $spice::error = "Subckt definition not found in spice." ;
216 0         0 return "-1" ;
217             }
218             }
219              
220             sub getCapacitors {
221 1     1 0 13 my ($subcktName) = @_ ;
222 1         1 $spice::error = "" ;
223 1         7 $spice::warn = "" ;
224 1         2 my $subcktDefn ;
225              
226 1         2 $spice::error = "" ;
227 1 50 33     7 if ( $subcktName && $spice::subckts{$subcktName} ) {
228 1         3 $subcktDefn = $spice::subckts{$subcktName} ;
229             }
230             else {
231 0         0 $spice::error = "Subckt definition not found in spice." ;
232 0         0 return "-1" ;
233             }
234 1         2 my @list ;
235             my $line ;
236 1         5 foreach $line ( split /\n/, $subcktDefn ) {
237 8 100       23 next unless ( $line =~ m/^\s*c/i ) ;
238 1         1 my @retValue ;
239 1         3 @retValue = getResCapName ( $line ) ;
240 1 50       4 if ( $#retValue > 0 ) { # make sure it has returned 2 elements.
241 1         3 push @list, @retValue ;
242             }
243             }
244 1         6 return @list ;
245             }
246              
247             sub getResistors {
248 1     1 0 11 my ($subcktName) = @_ ;
249 1         3 $spice::error = "" ;
250 1         1 $spice::warn = "" ;
251 1         2 my $subcktDefn ;
252              
253 1         2 $spice::error = "" ;
254 1 50 33     6 if ( $subcktName && $spice::subckts{$subcktName} ) {
255 1         3 $subcktDefn = $spice::subckts{$subcktName} ;
256             }
257             else {
258 0         0 $spice::error = "Subckt definition not found in spice." ;
259 0         0 return "-1" ;
260             }
261 1         1 my @list ;
262             my $line ;
263 1         6 foreach $line ( split /\n/, $subcktDefn ) {
264 8 100       22 next unless ( $line =~ m/^\s*r/i ) ;
265 1         2 my @retValue ;
266 1         5 @retValue = getResCapName ( $line ) ;
267 1 50       4 if ( $#retValue > 0 ) { # make sure it has returned 2 elements.
268 1         3 push @list, @retValue ;
269             }
270             }
271 1         5 return @list ;
272             }
273              
274             sub getResCapName {
275 2     2 0 3 my ( $stmt ) = @_ ;
276 2 50       8 if ( $stmt !~ m/^\s*[rc]/i ) {
277 0         0 $spice::error = "Not a valid resistor or capacitor declaration. :$stmt" ;
278 0         0 return "-1" ;
279             }
280 2         3 my @tmp ;
281 2         14 @tmp = split /\s+/, $stmt ;
282 2 50       6 if ( $#tmp < 3 ) {
283 0         0 $spice::error = "Not a valid resistor or capacitor declaration. :$stmt" ;
284 0         0 return "-1" ;
285             }
286 2         8 return ( $tmp[0], $tmp[3] ) ;
287             }
288              
289             sub getTransistors {
290 1     1 0 12 my ($subcktName) = @_ ;
291 1         2 $spice::error = "" ;
292 1         2 $spice::warn = "" ;
293 1         1 my $subcktDefn ;
294              
295 1         2 $spice::error = "" ;
296 1 50 33     11 if ( $subcktName && $spice::subckts{$subcktName} ) {
297 1         29 $subcktDefn = $spice::subckts{$subcktName} ;
298             }
299             else {
300 0         0 $spice::error = "Subckt definition not found in spice." ;
301 0         0 return "-1" ;
302             }
303 1         3 my @list ;
304             my $line ;
305 1         5 foreach $line ( split /\n/, $subcktDefn ) {
306 4 100       15 next unless ( $line =~ m/^\s*m/i ) ;
307 2         3 my @retValue ;
308 2         6 @retValue = getTxName ( $line ) ;
309 2 50       7 if ( $#retValue > 0 ) { # make sure it has returned 2 elements.
310 2         5 push @list, @retValue ;
311             }
312             }
313 1         6 return @list ;
314             }
315              
316             sub getTxName {
317 2     2 0 3 my ( $stmt ) = @_ ;
318 2 50       8 if ( $stmt !~ m/^\s*m/i ) {
319 0         0 $spice::error = "Not a valid instance statement. :$stmt" ;
320 0         0 return "-1" ;
321             }
322 2         3 my $tx ;
323             my $type ;
324 2         6 ( $tx ) = split /\s+/, $stmt ;
325 2         3 my @tmp ;
326 2 50       7 if ( $stmt =~ m/\=/ ) {
327 2         18 ( @tmp ) = split /\s*\=\s*/, $stmt ;
328 2         19 ( @tmp ) = split /\s+/, $tmp[0] ;
329 2 50       9 if ( $tmp[$#tmp-1] ) {
330 2         33 $type = $tmp[$#tmp-1] ;
331             }
332             else {
333 0         0 $spice::error = "could not find transistor type." ;
334 0         0 return "-1" ;
335             }
336             }
337             else {
338 0         0 ( @tmp ) = split /\s+/, $stmt ;
339 0 0       0 if ( $tmp[$#tmp] ) {
    0          
340 0         0 $type = $tmp[$#tmp] ;
341             }
342             elsif ( $tmp[$#tmp-1] ) {
343 0         0 $type = $tmp[$#tmp-1] ;
344             }
345             else {
346 0         0 $spice::error = "could not find transistor type." ;
347 0         0 return "-1" ;
348             }
349             }
350 2         8 return ( $tx, $type ) ;
351             }
352              
353             sub getInstances {
354 20     20 0 34 my ($subcktName) = @_ ;
355 20         21 $spice::error = "" ;
356 20         20 $spice::warn = "" ;
357 20         18 my $subcktDefn ;
358              
359 20         19 $spice::error = "" ;
360 20 50 33     75 if ( $subcktName && $spice::subckts{$subcktName} ) {
361 20         24 $subcktDefn = $spice::subckts{$subcktName} ;
362             }
363             else {
364 0         0 $spice::error = "Subckt definition not found in spice." ;
365 0         0 return "-1" ;
366             }
367 20         16 my @list ;
368             my $line ;
369 20         58 foreach $line ( split /\n/, $subcktDefn ) {
370 114 100       275 next unless ( $line =~ m/^\s*x/i ) ;
371 42         30 my @retValue ;
372 42         63 @retValue = getInstName ( $line ) ;
373 42 50       81 if ( $#retValue > 0 ) { # make sure it has returned 2 elements.
374 42         81 push @list, @retValue ;
375             }
376             }
377 20         130 return @list ;
378             }
379              
380             sub getInstName {
381 42     42 0 40 my ( $stmt ) = @_ ;
382 42 50       89 if ( $stmt !~ m/^\s*x/i ) {
383 0         0 $spice::error = "Not a valid instance statement." ;
384 0         0 return "-1" ;
385             }
386 42         53 my $inst ;
387             my $subckt ;
388 42         71 ( $inst ) = split /\s+/, $stmt ;
389 42         44 my @tmp ;
390 42 50       72 if ( $stmt =~ m/\=/ ) {
391 0         0 ( @tmp ) = split /\s*\=\s*/, $stmt ;
392 0         0 ( @tmp ) = split /\s+/, $tmp[0] ;
393 0 0       0 if ( $tmp[$#tmp-1] ) {
394 0         0 $subckt = $tmp[$#tmp-1] ;
395             }
396             else {
397 0         0 $spice::error = "could not find subckt name." ;
398 0         0 return "-1" ;
399             }
400             }
401             else {
402 42         92 ( @tmp ) = split /\s+/, $stmt ;
403 42 50       68 if ( $tmp[$#tmp] ) {
    0          
404 42         54 $subckt = $tmp[$#tmp] ;
405             }
406             elsif ( $tmp[$#tmp-1] ) {
407 0         0 $subckt = $tmp[$#tmp-1] ;
408             }
409             else {
410 0         0 $spice::error = "could not find subckt name." ;
411 0         0 return "-1" ;
412             }
413             }
414 42         109 return ( $inst, $subckt ) ;
415             }
416              
417             sub getTopSubckts {
418 1     1 0 8 my @nodes ;
419 1         3 $spice::error = "" ;
420 1         2 $spice::warn = "" ;
421 1         5 @nodes = keys %spice::subckts ;
422 1         3 my @list ;
423             my $node1 ;
424 0         0 my $node2 ;
425 1         4 foreach $node1 ( @nodes ) {
426 6         7 my $top = 1 ;
427 6         8 foreach $node2 ( @nodes ) {
428 21 100       35 next if ( $node2 eq $node1 ) ;
429 19         18 my $inst ;
430             my @instances ;
431 0         0 my %tmp ;
432 19         30 %tmp = getInstances($node2) ;
433 19         44 @instances = values %tmp ;
434 19         30 undef %tmp ;
435 19         22 foreach $inst ( @instances ) {
436 31 100       54 if ( $inst eq $node1 ) {$top = 0; last ;}
  5         6  
  5         5  
437             }
438 19 100       44 last if ( not $top ) ;
439             }
440 6 100       13 push @list, $node1 if ( $top ) ;
441             }
442 1         5 return @list ;
443             }
444              
445             sub getSubcktList {
446 1     1 0 24 $spice::error = "" ;
447 1         9 $spice::warn = "" ;
448 1         2 my @list ;
449 1         4 @list = keys %spice::subckts ;
450 1 50       4 if ( $#list == -1 ) {
451 0         0 $spice::error = "could not find subckt name." ;
452 0         0 return "-1" ;
453             }
454 1         5 return @list ;
455             }
456              
457             sub Log {
458 0     0 0   my ( $msg ) = @_ ;
459 0           print $msg ;
460             }
461              
462             END {
463 1 50   1   657 Log ( "exiting spice... \n" ) if ( $spice::verbose ) ;
464 1         2 undef $spice::error ;
465 1         3 undef $spice::warn ;
466 1         1 undef $spice::verbose ;
467 1         2 undef $spice::DEBUG_ ;
468 1         1 undef $spice::tmpFile ;
469 1         2 undef $spice::topSubckt ;
470 1         0 undef %spice::subckts ;
471             }
472             1; #just for fun.
473              
474             __END__