2004-01-05 Vangelis Rokas <vrokas@otenet.gr>
[fw/sdcc] / support / scripts / inc2h.pl
1 #!/usr/bin/perl
2
3 # Copyright (c) 2002 Kevin L. Pauba
4
5
6 # License:
7 #
8 # SDCC is licensed under the GNU Public license (GPL) v2.  Note that
9 # this license covers the code to the compiler and other executables,
10 # but explicitly does not cover any code or objects generated by sdcc.
11 # We have not yet decided on a license for the run time libraries, but
12 # it will not put any requirements on code linked against it. See:
13
14 # http://www.gnu.org/copyleft/gpl.html
15 #
16 # See http://sdcc.sourceforge.net/ for the latest information on sdcc.
17
18
19 $rcsid = q~$Id$~;
20 ($junk, $file, $version, $date, $time, $programmer, $status)
21     = split(/\s+/, $rcsid);
22 ($programName) = ($file =~ /(\S+),v/);
23
24 if ($#ARGV < 0 || $#ARGV > 1 ) {
25     Usage();
26 }
27 $processor = shift;
28 $path = shift;
29
30 $processor = uc $processor;
31 # Nathan Hurst <njh@mail.csse.monash.edu.au>: find gputils on Debian
32 if ($path eq '') {
33     if ( -x "/usr/share/gputils") {
34        $path = "/usr/share/gputils";
35     } elsif ( -x "/usr/share/gpasm") {
36        $path = "/usr/share/gpasm";
37     } else {
38        die "Could not find gpasm includes.\n";
39     }
40 }
41
42 #
43 # Read the symbols at the end of this file.
44 #
45 while (<DATA>) {
46     next if /^\s*#/;
47
48     if (/^\s*alias\s+(\S+)\s+(\S+)/) {
49         #
50         # Set an alias for a special function register.
51         # Some MPASM include files are not entirely consistent
52         # with sfr names.
53         #
54         $alias{$2} = $1;
55     } elsif (/^\s*address\s+(\S+)\s+(\S+)/) {
56         #
57         # Set a default address for a special function register.
58         # Some MPASM include files don't specify the address
59         # of all registers.
60         # 
61         # $addr{"$1"} = $2;
62         foreach $device (split(/[,\s]+/, $devices)) {
63             $addr{"p$device", "$1"} = $2;
64         }
65     } elsif (/^\s*bitmask\s+(\S+)\s+/) {
66         #
67         # Set the bitmask that will be used in the 'memmap' pragma.
68         #
69         $bitmask = "$1";
70         foreach $register (split(/\s+/, $')) {
71             $bitmask{"$register"} = $bitmask;
72         }
73     } elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) {
74         $lo = $1;
75         $hi = $2;
76         $bitmask = $3;
77         foreach $device (split(/[,\s]+/, $devices)) {
78             $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
79         }
80     } elsif (/^\s*processor\s+/) {
81         $devices = $';
82         $type = '';
83     } elsif (/^\s*(\S+)/) {
84         $type = $1;
85         $_ = $';
86         foreach $key (split) {
87             eval "\$type{'$key'} = $type;";
88         }
89     } else {
90         foreach $key (split) {
91             eval "\$type{'$key'} = $type;";
92         }
93     }
94 }
95
96 #
97 # Read the linker file.
98 #
99 #  $linkFile = "$path/lkr/" . lc $processor . ".lkr";
100 #  open(LINK, "<$linkFile")
101 #      || die "$programName: Error: Cannot open linker file $linkFile ($!)\n";
102 #  while (<LINK>) {
103 #      if (/^(\S+)\s+NAME=(\S+)\s+START=(\S+)\s+END=(\S+)\s+(PROTECTED)?/) {
104 #       $type = $1;
105 #       $name = $2;
106 #       $start = $3;
107 #       $end = $4;
108 #       $protected = 1 if ($5 =~ /protected/i);
109
110 #       if ($type =~ /(SHAREBANK)|(DATABANK)/i) {
111 #           $ram{"p$processor"} .=
112 #               sprintf("#pragma memmap %7s %7s RAM 0x000\t// $name\n",
113 #                       $start, $end);
114 #       }
115 #      } elsif (/^SECTION\s+NAME=(\S+)\s+ROM=(\S+)\s+/) {
116 #      }
117 #  }
118
119 #
120 # Convert the file.
121 #
122 $defaultType = 'other';
123 $includeFile = "$path/header/p" . lc $processor . ".inc";
124 open(HEADER, "<$includeFile")
125     || die "$programName: Error: Cannot open include file $includeFile ($!)\n";
126
127 while (<HEADER>) {
128     if (/^;-* (\S+) Bits/i) {
129         if (defined($alias{$1})) {
130             $defaultType = "bits $alias{$1}";
131         } else {
132             $defaultType = "bits $1";
133         }
134         s/;/\/\//;
135         $body .= "$_";
136     } elsif (/^;-* Register Files/i) {
137         $defaultType = 'sfr';
138         s/;/\/\//;
139         $body .= "$_";
140     } elsif (/^;=*/i) {
141         $defaultType = '';
142         s/;/\/\//;
143         $body .= "$_";
144     } elsif (/^\s*;/) {
145         #
146         # Convert ASM comments to C style.
147         #
148         $body .= "//$'";
149     } elsif (/^\s*IFNDEF __(\S+)/) {
150         #
151         # Processor type.
152         #
153         $processor = $1;
154         $body .= "//$_";
155     } elsif (/^\s*(\S+)\s+EQU\s+H'(.+)'/) {
156         #
157         # Useful bit of information.
158         #
159         $name = $1;
160         $value = $2;
161         $rest = $';
162         $rest =~ s/;/\/\//;
163         chomp($rest);
164
165         if (defined($type{"p$processor", "$name"})) {
166             $type = $type{"p$processor", "$name"};
167         } elsif (defined($type{"$name"})) {
168             $type = $type{"$name"};
169         } else {
170             $type = $defaultType;
171         }
172
173         if (defined($bitmask{"p$processor", "$name"})) {
174             $bitmask = $bitmask{"p$processor", "$name"};
175 #       } elsif (defined($bitmask{"$name"})) {
176 #           $bitmask = $bitmask{"$name"};
177         } else {
178             $bitmask = "0x000";
179         }
180
181         if ($type eq 'sfr') {
182             #
183             # A special function register.
184             #
185             $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
186                                 . "SFR %s\t// %s\n",
187                                 $name, $name, $bitmask, $name);
188             if (defined $addr{"p$processor", "$name"}) {
189                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
190             } else {
191                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
192             }
193             $body .= sprintf("sfr  at %-30s %s;$rest\n", "${name}_ADDR", $name);
194             $addr{"p$processor", "$name"} = "0x$value";
195         } elsif ($type eq 'volatile') {
196             #
197             # A location that can change without 
198             # direct program manipulation.
199             #
200             $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
201                                 . "SFR %s\t// %s\n",
202                                 $name, $name, $bitmask, $name);
203             $body .= sprintf("data at %-30s %s;$rest\n", "${name}_ADDR volatile char", $name);
204             if (defined $addr{"p$processor", "$name"}) {
205                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
206             } else {
207                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
208             }
209         } elsif ($type =~ /^bits/) {
210             ($junk, $register) = split(/\s/, $type);
211             $bit = hex($value);
212             $addr = $addr{"$register"};
213             $body .= "BIT_AT(${register}_ADDR,$bit)\t$name;$rest\n";
214         } else {
215             #
216             # Other registers, bits and/or configurations.
217             #
218             if ($type eq 'other') {
219                 #
220                 # A known symbol.
221                 #
222                 $body .= sprintf("#define %-20s 0x%s$rest\n", $name, $value);
223             } else {
224                 #
225                 # A symbol that isn't defined in the data
226                 # section at the end of the file.  Let's 
227                 # add a comment so that we can add it later.
228                 #
229                 $body .= sprintf("#define %-20s 0x%s$rest\n",
230                                  $name, $value);
231             }
232         }
233     } elsif (/^\s*$/) {
234         #
235         # Blank line.
236         #
237         $body .= "\n";
238     } elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) {
239         $maxram .= "//\n// Memory organization.\n//\n"
240             . sprintf("#pragma maxram 0x%s\n\n", $1);
241         $pragmas = $maxram
242             . $ram{"p$processor"} . "\n"
243                 . $pragmas;
244         $body .= "// $_";
245     } else {
246         #
247         # Anything else we'll just comment out.
248         #
249         $body .= "// $_";
250     }
251 }
252 $header .= <<EOT;
253 //
254 // Register Declarations for Microchip $processor Processor
255 //
256 //
257 // This header file was automatically generated by:
258 //
259 //\t$programName V$version
260 //
261 //\tCopyright (c) 2002, Kevin L. Pauba, All Rights Reserved
262 //
263 //\tSDCC is licensed under the GNU Public license (GPL) v2.  Note that
264 //\tthis license covers the code to the compiler and other executables,
265 //\tbut explicitly does not cover any code or objects generated by sdcc.
266 //\tWe have not yet decided on a license for the run time libraries, but
267 //\tit will not put any requirements on code linked against it. See:
268 // 
269 //\thttp://www.gnu.org/copyleft/gpl/html
270 //
271 //\tSee http://sdcc.sourceforge.net/ for the latest information on sdcc.
272 //
273 // 
274 #ifndef P${processor}_H
275 #define P${processor}_H
276
277 #ifndef BIT_AT
278 #define BIT_AT(base,bitno) sbit at ((base<<3)+bitno)
279 #endif
280
281 //
282 // Register addresses.
283 //
284 EOT
285
286 print $header
287     . $addresses . "\n"
288     . $pragmas . "\n\n"
289     . $body
290     . "#endif\n";
291
292 sub Usage {
293         print STDERR <<EOT;
294
295 inc2h.pl - A utility to convert MPASM include files to header files
296            suitable for the SDCC compiler.
297
298 License: Copyright (c) 2002 Kevin L. Pauba
299
300          SDCC is licensed under the GNU Public license (GPL) v2; see
301          http://www.gnu.org/copyleft/gpl.html See http://sdcc.sourceforge.net/
302          for the latest information on sdcc.
303
304 Usage:   $programName processor [path]
305
306          where:
307
308          processor      The name of the processor (16f84, 16f877, etc.)
309
310          path           The path to the parent of the "header" and "lkr"
311                         directories.  The default is "/usr/share/gpasm".
312
313          The header file will be written to the standard output.
314
315          $#ARGV
316 EOT
317         exit;
318 }
319
320 __END__
321
322 #
323 # processor <processor_name>
324 # address <register_name> <hex_address>
325 # bitmask <bitmask> <register_list>
326 # ram <lo_address> <hi_address> <bitmask>
327 # sfr <register_list>
328 # volatile <address_list>
329 # bit <address_list>
330 #
331
332 alias OPTION_REG OPTION
333 volatile INDF PCL
334
335 #
336 # bitmask settings.
337 #
338 processor 16F84
339     bitmask 0x080 INDF PCL STATUS FSR PCLATH INTCON
340
341 processor 16F873, 16F874, 16F877, 16F627, 16F628, 16F876
342     bitmask 0x180 INDF PCL STATUS FSR PCLATH INTCON
343     bitmask 0x100 TMR0 OPTION_REG PORTB TRISB
344
345 #
346 # Memory maps.
347 #
348 processor 16F84
349     ram 0x000C 0x004f 0x080
350
351 processor 16F627, 16F628
352     ram 0x0020 0x006f 0x000
353     ram 0x0070 0x007f 0x180
354     ram 0x00a0 0x00ef 0x000
355     ram 0x0120 0x014f 0x000
356
357 processor 16F876, 16F877
358     ram 0x0020 0x006f 0x000
359     ram 0x0070 0x007f 0x180
360     ram 0x00a0 0x00ef 0x000
361     ram 0x0110 0x016f 0x000
362     ram 0x0190 0x01ef 0x000
363
364 processor 16F873, 16F874
365     ram 0x0020 0x007f 0x100
366     ram 0x00a0 0x00ff 0x100
367