Imported Upstream version 2.9.0
[debian/cc1111] / support / scripts / inc2h-pic16.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4
5 #
6 # Parse MPASM include files to extract SDCC header/device library files
7 # This script is (c) 2007 by Raphael Neider <rneider AT web.de>,
8 # it is licensed under the terms of the GPL v2.
9 #
10 # Usage: perl inc2h-pic16.pl /path/to/pDEVICE.inc
11 # where pDEVICE.inc might be contained in a gputils(.sf.net) package.
12 #
13 # Steps to add a new target device to SDCC/PIC16:
14 #
15 # 1. Create picDEVICE.c and picDEVICE.h from pDEVICE.inc using
16 #    perl inc2h-pic16.pl /path/to/pDEVICE.inc
17 # 2. mv picDEVICE.h $SDCC/device/include/pic16
18 # 3. mv picDEVICE.c $SDCC/device/lib/pic16/libdev
19 # 4. add DEVICE to $SDCC/device/lib/pic16/pics.all (and .build)
20 # 5. either
21 #    (a) adjust $SDCC/device/lib/pic16/libio/*.ignore
22 #        if the device does not support ADC, I2C, or USART
23 #        OR
24 #    (b) adjust $SDCC/device/include/pic16/adc.h
25 #        adding the new device to the correct ADC style class
26 # 6. edit $SDCC/device/include/pic16/pic18fregs.h
27 # 7. edit $SDCC/device/include/pic16/pic16devices.txt
28 #
29 # The file format of steps 6 and 7 is self explanatory, in most
30 # if not all cases you can copy and paste another device's records
31 # and adjust them to the newly added device.
32 #
33 # Please try to add device families (with a common datasheet) rather
34 # than a single device and use the .h and .c files of the largest
35 # device for all (using #include "largest.c" and #include "largest.h").
36 #
37
38 my $SCRIPT = $0;
39 $SCRIPT =~ s/.*\///g; # remove path prefix
40
41 sub max
42 {
43     my ($a,$b) = @_;
44     if ($a < $b) { return $b; }
45     else { return $a; }
46 }
47
48 sub LOG
49 {
50     foreach my $i (@_) {
51       print $i;
52     }
53 }
54
55 sub setup
56 {
57     my ($proc) = @_;
58     $proc = lc ($proc);
59     $proc =~ s,^pic,,;
60     $proc =~ s,^p,,;
61     my $header = "pic${proc}.h";
62     my $library = "pic${proc}.c";
63     open (HEADER, '>', "$header") or die "Could not open header file $header: $!";
64     open (LIBRARY, '>', "$library") or die "Could not open library file $library: $!.";
65
66
67     $proc = uc($proc);
68
69     print HEADER <<"HEREDOC"
70 /*
71  * $header - device specific declarations
72  *
73  * This file is part of the GNU PIC library for SDCC,
74  * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
75  *
76  * It has been automatically generated by $SCRIPT,
77  * (c) 2007 by Raphael Neider <rneider AT web.de>
78  */
79
80 #ifndef __PIC${proc}_H__
81 #define __PIC${proc}_H__ 1
82
83 HEREDOC
84 ;
85
86     print LIBRARY <<"HEREDOC"
87 /*
88  * $library - device specific definitions
89  *
90  * This file is part of the GNU PIC library for SDCC,
91  * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
92  *
93  * It has been automatically generated by $SCRIPT,
94  * (c) 2007 by Raphael Neider <rneider AT web.de>
95  */
96
97 #include <$header>
98
99 HEREDOC
100 ;
101 }
102
103 sub release
104 {
105     print HEADER <<HEREDOC
106
107 #endif
108
109 HEREDOC
110 ;
111
112     print LIBRARY <<HEREDOC
113
114 HEREDOC
115 ;
116     close HEADER;
117     close LIBRARY;
118 }
119
120 sub header
121 {
122     my $i;
123     foreach $i (@_) {
124         print HEADER $i;
125         #print $i;
126     }
127 }
128
129 sub library
130 {
131     my $i;
132     foreach $i (@_) {
133         print LIBRARY $i;
134         #print $i;
135     }
136 }
137
138 sub DEFINE
139 {
140     my ($name, $val, $comment) = @_;
141     header (sprintf("#define\t%-20s\t%s", $name, $val));
142     if (defined $comment) { header ("\t // $comment"); }
143     header "\n";
144 }
145
146 #######################
147 # main
148 #######################
149
150 my $state = 0;
151 my $sfrs = {};
152 my ($processor, $name);
153
154 while (<>) {
155     # extract processor type
156     chomp;
157     s/\s+/ /g;
158     next if (/^\s*$/);
159
160     if (/IFNDEF _*(18.*[0-9]+)/i) {
161         $processor = lc($1);
162         #LOG "Found processor: $processor.\n";
163         setup($processor);
164         next;
165     }
166
167     # extract SFR declarations
168     if (/;--.*Register Files.*--/i) {
169         $state = 1;
170     }
171     if ($state == 1 and /(\w+) EQU H'([0-9a-f]+)/i) {
172         my $addr = oct("0x" . $2);
173         $name = uc ($1);
174         $sfrs->{"$name"} = { "addr" => $addr,
175             "maxnames" => 0,
176             "bit0" => [],
177             "bit1" => [],
178             "bit2" => [],
179             "bit3" => [],
180             "bit4" => [],
181             "bit5" => [],
182             "bit6" => [],
183             "bit7" => [],
184         };
185
186         #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
187         next;
188     } elsif ($state == 1 and /(\w+) EQU ([0-9]+)/i) {
189         my $addr = 0+$2;
190         $name = uc ($1);
191         $sfrs->{"$name"} = { "addr" => $addr,
192             "maxnames" => 0,
193             "bit0" => [],
194             "bit1" => [],
195             "bit2" => [],
196             "bit3" => [],
197             "bit4" => [],
198             "bit5" => [],
199             "bit6" => [],
200             "bit7" => [],
201         };
202
203         #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
204         next;
205     }
206
207     # extract device id positions
208     if (/(_DEVID[0-9a-f]*) EQU H'([0-9a-f]+)/i) {
209         my $addr = oct("0x" . $2);
210         #LOG sprintf("Found device ID $1 at 0x%X.\n", $addr);
211         if ($state != 6) {
212             #print "\n// device IDs\n";
213             $state = 6;
214         }
215         DEFINE ($1, sprintf ("0x%X", $addr));
216         next;
217     }
218
219     if (/(_IDLOC[0-9a-f]*) EQU H'([90-9a-f]+)/i) {
220         my $addr = oct("0x" . $2);
221         #LOG sprintf("Found ID location: $1 at 0x%X.\n", $addr);
222         if ($state != 5) {
223             #print "\n// ID locations\n";
224             $state = 5;
225         }
226         DEFINE ($1, sprintf ("0x%X", $addr));
227         next;
228     }
229
230     # extract configuration bits
231     if (/Configuration Bits/i) {
232         $state = 3;
233         #print "\n\n// Configuration Bits\n";
234         header "\n\n// Configuration Bits\n";
235         next;
236     }
237
238     if ($state == 3 and /(_\w+) EQU H'([0-9a-f]+)/i) {
239         $name = $1;
240         my $addr = oct("0x" . $2);
241         # convert to double underscore form for SDCC internal consistency
242         $name =~ s/^_//g;
243         $name = "__".$name;
244         #LOG sprintf("Found config word $1 at 0x%X.\n", $addr);
245         DEFINE ($name, sprintf ("0x%X", $addr));
246         next;
247     }
248
249     if (($state == 3 or $state == 4) and /;--+ ((\w+) Options) --/i) {
250         $name = uc($2);
251         $state = 4;
252         #print "\n// $1\n";
253         header "\n// $1\n";
254         next;
255     }
256     if ($state == 4 and /(\w+) EQU H'([0-9a-f]+)(.*)/i) {
257         my $option = $1;
258         my $mask = oct ("0x" . $2);
259         my $comment = $3;
260         if ($comment =~ /[^;]*;\s*(.*)$/) {
261             $comment = $1;
262         }
263         #LOG sprintf ("Found config option $option, mask 0x%X in $name; comment: $comment.\n", $mask);
264         DEFINE ($option, sprintf("0x%X", $mask), $comment);
265         next;
266     }
267
268     # extract bit definitions
269     if (/;\s*-+\s*(\w+)\s*(Bits)?\s*-+/i) {
270         $state = 2;
271         $name = uc ($1);
272         next;
273     }
274     if ($state == 2 and /(\w+) EQU H'([0-9a-f]+)/i) {
275         my $bit = oct("0x" . $2);
276         #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
277         push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
278         $sfrs->{"$name"}->{"maxnames"} = max(
279             scalar @{$sfrs->{"$name"}->{"bit$bit"}},
280             $sfrs->{"$name"}->{"maxnames"}
281         );
282         next;
283     } elsif ($state == 2 and /(\w+) EQU ([0-9]+)/i) {
284         #print "@@@@ FOUND $1 $2 for $name\n";
285         my $bit = 0+$2;
286         #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
287         push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
288         $sfrs->{"$name"}->{"maxnames"} = max(
289             scalar @{$sfrs->{"$name"}->{"bit$bit"}},
290             $sfrs->{"$name"}->{"maxnames"}
291         );
292         next;
293     }
294
295     # unknown/unhandled line
296     #print "// $_\n";
297 }
298
299 header "\n";
300 library "\n";
301 my $namelut = {};
302 foreach my $reg (keys %$sfrs) {
303     if (!defined $namelut->{$sfrs->{"$reg"}->{"addr"}}) {
304         $namelut->{$sfrs->{"$reg"}->{"addr"}} = ();
305     }
306     push @{$namelut->{$sfrs->{"$reg"}->{"addr"}}}, $reg;
307 }
308
309 foreach my $idx (sort keys %$namelut) {
310     foreach my $reg (sort @{$namelut->{$idx}}) {
311         my $names = $sfrs->{"$reg"}->{"maxnames"};
312
313         header sprintf ("extern __sfr __at (0x%03X) %s;\n", $idx, $reg);
314         library sprintf (      "__sfr __at (0x%03X) %s;\n", $idx, $reg);
315
316         #print sprintf ("$reg @ %X (<= %d bit names)\n", $sfrs->{"$reg"}->{"addr"}, $names);
317         if ($names > 0) {
318             header sprintf ("typedef union {\n");
319
320             for (my $j=0; $j < $names; $j++) {
321                 header sprintf ("\tstruct {\n");
322                 for (my $bit=0; $bit < 8; $bit++) {
323                     my $bitname = $sfrs->{"$reg"}->{"bit$bit"}->[$j];
324                     if (defined $bitname) {
325                         header sprintf ("\t\tunsigned %-10s\t: 1;\n", $bitname);
326                     } else {
327                         header sprintf ("\t\tunsigned %-10s\t: 1;\n", "");
328                     }
329                 }
330                 header sprintf ("\t};\n");
331             }
332
333             header sprintf ("} __${reg}bits_t;\n");
334             header sprintf ("extern volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);
335             library sprintf (      "volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);
336         }
337
338         header "\n";
339         library "\n";
340     }
341 }
342
343 release;