5.4.1 updates for make allhds/allzhds
[etherboot.git] / src / genrules.pl
1 #!/usr/bin/perl -w
2 #
3 #       Helper program to generate Makefile rules into file Rom from table in
4 #       file NIC
5 #
6 #       GPL, Ken Yap 2001, with major contributions by Klaus Espenlaub
7 #       Revised 2002
8 #
9
10 use strict;
11
12 use bytes;
13
14 use File::Basename;
15
16 use vars qw($familyfile $nic @families $curfam %drivers %pcient %isaent %isalist %buildent $arch @srcs);
17
18 sub __gendep ($$$)
19 {
20         my ($file, $deps, $driver_dep) = @_;
21         foreach my $source (@$deps) {
22                 my $inc;
23                 my @collect_dep = ();
24                 $inc = "arch/$arch/include/$source" unless ! -e "arch/$arch/include/$source";
25                 $inc = "include/$source" unless ! -e "include/$source";
26                 $inc = dirname($file) . "/$source" unless ! -e dirname($file) . "/$source";
27                 unless (defined($inc)) {
28                         print STDERR "$source from $file not found (shouldn't happen)\n";
29                         next;
30                 };
31                 next if (exists ${$driver_dep}{$inc});
32                 ${$driver_dep}{$inc} = $inc;
33 # Warn about failure to open, then skip, rather than soldiering on with the read
34                 unless (open(INFILE, "$inc")) {
35                         print STDERR "$inc: $! (shouldn't happen)\n";
36                         next;
37                 };
38                 while (<INFILE>) {
39                         chomp($_);
40 # This code is not very smart: no C comments or CPP conditionals processing is
41 # done.  This may cause unexpected (or incorrect) additional dependencies.
42 # However, ignoring the CPP conditionals is in some sense correct: we need to
43 # figure out a superset of all the headers for the driver source.  
44                         next unless (s/^\s*#include\s*"([^"]*)".*$/$1/);
45 # Ignore system includes, like the ones in osdep.h
46                         next if ($_ =~ m:^/:);
47 # Ignore "special" includes, like .buildserial.h
48                         next if /^\./;
49                         push(@collect_dep, $_);
50                 }
51                 close(INFILE);
52                 if (@collect_dep) {
53                         &__gendep($inc, \@collect_dep, $driver_dep);
54                 }
55         }
56 }
57
58 sub gendep ($) {
59         my ($driver) = @_;
60
61         # Automatically generate the dependencies for the driver sources.
62         my %driver_dep = ();
63         __gendep( "", [ $driver ], \%driver_dep);
64         return sort values %driver_dep
65 }
66
67 # Make sure that every rom name exists only once.
68 # make will warn if it finds duplicate rules, but it is better to stop
69 sub checkduplicate (\%$$) {
70         my ($anyent, $curfam, $romname) = @_;
71         foreach my $family (@families) {
72                 if (exists($$anyent{$family})) {
73                         my $aref = $$anyent{$family};
74                         foreach my $entry (@$aref) {
75                                 if ($entry->[0] eq $romname) {
76                                         print STDERR "\nROM name $romname defined twice. Please correct.\n";
77                                         exit 1;
78                                 }
79                         }
80                 }
81         }
82 }
83
84 sub genroms($) {
85         my ($driver) = @_;
86         
87         # Automatically discover the ROMS this driver can produce.
88         unless (open(INFILE, "$driver")) {
89                 print STDERR "$driver: %! (shouldn't happen)\n";
90                 next;
91         };
92         while (<INFILE>) {
93                 chomp($_);
94                 if ($_ =~ m/^\s*PCI_ROM\(\s*0x([0-9A-Fa-f]*)\s*,\s*0x([0-9A-Fa-f]*)\s*,\s*"([^"]*)"\s*,\s*"([^"]*)"\)/) {
95
96                         # We store a list of PCI IDs and comments for each PC target
97                         my ($vendor_id, $device_id, $rom, $comment) = (hex($1), hex($2), $3, $4);
98                         my $ids = sprintf("0x%04x,0x%04x", $vendor_id, $device_id);
99                         checkduplicate(%pcient, $curfam, $rom);
100                         push(@{$pcient{$curfam}}, [$rom, $ids, $comment]);
101                 }
102                 elsif($_ =~ m/^\s*ISA_ROM\(\s*"([^"]*)"\s*,\s*"([^"]*)"\)/) {
103                         my ($rom, $comment) = ($1, $2);
104                         # We store the base driver file for each ISA target
105                         $isalist{$rom} = $curfam;
106                         $buildent{$rom} = 1;
107                         checkduplicate(%isaent, $curfam, $rom);
108                         push(@{$isaent{$curfam}}, [$rom, $comment]);
109                 }
110                 elsif($_ =~ m/^\s*PCI_ROM/ or $_ =~ m/^\s*ISA_ROM/) {
111                         # Complain since we cannot parse this. Of course it would be nicer if we could parse...
112                         print STDERR "\nFound incomplete PCI_ROM or ISA_ROM macro in file $driver.\n";
113                         print STDERR "ROM macros spanning more than one line are not supported,\n";
114                         print STDERR "please adjust $driver accordingly.\n\n\n";
115                         exit 1;
116                 }
117         }
118 }
119
120 sub addfam ($) {
121         my ($family) = @_;
122
123         push(@families, $family);
124         # We store the list of dependencies in the hash for each family
125         my @deps = &gendep("$family.c");
126         $drivers{$family} = join(' ', @deps);
127         $pcient{$family} = [];
128         genroms("$family.c");
129 }
130
131 sub addrom ($) {
132         my ($rom, $ids, $comment) = split(' ', $_[0], 3);
133
134         # defaults if missing
135         $ids = '-' unless ($ids);
136         $comment = $rom unless ($comment);
137         if ($ids ne '-') {
138                 # We store a list of PCI IDs and comments for each PCI target
139                 checkduplicate(%pcient, $curfam, $rom);
140                 push(@{$pcient{$curfam}}, [$rom, $ids, $comment]);
141         } else {
142                 # We store the base driver file for each ISA target
143                 $isalist{$rom} = $curfam;
144                 $buildent{$rom} = 1;
145                 checkduplicate(%isaent, $curfam, $rom);
146                 push(@{$isaent{$curfam}}, [$rom, $comment]);
147         }
148 }
149
150 # Return true if this driver is ISA only
151 sub isaonly ($) {
152         my $aref = $pcient{$_[0]};
153
154         return ($#$aref < 0);
155 }
156
157 $#ARGV >= 1 or die "Usage: $0 Families bin/NIC arch sources...\n";
158 $familyfile = shift(@ARGV);
159 $nic  = shift(@ARGV);
160 $arch = shift(@ARGV);
161 @srcs = @ARGV;
162 open FAM, "<$familyfile" or die "Could not open $familyfile: $!\n";
163
164 $curfam = '';
165 while ( <FAM> ) {
166         chomp($_);
167         next if (/^\s*(#.*)?$/);
168         my ($keyword) = split(' ', $_ , 2);
169         if ($keyword eq 'family') {
170                 my ($keyword, $driver) = split(' ', $_, 2);
171                 $curfam = '';
172                 if (! -e "$driver.c") {
173                         print STDERR "Driver file $driver.c not found, skipping...\n";
174                         next;
175                 }
176                 if ($driver =~ "^arch" && $driver !~ "^arch/$arch") {
177 # This warning just makes noise for most compilations.
178 #                       print STDERR "Driver file $driver.c not for arch $arch, skipping...\n";
179                         next;
180                 }
181                 &addfam($curfam = $driver);
182         } else {
183                 # skip until we have a valid family
184                 next if ($curfam eq '');
185                 &addrom($_);
186         }
187 }
188 close FAM;
189
190 open(N,">$nic") or die "$nic: $!\n";
191 print N <<EOF;
192 # This is an automatically generated file, do not edit
193 # It does not affect anything in the build, it's only for rom-o-matic
194
195 EOF
196 foreach my $family (@families) {
197         print N "family\t$family\n";
198         if (exists($pcient{$family})) {
199                 my $aref = $pcient{$family};
200                 foreach my $entry (@$aref) {
201                         my $rom = $entry->[0];
202                         my $ids = $entry->[1];
203                         my $comment = $entry->[2];
204                         print N "$rom\t$ids\t$comment\n";
205                 }
206         }
207         if (exists($isaent{$family})) {
208                 my $aref = $isaent{$family};
209                 foreach my $entry (@$aref) {
210                         my $rom = $entry->[0];
211                         my $comment = $entry->[1];
212                         print N "$rom\t-\t$comment\n";
213                 }
214         }
215         print N "\n";
216 }
217 close(N);
218
219 # Generate the normal source dependencies
220 print "# Core object file dependencies\n";
221 foreach my $source (@srcs) {
222         next if ($source !~ '[.][cS]$');
223         my @deps = &gendep($source);
224         my $obj = $source;
225         $obj =~ s/^.*?([^\/]+)\.[cS]/bin\/$1.o/;
226         foreach my $dep (@deps) {
227                 print "$obj: $dep\n";
228         }
229         print("\n");
230 }
231
232 # Generate the assignments to DOBJS and BINS
233 print "# Driver object files and ROM image files\n";
234 print "DOBJS\t:=\n";
235 print "PCIOBJS\t:=\n";
236
237 print "# Target formats\n";
238 print "EB_ISOS\t:=\n";
239 print "EB_LISOS\t:=\n";
240 print "EB_COMS\t:=\n";
241 print "EB_EXES\t:=\n";
242 print "EB_LILOS\t:=\n";
243 print "EB_ZLILOS\t:=\n";
244 print "EB_PXES\t:=\n";
245 print "EB_ZPXES\t:=\n";
246 print "EB_DSKS\t:=\n";
247 print "EB_ZDSKS\t:=\n";
248 print "EB_HDS\t:=\n";
249 print "EB_ZHDS\t:=\n";
250 print "EB_ELFS\t:=\n";
251 print "EB_ZELFS\t:=\n";
252 print "EB_LMELFS\t:=\n";
253 print "EB_ZLMELFS\t:=\n";
254 print "EB_ELFDS\t:=\n";
255 print "EB_ZELFDS\t:=\n";
256 print "EB_LMELFDS\t:=\n";
257 print "EB_ZLMELFDS\t:=\n";
258
259 foreach my $pci (sort keys %pcient) {
260         my $img = basename($pci);
261
262         print "DOBJS\t+= \$(BIN)/$img.o\n";
263         print "PCIOBJS\t+= \$(BIN)/$img.o\n" unless isaonly($pci);
264
265 # Output targets
266         print "EB_LILOS\t+= \$(BIN)/$img.lilo \nEB_ZLILOS\t+= \$(BIN)/$img.zlilo\n";
267         print "EB_PXES\t+= \$(BIN)/$img.pxe   \nEB_ZPXES\t+= \$(BIN)/$img.zpxe\n";
268         print "EB_DSKS\t+= \$(BIN)/$img.dsk   \nEB_ZDSKS\t+= \$(BIN)/$img.zdsk\n";
269         print "EB_HDS\t+= \$(BIN)/$img.hd   \nEB_ZHDS\t+= \$(BIN)/$img.zhd\n";
270         print "EB_ELFS\t+= \$(BIN)/$img.elf   \nEB_ZELFS\t+= \$(BIN)/$img.zelf\n";
271         print "EB_LMELFS\t+= \$(BIN)/$img.lmelf \nEB_ZLMELFS\t+= \$(BIN)/$img.zlmelf\n";
272         print "EB_ELFDS\t+= \$(BIN)/$img.elfd   \nEB_ZELFDS\t+= \$(BIN)/$img.zelfd\n";
273         print "EB_LMELFDS\t+= \$(BIN)/$img.lmelfd \nEB_ZLMELFDS\t+= \$(BIN)/$img.zlmelfd\n";
274         print "EB_BIMAGES\t+= \$(BIN)/$img.bImage \nEB_BZIMAGES\t+= \$(BIN)/$img.bzImage\n";
275         print "EB_ISOS\t+= \$(BIN)/$img.iso\n";
276         print "EB_LISOS\t+= \$(BIN)/$img.liso\n";
277         print "EB_COMS\t+= \$(BIN)/$img.com\n";
278         print "EB_EXES\t+= \$(BIN)/$img.exe\n";
279 }
280
281 foreach my $img (sort keys %buildent) {
282
283         print "DOBJS\t+= \$(BIN)/$img.o\n";
284
285 # Output targets
286         print "EB_LILOS\t+= \$(BIN)/$img.lilo \nEB_ZLILOS\t+= \$(BIN)/$img.zlilo\n";
287         print "EB_PXES\t+= \$(BIN)/$img.pxe   \nEB_ZPXES\t+= \$(BIN)/$img.zpxe\n";
288         print "EB_DSKS\t+= \$(BIN)/$img.dsk   \nEB_ZDSKS\t+= \$(BIN)/$img.zdsk\n";
289         print "EB_HDS\t+= \$(BIN)/$img.hd   \nEB_ZHDS\t+= \$(BIN)/$img.zhd\n";
290         print "EB_ELFS\t+= \$(BIN)/$img.elf   \nEB_ZELFS\t+= \$(BIN)/$img.zelf\n";
291         print "EB_LMELFS\t+= \$(BIN)/$img.lmelf \nEB_ZLMELFS\t+= \$(BIN)/$img.zlmelf\n";
292         print "EB_ELFDS\t+= \$(BIN)/$img.elfd   \nEB_ZELFDS\t+= \$(BIN)/$img.zelfd\n";
293         print "EB_LMELFDS\t+= \$(BIN)/$img.lmelfd \nEB_ZLMELFDS\t+= \$(BIN)/$img.zlmelfd\n";
294         print "EB_BIMAGES\t+= \$(BIN)/$img.bImage \nEB_BZIMAGE\t+= \$(BIN)/$img.bzImage\n";
295         print "EB_ISOS\t+= \$(BIN)/$img.iso\n";
296         print "EB_LISOS\t+= \$(BIN)/$img.liso\n";
297         print "EB_COMS\t+= \$(BIN)/$img.com\n";
298         print "EB_EXES\t+= \$(BIN)/$img.exe\n";
299 }
300
301 print "ROMS\t:=\n";
302 foreach my $family (sort keys %pcient) {
303         my $aref = $pcient{$family};
304         foreach my $entry (@$aref) {
305                 my $rom = $entry->[0];
306                 print "ROMS\t+= \$(BIN)/$rom.rom \$(BIN)/$rom.zrom\n";
307         }
308 }
309 foreach my $isa (sort keys %isalist) {
310         print "ROMS\t+= \$(BIN)/$isa.rom \$(BIN)/$isa.zrom\n";
311 }
312
313 # Generate the *.o rules
314 print "\n# Rules to build the driver object files\n";
315 foreach my $pci (sort keys %drivers) {
316         # For ISA the rule for .o will generated later
317         next if isaonly($pci);
318         # PCI drivers are compiled only once for all ROMs
319         (my $macro = basename($pci)) =~ tr/\-/_/;
320         my $obj = basename($pci);
321         my $deps = $drivers{$pci};
322         print <<EOF;
323
324 \$(BIN)/$obj.o: $pci.c \$(MAKEDEPS) $deps
325         \$(CC) \$(CFLAGS) \$(\U$macro\EFLAGS) -o \$@ -c \$<
326
327 \$(BIN)/$obj--%.o:      \$(BIN)/%.o \$(BIN)/$obj.o \$(MAKEDEPS)
328         \$(LD) \$(LDFLAGS) -r \$(BIN)/$obj.o \$< -o \$@
329
330 EOF
331 }
332
333 # Do the ISA entries
334 foreach my $isa (sort keys %isalist) {
335         (my $macro = $isa) =~ tr/\-/_/;
336         my $base = $isalist{$isa};
337         my $deps = $drivers{$base};
338         print <<EOF;
339 \$(BIN)/$isa.o: $base.c \$(MAKEDEPS) $deps
340         \$(CC) \$(CFLAGS) \$(\U$macro\EFLAGS) -o \$@ -c \$<
341
342 \$(BIN)/$isa--%.o:      \$(BIN)/%.o \$(BIN)/$isa.o \$(MAKEDEPS)
343         \$(LD) \$(LDFLAGS) -r \$(BIN)/$isa.o \$< -o \$@ 
344 EOF
345 }
346
347 # Generate the Rom rules
348 print "# Rules to build the ROM files\n";
349 foreach my $family (sort keys %pcient) {
350         next if isaonly($family);
351         my $img = basename($family);
352         print <<EOF;
353 ROMTYPE_$img = PCI
354 EOF
355         my $aref = $pcient{$family};
356         foreach my $entry (@$aref) {
357                 my ($rom, $ids, $comment) = @$entry;
358                 next if ($ids eq '-');
359                 print <<EOF;
360 ROMTYPE_$rom = PCI
361 MAKEROM_ID_$rom = -p $ids
362
363 EOF
364                 next if($rom eq $img);
365                 print <<EOF;
366 \$(BIN)/$rom\%rom: \$(BIN)/$img\%rom
367         cat \$< > \$@
368         \$(MAKEROM) \$(MAKEROM_FLAGS) \$(MAKEROM_\$(ROMCARD)) \$(MAKEROM_ID_\$(ROMCARD)) -i\$(IDENT) \$@
369
370 EOF
371         }
372 }
373
374 # ISA ROMs are prepared from the matching code images
375 # Think this can probably be removed, but not sure
376 foreach my $isa (sort keys %isalist) {
377         print <<EOF;
378 EOF
379 }
380