1#!/usr/local/bin/perl -w
2#
3# Copyright (C) 2003, 2011 Dan McMahill
4#
5# This program is free software; you can redistribute it and/or modify
6# it under the terms of the GNU General Public License as published by
7# the Free Software Foundation; either version 2 of the License, or
8# (at your option) any later version.
9#
10# This program is distributed in the hope that it will be useful,
11# but WITHOUT ANY WARRANTY; without even the implied warranty of
12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13# GNU General Public License for more details.
14#
15# You should have received a copy of the GNU General Public License
16# along with this program; if not, write to the Free Software
17# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
18# MA 02111-1301 USA.
19
20
21# This script is used to process PADS PowerPCB .eco files to backannotate
22# changes to gEDA schematics.  Not all ECO file sections are implemented,
23# and this program is relatively untested.  Please proceed with caution.
24#
25
26# for parsing input options
27use Getopt::Long;
28
29# for ceil function
30use POSIX;
31
32# don't allow -he to be interpreted as --help
33$Getopt::Long::autoabbrev=0;
34
35# make the options be case sensitive
36$Getopt::Long::ignorecase=0;
37
38&GetOptions( ('h|help' => \&usage,
39	      'n|nocopy' => \$nocopy,
40	      'v|verbose' => \$verbose,
41	      'V|version' => \&version
42	     ) );
43
44usage() if $Getopt::Long::error;
45usage() unless @ARGV;
46
47# ECO file name
48$eco = shift( @ARGV );
49
50# if no schematic names follow, exit
51usage() unless @ARGV;
52
53# make sure the input netlist exists and we can open it
54$i = 0;
55while( @ARGV ) {
56  $fname[$i] = shift( @ARGV );
57  die "Schematic file $fname[$i] does not exist or can not be read"
58    unless -r $fname[$i];
59  $i++;
60}
61
62$filecnt = $i;
63
64
65if( $verbose ){ print "Loading ECO file: $eco\n"; }
66$eco_state="DEFAULT";
67$got_end=0;
68open( ECO, "$eco" ) or die "Can't open ECO file $eco !\n";
69
70$line = <ECO>;
71if( $line =~ /^\*PADS-ECO-V3\.0\*[\n\r]*$/ ) {
72    print "Read ECO header line\n" if $verbose ;
73} elsif( $line =~ /^\*PADS-ECO-\*/ ) {
74    print "Unknown ECO file version: $line\n";
75    exit 1;
76} else {
77    print "Invalid ECO file header: $line\n";
78    exit 1;
79}
80
81while( $line = <ECO> ) {
82    #  if( $verbose ){ print "$line\n"; }
83    if( $line =~ /^\*CHGPART\*/ ) {
84	# change type of part (forward annotation)
85	$eco_state="CHGPART";
86	next;
87    } elsif( $line =~ /^\*DEL_ATTRIBUTE\*/ ) {
88	# delete object attribute (forward annotation)
89	$eco_state="DEL_ATTRIBUTE";
90	next;
91    } elsif( $line =~ /^\*DELPART\*/ ) {
92	# delete part from the design (forward annotation)
93	$eco_state="DELPART";
94	next;
95    } elsif( $line =~ /^\*DELPIN\*/ ) {
96	# delete pins from net (forward annotation)
97	$eco_state="DELPIN";
98	next;
99    } elsif( $line =~ /^\*END\*/ ) {
100	# end of ECO file
101	$eco_state="END";
102	$got_end=1;
103	next;
104    } elsif( $line =~ /^\*JOINNET\*/ ) {
105	# join two nets together (forward annotation)
106	$eco_state="JOINNET";
107	next;
108    } elsif( $line =~ /^\*NET\*/ ) {
109	# add pin to net (forward annotation)
110	$eco_state="NET";
111	next;
112    } elsif( $line =~ /^\*PART\*/ ) {
113	# add part to the design (forward annotation)
114	$eco_state="PART";
115	next;
116    } elsif( $line =~ /^\*REMARK\*/ ) {
117	# don't change state on comment lines
118	print "Skipping *REMARK* line\n" if $verbose;
119	next;
120    } elsif( $line =~ /^\*RENNET\*/ ) {
121	# rename netname (forward annotation)
122	$eco_state="RENNET";
123	next;
124    } elsif( $line =~ /^\*RENPART\*/ ) {
125	# rename part in design (forward/backward annotation)
126	$eco_state="RENPART";
127	print "Starting *RENPART* (Refdes Renumber) section\n" if $verbose;
128	next;
129    } elsif( $line =~ /^\*SET_ATTRIBUTE\*/ ) {
130	# set object attribute (forward annotation)
131	$eco_state="SET_ATTRIBUTE";
132	next;
133    } elsif( $line =~ /^\*SIGNAL\*/ ) {
134	# part of *NET* and also *SPLITNET* (forward annotation)
135	$eco_state="SIGNAL";
136	next;
137    } elsif( $line =~ /^\*SPLITNET\*/ ) {
138	# split net into two new nets (forward annotation)
139	$eco_state="SPLITNET";
140	next;
141    } elsif( $line =~ /^\*SWPGATES\*/ ) {
142	$eco_state="SWPGATES";
143	print "Starting *SWPGATES* (Gate Swapping) section\n" if $verbose;
144	next;
145    } elsif( $line =~ /^\*SWPPINS\*/ ) {
146	$eco_state="SWPPINS";
147	print "Starting *SWPPINS* (Pin Swapping) section\n" if $verbose;
148	next;
149    } elsif( $line =~ /^\*/ ) {
150	print "WARNING:  Unknown command line:\n";
151	print "          $line\n";
152	$eco_state="DEFAULT";
153	next;
154    } else {
155	# this must be a data line
156	#if( $verbose ){ print "Processing data line: $line"; }
157    }
158
159    if( $eco_state =~ "RENPART" ) {
160	parseRENPART($line);
161    } elsif( $eco_state =~ "SWPGATES" ) {
162	parseSWPGATES($line);
163    } elsif( $eco_state =~ "SWPPINS" ) {
164	parseSWPPINS($line);
165    } else {
166	print "Skipping lines in $eco_state section\n" if $verbose;
167    }
168
169}
170close( ECO );
171
172for($i=0; $i < $filecnt; $i++) {
173  print "Processing schematic file #", $i+1, ": $fname[$i]\n";
174  open(NETLIST,"$fname[$i]") or
175    die "Can't open schematic $fname[$i]: $!\n";
176
177  # open output netlist
178  $outfname="$fname[$i].new";
179  open(OUTSCH,">$outfname") or die "Can't open $outfname: $!\n";
180
181    while($line = <NETLIST>) {
182	$line = executeRENPART($line);
183	print OUTSCH "$line";
184    }
185    close(NETLIST);
186    close(OUTSCH);
187
188    if( $nocopy ) {
189      print "Leaving page #",$i+1," output in $outfname\n";
190    }
191    else {
192      system("mv $outfname $fname[$i]");
193    }
194
195}
196
197print "\n---- Gate Swapping ----\n";
198executeSWPGATES();
199print "\n---- Pin  Swapping ----\n";
200executeSWPPINS();
201print "\nBackannotation finished ", scalar localtime, "\n";
202
203exit;
204
205
206#######################################################################
207#
208# Subroutines
209#
210#######################################################################
211
212#---------------------------------
213# executeRENPART(line)
214#---------------------------------
215
216sub executeRENPART {
217  my $line = shift(@_);
218
219  return $line unless defined %cmd_rename;
220  return $line unless $line =~ /^refdes=/;
221
222  # pick out the reference designator
223  $refdes = $line;
224  $refdes =~ s/^refdes=//;
225  $refdes =~ s/[\r\n]*$//;
226
227  # see if its listed in our hash of reference designators to be
228  # renamed
229  return $line unless exists $cmd_rename{$refdes};
230
231  print "executeRENPART():  Renaming $refdes to $cmd_rename{$refdes}\n"
232      if $verbose;
233  return "refdes=$cmd_rename{$refdes}\n";
234
235}
236
237#---------------------------------
238# executeSWPGATES()
239#---------------------------------
240
241sub executeSWPGATES {
242  my $key;
243
244  foreach $key (keys %cmd_swap_gates ) {
245    print "Please manually swap gates $key and  $cmd_swap_gates{$key}\n";
246  }
247}
248
249#---------------------------------
250# executeSWPPINS()
251#---------------------------------
252
253sub executeSWPPINS {
254  my $key;
255  my @pins;
256
257  foreach  $key (keys %cmd_swap_pins ) {
258    @pins = split '\.',,$cmd_swap_pins{$key};
259    print "Please manually swap pins $pins[0] and $pins[1] on $key\n";
260  }
261}
262
263#---------------------------------
264# parseRENPART(line)
265#---------------------------------
266
267sub parseRENPART {
268  my $line = shift(@_);
269  my @refs;
270  @refs = split ' ',,$line;
271
272  print "parseRENPART():  Scheduling rename of $refs[0] to $refs[1]\n"
273      if $verbose;
274  $cmd_rename{$refs[0]} = $refs[1];
275
276}
277
278#---------------------------------
279# parseSWPGATES(line)
280#---------------------------------
281
282sub parseSWPGATES {
283  my $line = shift(@_);
284  my @refs;
285  @refs = split ' ',,$line;
286
287  print "parseSWPGATES():  Scheduling swap of gate $refs[0] with $refs[1]\n"
288      if $verbose;
289  $cmd_swap_gates{$refs[0]} = $refs[1];
290
291}
292
293#---------------------------------
294# parseSWPPINS(line)
295#---------------------------------
296
297sub parseSWPPINS {
298  my $line = shift(@_);
299  @refs = split ' ',,$line;
300  @pins = split '\.',,$refs[1];
301
302  print "parseSWPPINS():  Scheduling swap of pins on $refs[0] : pins ",
303  "$pins[0] and $pins[1]\n" if $verbose;
304  $cmd_swap_pins{$refs[0]} = $refs[1];
305
306}
307
308#---------------------------------
309# usage()
310#
311# prints program usage
312#---------------------------------
313
314sub usage {
315  my $pname = $0;
316  $pname =~ s/.*\///g;
317
318  print "Usage:\n\n";
319  print "\t$pname [-n|--nocopy] [-v|--verbose] change.eco file1.sch [file2.sch [file3.sch ... ] ]\n";
320  print "\t$pname -h|--help\n";
321  print "\t$pname -V|--version\n";
322  print "\n";
323  print "$pname reads a PADS PowerPCB ECO file and backannotates changes\n";
324  print "to a gEDA schematic.\n";
325  print "\n";
326  print "$pname accepts the following options:\n";
327  print "\n";
328  print "    -h|--help      Displays this help message.\n";
329  print "\n";
330  print "    -n|--nocopy    If given, this flag leaves the modified files in new files\n";
331  print "                whose names are generated by appending a \".new\" to the\n";
332  print "                original file names.  The default is to overwrite the original.\n";
333  print "\n";
334  print "    -v|--verbose   Enables verbose output.\n";
335  print "\n";
336  print "    -V|--version   Shows the version of this program.\n";
337  print "\n\n";
338  print "$pname was written by Dan McMahill <dmcmahill\@netbsd.org>\n";
339  print "\n\n";
340  exit;
341}
342
343#---------------------------------
344# version()
345#
346# prints program version
347#---------------------------------
348
349sub version {
350  open(PROG,"$0") or die "Could not open \"$0\" to find version\n\n";
351  my $pname = $0;
352  $pname =~ s/.*\///g;
353
354  while($line = <PROG>) {
355    if( $line =~ /^#\s*\$Id.*\$/) {
356      @words = split ' ',,$line;
357      $version = $words[3];
358      $date = $words[4];
359      print "$pname ($0):  Version $version, $date\n";
360      exit;
361    }
362  }
363  print "Could not determine version of \"$0\"\n\n";
364  exit;
365}
366
367# ----------------------------------------------
368#
369# Change Log
370#
371# $Log$
372# Revision 1.1  2003-08-31 21:39:52  ahvezda
373# Added pads_backannotate perl script
374#
375# Revision 1.4  2003/07/19 04:34:55  dan
376# bring this program up to a usable state.  Refdes renumbering is fully
377# supported and pin/gate swapping while not supported, gives a report of
378# the manual swaps needed.
379#
380# Revision 1.3  2003/03/03 03:44:26  dan
381# Finish up code to handle the RENPART .eco directive.  The output files
382# are still not written, but everything else is in place to handle backannotation
383# of reference designator renumbers.
384#
385# Revision 1.2  2003/02/21 12:30:30  dan
386# fix perl path
387#
388# Revision 1.1  2003/02/19 23:31:50  dan
389# start (non functional so far) of a pads to gschem backannotation tool
390#
391#
392#
393