sdcc:
[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 = uc(shift);
28 $path = shift;
29
30 if ($^O eq 'MSWin32') {
31     if ($path eq '') {
32         if (defined($path = $ENV{'GPUTILS_HEADER_PATH'}) || defined($path = $ENV{'GPUTILS_LKR_PATH'})) {
33             $path .= '\\..';
34         }
35         else {
36             die "Could not find gpasm includes.\n";
37         }
38     }
39     $path_delim = '\\';
40 }
41 else {
42     # Nathan Hurst <njh@mail.csse.monash.edu.au>: find gputils on Debian
43     if ($path eq '') {
44         if ( -x "/usr/share/gputils") {
45             $path = "/usr/share/gputils";
46         } elsif ( -x "/usr/share/gpasm") {
47             $path = "/usr/share/gpasm";
48         } else {
49             die "Could not find gpasm includes.\n";
50         }
51     }
52     $path_delim = '/';
53 }
54
55 #
56 # Read the symbols at the end of this file.
57 #
58 while (<DATA>) {
59     next if /^\s*#/;
60
61     if (/^\s*alias\s+(\S+)\s+(\S+)/) {
62         #
63         # Set an alias for a special function register.
64         # Some MPASM include files are not entirely consistent
65         # with sfr names.
66         #
67         $alias{$2} = $1;
68     } elsif (/^\s*address\s+(\S+)\s+(\S+)/) {
69         #
70         # Set a default address for a special function register.
71         # Some MPASM include files don't specify the address
72         # of all registers.
73         # 
74         # $addr{"$1"} = $2;
75         foreach $device (split(/[,\s]+/, $devices)) {
76             $addr{"p$device", "$1"} = $2;
77         }
78     } elsif (/^\s*bitmask\s+(\S+)\s+/) {
79         #
80         # Set the bitmask that will be used in the 'memmap' pragma.
81         #
82         $bitmask = "$1";
83         foreach $register (split(/\s+/, $')) {
84             $bitmask{"$register"} = $bitmask;
85         }
86     } elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) {
87         $lo = $1;
88         $hi = $2;
89         $bitmask = $3;
90         foreach $device (split(/[,\s]+/, $devices)) {
91             $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
92         }
93     } elsif (/^\s*processor\s+/) {
94         $devices = $';
95         $type = '';
96     } elsif (/^\s*(\S+)/) {
97         $type = $1;
98         $_ = $';
99         foreach $key (split) {
100             eval "\$type{'$key'} = $type;";
101         }
102     } else {
103         foreach $key (split) {
104             eval "\$type{'$key'} = $type;";
105         }
106     }
107 }
108
109 #
110 # Read the linker file.
111 #
112 #  $linkFile = "$path/lkr/" . lc $processor . ".lkr";
113 #  open(LINK, "<$linkFile")
114 #      || die "$programName: Error: Cannot open linker file $linkFile ($!)\n";
115 #  while (<LINK>) {
116 #      if (/^(\S+)\s+NAME=(\S+)\s+START=(\S+)\s+END=(\S+)\s+(PROTECTED)?/) {
117 #       $type = $1;
118 #       $name = $2;
119 #       $start = $3;
120 #       $end = $4;
121 #       $protected = 1 if ($5 =~ /protected/i);
122
123 #       if ($type =~ /(SHAREBANK)|(DATABANK)/i) {
124 #           $ram{"p$processor"} .=
125 #               sprintf("#pragma memmap %7s %7s RAM 0x000\t// $name\n",
126 #                       $start, $end);
127 #       }
128 #      } elsif (/^SECTION\s+NAME=(\S+)\s+ROM=(\S+)\s+/) {
129 #      }
130 #  }
131
132 # Create header for pic${processor}.c file
133 $lcproc = "pic" . lc($processor);
134 $c_head = <<EOT;
135 /* Register definitions for $lcproc.
136  * This file was automatically generated by:
137  *   $programName V$version
138  *   Copyright (c) 2002, Kevin L. Pauba, All Rights Reserved
139  */
140 #include <${lcproc}.h>
141
142 EOT
143
144 #
145 # Convert the file.
146 #
147 $defaultType = 'other';
148 $includeFile = $path.$path_delim.'header'.$path_delim.'p'.lc($processor).'.inc';
149 $defsFile = "pic" . lc($processor) . ".c";
150 open(HEADER, "<$includeFile")
151     || die "$programName: Error: Cannot open include file $includeFile ($!)\n";
152
153 while (<HEADER>) {
154     if (/^;-+ (\S+) Bits/i) {
155         # also accept "UIE/UIR Bits"
156         foreach $name (split(/\//, $1)) {
157             if (defined($alias{$name})) {
158                 $defaultType = "bits $alias{$name}";
159             } else {
160                 $defaultType = "bits $name";
161             }
162         }
163         s/;/\/\//;
164         $body .= "$_";
165     } elsif (/^;-+ Register Files/i) {
166         $defaultType = 'sfr';
167         s/;/\/\//;
168         $body .= "$_";
169     } elsif (/^;=+/i) {
170         $defaultType = '';
171         s/;/\/\//;
172         $body .= "$_";
173     } elsif (/^\s*;/) {
174         #
175         # Convert ASM comments to C style.
176         #
177         $body .= "//$'";
178     } elsif (/^\s*IFNDEF __(\S+)/) {
179         #
180         # Processor type.
181         #
182         $processor = $1;
183         $body .= "//$_";
184     } elsif (/^\s*(\S+)\s+EQU\s+H'(.+)'/) {
185         #
186         # Useful bit of information.
187         #
188         $name = $1;
189         $value = $2;
190         $rest = $';
191         $rest =~ s/;/\/\//;
192         chomp($rest);
193
194         if (defined($type{"p$processor", "$name"})) {
195             $type = $type{"p$processor", "$name"};
196         } elsif (defined($type{"$name"})) {
197             $type = $type{"$name"};
198         } else {
199             $type = $defaultType;
200         }
201
202         if (defined($bitmask{"p$processor", "$name"})) {
203             $bitmask = $bitmask{"p$processor", "$name"};
204 #       } elsif (defined($bitmask{"$name"})) {
205 #           $bitmask = $bitmask{"$name"};
206         } else {
207             $bitmask = "0x000";
208         }
209
210         if ($type eq 'sfr') {
211             #
212             # A special function register.
213             #
214             $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
215                                 . "SFR %s\t// %s\n",
216                                 $name, $name, $bitmask, $name);
217             if (defined $addr{"p$processor", "$name"}) {
218                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
219             } else {
220                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
221             }
222             $body .= sprintf("extern __sfr  __at %-30s $name;$rest\n", "(${name}_ADDR)" );
223             $c_head .= sprintf("__sfr  __at %-30s $name;\n", "(${name}_ADDR)");
224             $addr{"p$processor", "$name"} = "0x$value";
225         } elsif ($type eq 'volatile') {
226             #
227             # A location that can change without 
228             # direct program manipulation.
229             #
230             $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
231                                 . "SFR %s\t// %s\n",
232                                 $name, $name, $bitmask, $name);
233             $body .= sprintf("extern __data __at %-30s $name;$rest\n", "(${name}_ADDR) volatile char");
234             $c_head .= sprintf("__data __at %-30s $name;\n", "(${name}_ADDR) volatile char");
235             if (defined $addr{"p$processor", "$name"}) {
236                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
237             } else {
238                 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
239             }
240         } elsif ($type =~ /^bits/) {
241             ($junk, $register) = split(/\s/, $type);
242             $bit = hex($value);
243             $addr = $addr{"$register"};
244             # prepare struct declaration
245             for ($k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) {
246               $name = "" if ($bits{"$register"}->{oct($bit)} eq $name)
247             }
248             if ($name ne "") {
249               push @{$bits{"$register"}->{oct($bit)}}, $name;
250             }
251         } else {
252             #
253             # Other registers, bits and/or configurations.
254             #
255             if ($type eq 'other') {
256                 #
257                 # A known symbol.
258                 #
259                 $body .= sprintf("#define %-20s 0x%s$rest\n", $name, $value);
260             } else {
261                 #
262                 # A symbol that isn't defined in the data
263                 # section at the end of the file.  Let's 
264                 # add a comment so that we can add it later.
265                 #
266                 $body .= sprintf("#define %-20s 0x%s$rest\n",
267                                  $name, $value);
268             }
269         }
270     } elsif (/^\s*$/) {
271         #
272         # Blank line.
273         #
274         $body .= "\n";
275     } elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) {
276         $maxram .= "//\n// Memory organization.\n//\n";
277         $pragmas = $maxram
278             . $ram{"p$processor"} . "\n"
279                 . $pragmas;
280         $body .= "// $_";
281     } else {
282         #
283         # Anything else we'll just comment out.
284         #
285         $body .= "// $_";
286     }
287 }
288 $header .= <<EOT;
289 //
290 // Register Declarations for Microchip $processor Processor
291 //
292 //
293 // This header file was automatically generated by:
294 //
295 //\t$programName V$version
296 //
297 //\tCopyright (c) 2002, Kevin L. Pauba, All Rights Reserved
298 //
299 //\tSDCC is licensed under the GNU Public license (GPL) v2.  Note that
300 //\tthis license covers the code to the compiler and other executables,
301 //\tbut explicitly does not cover any code or objects generated by sdcc.
302 //\tWe have not yet decided on a license for the run time libraries, but
303 //\tit will not put any requirements on code linked against it. See:
304 // 
305 //\thttp://www.gnu.org/copyleft/gpl/html
306 //
307 //\tSee http://sdcc.sourceforge.net/ for the latest information on sdcc.
308 //
309 // 
310 #ifndef P${processor}_H
311 #define P${processor}_H
312
313 //
314 // Register addresses.
315 //
316 EOT
317
318 $c_head .= <<EOT;
319
320 // 
321 // bitfield definitions
322 // 
323 EOT
324
325 $structs = "";
326 ## create struct declarations
327 foreach $reg (sort keys %bits)
328 {
329   $structs .= "// ----- $reg bits --------------------\n";
330   $structs .= "typedef union {\n";
331   $idx = 0; $max = 1;
332   do {
333     $structs .= "  struct {\n";
334     for ($i=0; $i < 8; $i++)
335     {
336       @names = @{$bits{$reg}->{oct($i)}};
337       if ($max < scalar @names) { $max = scalar @names; }
338       if ($idx >= scalar @names) {
339         $structs .= "    unsigned char :1;\n";
340       } else { # (1 == scalar @names) {
341         $structs .= "    unsigned char " . $names[$idx] . ":1;\n";
342 #      } else {
343 #       $structs .= "  union {\n";
344 #       foreach $name (@names) {
345 #         $structs .= "    unsigned char " . $name . ":1;\n";
346 #       } # foreach
347 #       $structs .= "  };\n";
348       }
349     } # for
350     $structs .= "  };\n";
351     $idx++;
352   } while ($idx < $max);
353   $structs .= "} __${reg}_bits_t;\n";
354   $structs .= "extern volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n\n";
355   $c_head .= "volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n";
356   
357   # emit defines for individual bits
358   for ($i=0; $i < 8; $i++)
359   {
360     @names = @{$bits{$reg}->{oct($i)}};
361     foreach $field (@names) {
362       $structs .= sprintf("#define %-20s ${reg}_bits.$field\n", $field);
363     } # foreach
364   }
365   $structs .= "\n";
366 } # foreach
367
368 print $header
369     . $addresses . "\n"
370     . $pragmas . "\n\n"
371     . $body . "\n"
372     . $structs
373     . "#endif\n";
374
375 open(DEFS, ">$defsFile") or die "Could not open $defsFile for writing.";
376 print DEFS $c_head . "\n";
377 close DEFS;
378
379 sub Usage {
380         print STDERR <<EOT;
381
382 inc2h.pl - A utility to convert MPASM include files to header files
383            suitable for the SDCC compiler.
384
385 License: Copyright (c) 2002 Kevin L. Pauba
386
387          SDCC is licensed under the GNU Public license (GPL) v2; see
388          http://www.gnu.org/copyleft/gpl.html See http://sdcc.sourceforge.net/
389          for the latest information on sdcc.
390
391 Usage:   $programName processor [path]
392
393          where:
394
395          processor      The name of the processor (16f84, 16f877, etc.)
396
397          path           The path to the parent of the "header" and "lkr"
398                         directories.  The default is "/usr/share/gpasm".
399
400          The header file will be written to the standard output.
401
402          $#ARGV
403 EOT
404         exit;
405 }
406
407 __END__
408
409 #
410 # processor <processor_name>
411 # address <register_name> <hex_address>
412 # bitmask <bitmask> <register_list>
413 # ram <lo_address> <hi_address> <bitmask>
414 # sfr <register_list>
415 # volatile <address_list>
416 # bit <address_list>
417 #
418
419 alias OPTION_REG OPTION
420 volatile INDF PCL