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