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.
10 # Usage: perl inc2h-pic16.pl /path/to/pDEVICE.inc
11 # where pDEVICE.inc might be contained in a gputils(.sf.net) package.
13 # Steps to add a new target device to SDCC/PIC16:
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)
21 # (a) adjust $SDCC/device/lib/pic16/libio/*.ignore
22 # if the device does not support ADC, I2C, or USART
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
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.
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").
39 $SCRIPT =~ s/.*\///g; # remove path prefix
44 if ($a < $b) { return $b; }
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: $!.";
69 print HEADER <<"HEREDOC"
71 * $header - device specific declarations
73 * This file is part of the GNU PIC library for SDCC,
74 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
76 * It has been automatically generated by $SCRIPT,
77 * (c) 2007 by Raphael Neider <rneider AT web.de>
80 #ifndef __PIC${proc}_H__
81 #define __PIC${proc}_H__ 1
86 print LIBRARY <<"HEREDOC"
88 * $library - device specific definitions
90 * This file is part of the GNU PIC library for SDCC,
91 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
93 * It has been automatically generated by $SCRIPT,
94 * (c) 2007 by Raphael Neider <rneider AT web.de>
105 print HEADER <<HEREDOC
112 print LIBRARY <<HEREDOC
140 my ($name, $val, $comment) = @_;
141 header (sprintf("#define\t%-20s\t%s", $name, $val));
142 if (defined $comment) { header ("\t // $comment"); }
146 #######################
148 #######################
152 my ($processor, $name);
155 # extract processor type
160 if (/IFNDEF _*(18.*[0-9]+)/i) {
162 #LOG "Found processor: $processor.\n";
167 # extract SFR declarations
168 if (/;--.*Register Files.*--/i) {
171 if ($state == 1 and /(\w+) EQU H'([0-9a-f]+)/i) {
172 my $addr = oct("0x" . $2);
174 $sfrs->{"$name"} = { "addr" => $addr,
186 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
188 } elsif ($state == 1 and /(\w+) EQU ([0-9]+)/i) {
191 $sfrs->{"$name"} = { "addr" => $addr,
203 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
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);
212 #print "\n// device IDs\n";
215 DEFINE ($1, sprintf ("0x%X", $addr));
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);
223 #print "\n// ID locations\n";
226 DEFINE ($1, sprintf ("0x%X", $addr));
230 # extract configuration bits
231 if (/Configuration Bits/i) {
233 #print "\n\n// Configuration Bits\n";
234 header "\n\n// Configuration Bits\n";
238 if ($state == 3 and /(_\w+) EQU H'([0-9a-f]+)/i) {
240 my $addr = oct("0x" . $2);
241 # convert to double underscore form for SDCC internal consistency
244 #LOG sprintf("Found config word $1 at 0x%X.\n", $addr);
245 DEFINE ($name, sprintf ("0x%X", $addr));
249 if (($state == 3 or $state == 4) and /;--+ ((\w+) Options) --/i) {
256 if ($state == 4 and /(\w+) EQU H'([0-9a-f]+)(.*)/i) {
258 my $mask = oct ("0x" . $2);
260 if ($comment =~ /[^;]*;\s*(.*)$/) {
263 #LOG sprintf ("Found config option $option, mask 0x%X in $name; comment: $comment.\n", $mask);
264 DEFINE ($option, sprintf("0x%X", $mask), $comment);
268 # extract bit definitions
269 if (/;\s*-+\s*(\w+)\s*(Bits)?\s*-+/i) {
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"}
283 } elsif ($state == 2 and /(\w+) EQU ([0-9]+)/i) {
284 #print "@@@@ FOUND $1 $2 for $name\n";
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"}
295 # unknown/unhandled line
302 foreach my $reg (keys %$sfrs) {
303 if (!defined $namelut->{$sfrs->{"$reg"}->{"addr"}}) {
304 $namelut->{$sfrs->{"$reg"}->{"addr"}} = ();
306 push @{$namelut->{$sfrs->{"$reg"}->{"addr"}}}, $reg;
309 foreach my $idx (sort keys %$namelut) {
310 foreach my $reg (sort @{$namelut->{$idx}}) {
311 my $names = $sfrs->{"$reg"}->{"maxnames"};
313 header sprintf ("extern __sfr __at (0x%03X) %s;\n", $idx, $reg);
314 library sprintf ( "__sfr __at (0x%03X) %s;\n", $idx, $reg);
316 #print sprintf ("$reg @ %X (<= %d bit names)\n", $sfrs->{"$reg"}->{"addr"}, $names);
318 header sprintf ("typedef union {\n");
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);
327 header sprintf ("\t\tunsigned %-10s\t: 1;\n", "");
330 header sprintf ("\t};\n");
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);