Imported Upstream version 2.9.0
[debian/cc1111] / support / scripts / inc2h.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 # Copyright (c) 2002 Kevin L. Pauba
6
7
8 # License:
9 #
10 # SDCC is licensed under the GNU Public license (GPL) v2.  Note that
11 # this license covers the code to the compiler and other executables,
12 # but explicitly does not cover any code or objects generated by sdcc.
13 # We have not yet decided on a license for the run time libraries, but
14 # it will not put any requirements on code linked against it. See:
15 #
16 # http://www.gnu.org/copyleft/gpl.html
17 #
18 # See http://sdcc.sourceforge.net/ for the latest information on sdcc.
19
20 #####################################################################
21 # >>> How to add a new device to SDCC PIC14 port?
22 #
23 # This description assumes that you have a copy of SDCC's sources
24 # in /path/to/sdcc and a (source or installed) version of gputils
25 # in /path/to/gputils (the only important point here is that
26 # /path/to/gputils/headers must exist and contain "p<DEVICE>.inc").
27 # Furthermore, I assume you want to add support for the 16f887 device
28 # (note: no 'pic' or 'p' prefix!), change this as desired.
29 # inc2h.pl can only deal with one single device at a time; repeat the
30 # ../inc2h.pl-step as often as required.
31 #
32 # The proposed sequence of commands is then:
33 #
34 # $ cd /path/to/sdcc/support/scripts
35 # $ mkdir build && cd build
36 # $ ../inc2h.pl 16f887 /path/to/gputils
37 # $ mv pic16f887.c /path/to/sdcc/device/lib/pic/libdev
38 # $ mv pic16f887.h /path/to/sdcc/device/include/pic
39 # $ vim /path/to/sdcc/device/include/pic/pic14devices.inc
40
41 # # Use any pure text editor you like (`[Esc]:q![Enter]' quits Vim ;-)).
42 # # Add a record for the new device to the file; usually you can copy
43 # # the record of a similar device and adjust the values using the
44 # # datasheet. The format of pic14devices.txt is explained in the file
45 # # itself. Please keep the file sorted.
46 # # When you are done:
47 #
48 # $ cd /path/to/sdcc/device/lib
49 # $ make model-pic14
50 # $ make install 
51 #
52 # Congratulations, you have just added support for a new device to
53 # the port. You may consider posting your (changes to)
54 # pic14devices.txt and the generated files (picDEVICE.[ch]) to
55 # have them included into the official source tree.
56 # Some testing beforehand would be appreciated, though.
57 #####################################################################
58
59 my $rcsid = q~$Id: inc2h.pl 4850 2007-06-12 21:49:18Z tecodev $~;
60 my ($junk, $file, $version, $date, $time, $programmer, $status)
61     = split(/\s+/, $rcsid);
62 my ($programName) = ($file =~ /(\S+)/);
63
64 if ($#ARGV < 0 || $#ARGV > 1 ) {
65     Usage();
66 }
67 my $processor = uc(shift);
68 my $path = shift;
69 my %sfrs = ();
70 my %alias = ();
71 my %bits = ();
72 my %bitmasks = ();
73 my %addr = ();
74 my %ram = ();
75 my $path_delim = "/";
76 my $devices = "";
77 my %types = ();
78 my $type = "";
79
80 # just in time fixes for some register names
81 sub fixname {
82     my $name = shift;
83     $name =~ s/COMCON/CMCON/ig;
84     # use OPTION_REG instead of OPTION as OPTION is a assembler directive
85     $name =~ s/OPTION(_REG)?/OPTION_REG/ig;
86     # often declared as LCDDATn, but bits defined for LCDDATAn, 0 <= n <= 10
87     $name =~ s/LCDDAT([^A])/LCDDATA$1/ig;
88     # LCDSE2 is missing in some headers, but LCDSE3 is declared...
89     $name =~ s/LCDSE3/LCDSE2/ig;
90     # XXX: should this be named LININTF or LINPRT?
91     $name =~ s/LININTF/LINPRT/ig;
92     # FIXME: duplicate declarations for n in {0,1,2}
93     $name =~ s/UEPn/UEP0/ig;
94
95     return $name;
96 }
97
98 sub checkname {
99     my $name = shift;
100     if (not exists $sfrs{$name}) {
101         print "SFR $name not defined (yet).\n";
102         # Find similar ones.
103         if (exists $sfrs{$name."0"}) {
104             print "  but ".$name."0 exists---using that instead.\n";
105             return $name."0";
106         }
107         my $try = $name;
108         $try =~ s/[0-9]$//;
109         if (exists $sfrs{$try}) {
110             print "  but $try exists---using that instead.\n";
111             return $try;
112         }
113         die "Not found a similar SFR---aborting.\n";
114     }
115     return $name;
116 }
117
118 # exists clone for arrays---does this not exist in Perl?!?
119 sub contained {
120     my $name = shift;
121     my $arr = shift;
122
123     foreach my $item (@$arr) {
124         return 1 if ($name eq $item); 
125     }
126     return 0;
127 }
128
129
130 $path = "" if (!defined $path);
131 if ($^O eq 'MSWin32') {
132     if ($path eq '') {
133         if (defined($path = $ENV{'GPUTILS_HEADER_PATH'}) || defined($path = $ENV{'GPUTILS_LKR_PATH'})) {
134             $path .= '\\..';
135         }
136         else {
137             die "Could not find gpasm includes.\n";
138         }
139     }
140     $path_delim = '\\';
141 }
142 else {
143     # Nathan Hurst <njh@mail.csse.monash.edu.au>: find gputils on Debian
144     if ($path eq '') {
145         if ( -x "/usr/share/gputils") {
146             $path = "/usr/share/gputils";
147         } elsif ( -x "/usr/share/gpasm") {
148             $path = "/usr/share/gpasm";
149         } elsif ( -x "/usr/local/share/gputils") {
150             $path = "/usr/local/share/gputils";
151         } else {
152             die "Could not find gpasm includes.\n";
153         }
154     }
155     $path_delim = '/';
156 }
157
158 #
159 # Read the symbols at the end of this file.
160 #
161 while (<DATA>) {
162     next if /^\s*#/;
163
164     if (/^\s*alias\s+(\S+)\s+(\S+)/) {
165         #
166         # Set an alias for a special function register.
167         # Some MPASM include files are not entirely consistent
168         # with sfr names.
169         #
170         $alias{fixname($2)} = fixname($1);
171     } elsif (/^\s*address\s+(\S+)\s+(\S+)/) {
172         #
173         # Set a default address for a special function register.
174         # Some MPASM include files don't specify the address
175         # of all registers.
176         # 
177         # $addr{"$1"} = $2;
178         foreach my $device (split(/[,\s]+/, $devices)) {
179             $addr{"p$device", "$1"} = $2;
180         }
181     } elsif (/^\s*bitmask\s+(\S+)\s+/) {
182         #
183         # Set the bitmask that will be used in the 'memmap' pragma.
184         #
185         my $bitmask = "$1";
186         foreach my $register (split(/\s+/, $')) {
187             $bitmasks{"$register"} = $bitmask;
188         }
189     } elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) {
190         # This info is now provided in "include/pic/pic14devices.txt".
191         #$lo = $1;
192         #$hi = $2;
193         #my $bitmask = $3;
194         #foreach $device (split(/[,\s]+/, $devices)) {
195         #    $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
196         #}
197     } elsif (/^\s*processor\s+/) {
198         $devices = $';
199         $type = '';
200     } elsif (/^\s*(\S+)/) {
201         $type = $1;
202         $_ = $';
203         foreach my $key (split) {
204             eval "\$types{'$key'} = $type;";
205         }
206     } else {
207         foreach my $key (split) {
208             eval "\$types{'$key'} = $type;";
209         }
210     }
211 }
212
213 #
214 # Read the linker file.
215 #
216 #  $linkFile = "$path/lkr/" . lc $processor . ".lkr";
217 #  open(LINK, "<$linkFile")
218 #      || die "$programName: Error: Cannot open linker file $linkFile ($!)\n";
219 #  while (<LINK>) {
220 #      if (/^(\S+)\s+NAME=(\S+)\s+START=(\S+)\s+END=(\S+)\s+(PROTECTED)?/) {
221 #       $type = $1;
222 #       $name = $2;
223 #       $start = $3;
224 #       $end = $4;
225 #       $protected = 1 if ($5 =~ /protected/i);
226
227 #       if ($type =~ /(SHAREBANK)|(DATABANK)/i) {
228 #           $ram{"p$processor"} .=
229 #               sprintf("#pragma memmap %7s %7s RAM 0x000\t// $name\n",
230 #                       $start, $end);
231 #       }
232 #      } elsif (/^SECTION\s+NAME=(\S+)\s+ROM=(\S+)\s+/) {
233 #      }
234 #  }
235
236 # Create header for pic${processor}.c file
237 my $lcproc = "pic" . lc($processor);
238 my $c_head = <<EOT;
239 /* Register definitions for $lcproc.
240  * This file was automatically generated by:
241  *   $programName V$version
242  *   Copyright (c) 2002, Kevin L. Pauba, All Rights Reserved
243  */
244 #include <${lcproc}.h>
245
246 EOT
247
248 #
249 # Convert the file.
250 #
251 my $defaultType = 'other';
252 my $includeFile = $path.$path_delim.'header'.$path_delim.'p'.lc($processor).'.inc';
253 my $headFile = "pic" . lc($processor) . ".h";
254 my $defsFile = "pic" . lc($processor) . ".c";
255
256 my $body = "";
257 my $header = "";
258 my $addresses = "";
259 my $pragmas = "";
260
261 open(HEADER, "<$includeFile")
262     || die "$programName: Error: Cannot open include file $includeFile ($!)\n";
263
264 while (<HEADER>) {
265     
266     if (/^;-+ Register Files/i) {
267         $defaultType = 'sfr';
268         s/;/\/\//;
269         $body .= "$_";
270     } elsif (/^;-+\s*(\S+)\s+Bits/i || /^;-+\s*(\S+)\s+-+/i) {
271         # The second case is usually bits, but the word Bits is missing
272         # also accept "UIE/UIR Bits"
273         foreach my $name (split(/\//, $1)) {
274             $name = fixname($name);
275             $name = checkname($name);
276
277             if (defined($alias{$name})) {
278                 $defaultType = "bits $alias{$name}";
279             } else {
280                 $defaultType = "bits $name";
281             }
282         }
283         s/;/\/\//;
284         $body .= "$_";
285     } elsif (/^;=+/i) {
286         $defaultType = '';
287         s/;/\/\//;
288         $body .= "$_";
289     } elsif (/^\s*;/) {
290         #
291         # Convert ASM comments to C style.
292         #
293         $body .= "//$'";
294     } elsif (/^\s*IFNDEF\s+__(\S+)/) {
295         #
296         # Processor type.
297         #
298         $processor = $1;
299         $body .= "//$_";
300     } elsif (/^\s*(\S+)\s+EQU\s+H'(.+)'/) {
301         #
302         # Useful bit of information.
303         #
304         my $name = $1;
305         my $value = $2;
306         my $rest = $';
307         my $bitmask = "0x0000";
308
309         $rest =~ s/;/\/\//;
310         chomp($rest);
311
312         if (defined($types{"p$processor", "$name"})) {
313             $type = $types{"p$processor", "$name"};
314         } elsif (defined($types{"$name"})) {
315             $type = $types{"$name"};
316         } else {
317             $type = $defaultType;
318         }
319         #print "$name --> $type\n"; ## DEBUG
320
321         if (defined($bitmasks{"p$processor", "$name"})) {
322             $bitmask = $bitmasks{"p$processor", "$name"};
323 #       } elsif (defined($bitmasks{"$name"})) {
324 #           $bitmask = $bitmasks{"$name"};
325         }
326
327         if ($type eq 'sfr') {
328             #
329             # A special function register.
330             #
331 #           $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
332 #                               . "SFR %s\t// %s\n",
333 #                               $name, $name, $bitmask, $name);
334             $name = fixname($name);
335             if (defined $addr{"p$processor", "$name"}) {
336                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
337             } else {
338                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
339             }
340             $body .= sprintf("extern __sfr  __at %-30s $name;$rest\n", "(${name}_ADDR)" );
341             $c_head .= sprintf("__sfr  __at %-30s $name;\n", "(${name}_ADDR)");
342             $addr{"p$processor", "$name"} = "0x$value";
343             $sfrs{$name}=1;
344         } elsif ($type eq 'volatile') {
345             #
346             # A location that can change without 
347             # direct program manipulation.
348             #
349             $name = fixname($name);
350 #           $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
351 #                               . "SFR %s\t// %s\n",
352 #                               $name, $name, $bitmask, $name);
353             $body .= sprintf("extern __data __at %-30s $name;$rest\n", "(${name}_ADDR) volatile char");
354             $c_head .= sprintf("__data __at %-30s $name;\n", "(${name}_ADDR) volatile char");
355             if (defined $addr{"p$processor", "$name"}) {
356                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
357             } else {
358                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
359             }
360         } elsif ($type =~ /^bits/) {
361             my ($junk, $register) = split(/\s/, $type);
362             my $bit = hex($value);
363             my $addr = $addr{"$register"};
364
365             # prepare struct declaration
366             if (0) { # DEBUG
367                 foreach my $key (keys %bits) {
368                     print "   $key\n";
369                 }
370                 print "$register // $bit // ".$bits{"$register"}."\n";
371             }
372             if (!defined $bits{"$register"}) {
373                 $bits{"$register"} = {}; # reference to empty hash
374             }
375             if (!defined $bits{"$register"}->{oct($bit)}) {
376                 $bits{"$register"}->{oct($bit)} = []; # reference to empty array
377             }
378             for (my $k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) {
379               $name = "" if ($bits{"$register"}->{oct($bit)} eq $name)
380             }
381             if (($name ne "")
382                 and (1 != contained($name, \@{$bits{"$register"}->{oct($bit)}}))
383             ) {
384               push @{$bits{"$register"}->{oct($bit)}}, $name;
385             }
386         } else {
387             #
388             # Other registers, bits and/or configurations.
389             #
390             $name = fixname($name);
391             if ($type eq 'other') {
392                 #
393                 # A known symbol.
394                 #
395                 $body .= sprintf("#define %-20s 0x%s$rest\n", $name, $value);
396             } else {
397                 #
398                 # A symbol that isn't defined in the data
399                 # section at the end of the file.  Let's 
400                 # add a comment so that we can add it later.
401                 #
402                 $body .= sprintf("#define %-20s 0x%s$rest\n",
403                                  $name, $value);
404             }
405         }
406     } elsif (/^\s*$/) {
407         #
408         # Blank line.
409         #
410         $body .= "\n";
411     } elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) {
412         my $maxram .= "//\n// Memory organization.\n//\n";
413         if (!defined $ram{"p$processor"}) {
414             $ram{"p$processor"} = "";
415         }
416         $pragmas = $maxram
417             . $ram{"p$processor"} . "\n"
418                 . $pragmas;
419         $body .= "// $_";
420     } else {
421         #
422         # Anything else we'll just comment out.
423         #
424         $body .= "// $_";
425     }
426 }
427 $header .= <<EOT;
428 //
429 // Register Declarations for Microchip $processor Processor
430 //
431 //
432 // This header file was automatically generated by:
433 //
434 //\t$programName V$version
435 //
436 //\tCopyright (c) 2002, Kevin L. Pauba, All Rights Reserved
437 //
438 //\tSDCC is licensed under the GNU Public license (GPL) v2.  Note that
439 //\tthis license covers the code to the compiler and other executables,
440 //\tbut explicitly does not cover any code or objects generated by sdcc.
441 //\tWe have not yet decided on a license for the run time libraries, but
442 //\tit will not put any requirements on code linked against it. See:
443 // 
444 //\thttp://www.gnu.org/copyleft/gpl/html
445 //
446 //\tSee http://sdcc.sourceforge.net/ for the latest information on sdcc.
447 //
448 // 
449 #ifndef P${processor}_H
450 #define P${processor}_H
451
452 //
453 // Register addresses.
454 //
455 EOT
456
457 $c_head .= <<EOT;
458
459 // 
460 // bitfield definitions
461 // 
462 EOT
463
464 # Add PORT* and TRIS* bit entries
465 # file format is:
466 #    16f84   A0-4,B0-7
467 #    *       A0-5,B0-7,C0-7,D0-7,E0-2
468 {
469   my $pinfo = undef;
470   my $defpinfo = undef;
471   open(P14PORTS, "< pic14ports.txt") && do {
472     while(<P14PORTS>) {
473         s/\r//g; chomp;
474         if(/^\s*(\*|\w*)\s*([ABCDE0-7,-]+)\s*$/) {
475             if(lc($1) eq lc($processor)) {
476                 die if defined $pinfo;
477                 $pinfo = $2;
478             } elsif($1 eq "*") {
479                 die if defined $defpinfo;
480                 $defpinfo = $2;
481             }
482         } elsif(/^\s*#/ || /^\s*$/) {
483             # ignore blanks, comments
484         } else {
485             die "bad line in pic14ports '$_'";
486         }
487     }
488     close P14PORTS;
489   };
490   $defpinfo = "A0-5,B0-7,C0-7,D0-7,E0-2" unless defined $defpinfo;
491   $pinfo = $defpinfo unless defined $pinfo;
492
493   if(defined $pinfo) {
494     foreach  (split /,/, $pinfo) {
495         if(/^([ABCDE])([0-7])-([0-7])$/) {
496             my($prt, $low, $high) = ($1, $2, $3);
497             next unless defined $sfrs{"PORT$prt"} && defined $sfrs{"TRIS$prt"};
498             next if     defined $bits{"PORT$prt"};
499             for(my $i = $low; $i <= $high; $i++) {
500                 push @{$bits{"PORT$prt"}->{oct($i)}}, "R$prt".$i;
501             }
502             next if     defined $bits{"TRIS$prt"};
503             for(my $i = $low; $i <= $high; $i++) {
504                 push @{$bits{"TRIS$prt"}->{oct($i)}}, "TRIS$prt".$i;
505             }
506         } else { die }
507     }
508   }
509 }
510
511 my $structs = "";
512 ## create struct declarations
513 foreach my $reg (sort keys %bits)
514 {
515   $structs .= "// ----- $reg bits --------------------\n";
516   $structs .= "typedef union {\n";
517   my $idx = 0;
518   my $max = 1;
519   do {
520     $structs .= "  struct {\n";
521     for (my $i=0; $i < 8; $i++)
522     {
523       if (!defined $bits{$reg}) {
524           #print "bits{$reg} undefined\n";
525       }
526       if (!defined $bits{$reg}->{oct($i)}) {
527           #print "bits{$reg}->{".oct($i)."} undefined\n";
528           $bits{$reg}->{oct($i)} = []; # empty array reference
529       }
530       my @names = @{$bits{$reg}->{oct($i)}};
531       if ($max < scalar @names) { $max = scalar @names; }
532       if ($idx >= scalar @names) {
533         $structs .= "    unsigned char :1;\n";
534       } else { # (1 == scalar @names) {
535         $structs .= "    unsigned char " . $names[$idx] . ":1;\n";
536 #      } else {
537 #       $structs .= "  union {\n";
538 #       foreach $name (@names) {
539 #         $structs .= "    unsigned char " . $name . ":1;\n";
540 #       } # foreach
541 #       $structs .= "  };\n";
542       }
543     } # for
544     $structs .= "  };\n";
545     $idx++;
546   } while ($idx < $max);
547   $structs .= "} __${reg}_bits_t;\n";
548   #if(defined $sfrs{$reg}) {
549     $structs .= "extern volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n\n";
550     $c_head .= "volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n";
551   #}
552   
553   # emit defines for individual bits
554   $structs .= "#ifndef NO_BIT_DEFINES\n";
555   for (my $i=0; $i < 8; $i++)
556   {
557     my @names = @{$bits{$reg}->{oct($i)}};
558     foreach my $field (@names) {
559       $structs .= sprintf("#define %-20s ${reg}_bits.$field\n", $field);
560     } # foreach
561   }
562   $structs .= "#endif /* NO_BIT_DEFINES */\n";
563   $structs .= "\n";
564 } # foreach
565
566 open(HEAD, ">$headFile") or die "Could not open $headFile for writing.";
567 print HEAD $header
568     . $addresses . "\n"
569     . $pragmas . "\n\n"
570     . $body . "\n"
571     . $structs
572     . "#endif\n";
573 close(HEAD);
574
575 open(DEFS, ">$defsFile") or die "Could not open $defsFile for writing.";
576 print DEFS $c_head . "\n";
577 close DEFS;
578
579 sub Usage {
580         print STDERR <<EOT;
581
582 inc2h.pl - A utility to convert MPASM include files to header files
583            suitable for the SDCC compiler.
584
585 License: Copyright (c) 2002 Kevin L. Pauba
586
587          SDCC is licensed under the GNU Public license (GPL) v2; see
588          http://www.gnu.org/copyleft/gpl.html See http://sdcc.sourceforge.net/
589          for the latest information on sdcc.
590
591 Usage:   $programName processor [path]
592
593          where:
594
595          processor      The name of the processor (16f84, 16f877, etc.)
596
597          path           The path to the parent of the "header" and "lkr"
598                         directories.  The default is "/usr/share/gpasm".
599
600          The header file will be written to the standard output.
601
602          $#ARGV
603 EOT
604         exit;
605 }
606
607 __END__
608
609 #
610 # processor <processor_name>
611 # address <register_name> <hex_address>
612 # bitmask <bitmask> <register_list>
613 # ram <lo_address> <hi_address> <bitmask>
614 # sfr <register_list>
615 # volatile <address_list>
616 # bit <address_list>
617 #
618
619 alias OPTION_REG OPTION
620 volatile INDF PCL