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