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)
20 # 5. adjust $SDCC/device/lib/pic16/libio/*.ignore if the device
21 # does not support ADC, I2C, or USART
22 # 6. edit $SDCC/device/include/pic16/pic18fregs.h
23 # 7. edit $SDCC/device/include/pic16/pic16devices.txt
25 # The file format of steps 6 and 7 is self explanatory, in most
26 # if not all cases you can copy and paste another device's records
27 # and adjust them to the newly added device.
29 # Please try to add device families (with a common datasheet) rather
30 # than a single device and use the .h and .c files of the largest
31 # device for all (using #include "largest.c" and #include "largest.h").
35 $SCRIPT =~ s/.*\///g; # remove path prefix
40 if ($a < $b) { return $b; }
57 my $header = "pic${proc}.h";
58 my $library = "pic${proc}.c";
59 open (HEADER, '>', "$header") or die "Could not open header file $header: $!";
60 open (LIBRARY, '>', "$library") or die "Could not open library file $library: $!.";
65 print HEADER <<"HEREDOC"
67 * $header - device specific declarations
69 * This file is part of the GNU PIC library for SDCC,
70 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
72 * It has been automatically generated by $SCRIPT,
73 * (c) 2007 by Raphael Neider <rneider AT web.de>
76 #ifndef __PIC${proc}_H__
77 #define __PIC${proc}_H__ 1
82 print LIBRARY <<"HEREDOC"
84 * $library - device specific definitions
86 * This file is part of the GNU PIC library for SDCC,
87 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
89 * It has been automatically generated by $SCRIPT,
90 * (c) 2007 by Raphael Neider <rneider AT web.de>
101 print HEADER <<HEREDOC
108 print LIBRARY <<HEREDOC
136 my ($name, $val, $comment) = @_;
137 header (sprintf("#define\t%-20s\t%s", $name, $val));
138 if (defined $comment) { header ("\t // $comment"); }
142 #######################
144 #######################
148 my ($processor, $name);
151 # extract processor type
156 if (/IFNDEF _*(18.*[0-9]+)/i) {
158 #LOG "Found processor: $processor.\n";
163 # extract SFR declarations
164 if (/;--.*Register Files.*--/i) {
167 if ($state == 1 and /(\w+) EQU H'([0-9a-f]+)/i) {
168 my $addr = oct("0x" . $2);
170 $sfrs->{"$name"} = { "addr" => $addr,
182 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
184 } elsif ($state == 1 and /(\w+) EQU ([0-9]+)/i) {
187 $sfrs->{"$name"} = { "addr" => $addr,
199 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
203 # extract device id positions
204 if (/(_DEVID[0-9a-f]*) EQU H'([0-9a-f]+)/i) {
205 my $addr = oct("0x" . $2);
206 #LOG sprintf("Found device ID $1 at 0x%X.\n", $addr);
208 #print "\n// device IDs\n";
211 DEFINE ($1, sprintf ("0x%X", $addr));
215 if (/(_IDLOC[0-9a-f]*) EQU H'([90-9a-f]+)/i) {
216 my $addr = oct("0x" . $2);
217 #LOG sprintf("Found ID location: $1 at 0x%X.\n", $addr);
219 #print "\n// ID locations\n";
222 DEFINE ($1, sprintf ("0x%X", $addr));
226 # extract configuration bits
227 if (/Configuration Bits/i) {
229 #print "\n\n// Configuration Bits\n";
230 header "\n\n// Configuration Bits\n";
234 if ($state == 3 and /(_\w+) EQU H'([0-9a-f]+)/i) {
236 my $addr = oct("0x" . $2);
237 # convert to double underscore form for SDCC internal consistency
240 #LOG sprintf("Found config word $1 at 0x%X.\n", $addr);
241 DEFINE ($name, sprintf ("0x%X", $addr));
245 if (($state == 3 or $state == 4) and /;--+ ((\w+) Options) --/i) {
252 if ($state == 4 and /(\w+) EQU H'([0-9a-f]+)(.*)/i) {
254 my $mask = oct ("0x" . $2);
256 if ($comment =~ /[^;]*;\s*(.*)$/) {
259 #LOG sprintf ("Found config option $option, mask 0x%X in $name; comment: $comment.\n", $mask);
260 DEFINE ($option, sprintf("0x%X", $mask), $comment);
264 # extract bit definitions
265 if (/;\s*-+\s*(\w+)\s*(Bits)?\s*-+/i) {
270 if ($state == 2 and /(\w+) EQU H'([0-9a-f]+)/i) {
271 my $bit = oct("0x" . $2);
272 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
273 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
274 $sfrs->{"$name"}->{"maxnames"} = max(
275 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
276 $sfrs->{"$name"}->{"maxnames"}
279 } elsif ($state == 2 and /(\w+) EQU ([0-9]+)/i) {
280 #print "@@@@ FOUND $1 $2 for $name\n";
282 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
283 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
284 $sfrs->{"$name"}->{"maxnames"} = max(
285 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
286 $sfrs->{"$name"}->{"maxnames"}
291 # unknown/unhandled line
298 foreach my $reg (keys %$sfrs) {
299 if (!defined $namelut->{$sfrs->{"$reg"}->{"addr"}}) {
300 $namelut->{$sfrs->{"$reg"}->{"addr"}} = ();
302 push @{$namelut->{$sfrs->{"$reg"}->{"addr"}}}, $reg;
305 foreach my $idx (sort keys %$namelut) {
306 foreach my $reg (sort @{$namelut->{$idx}}) {
307 my $names = $sfrs->{"$reg"}->{"maxnames"};
309 header sprintf ("extern __sfr __at (0x%03X) %s;\n", $idx, $reg);
310 library sprintf ( "__sfr __at (0x%03X) %s;\n", $idx, $reg);
312 #print sprintf ("$reg @ %X (<= %d bit names)\n", $sfrs->{"$reg"}->{"addr"}, $names);
314 header sprintf ("typedef union {\n");
316 for (my $j=0; $j < $names; $j++) {
317 header sprintf ("\tstruct {\n");
318 for (my $bit=0; $bit < 8; $bit++) {
319 my $bitname = $sfrs->{"$reg"}->{"bit$bit"}->[$j];
320 if (defined $bitname) {
321 header sprintf ("\t\tunsigned %-10s\t: 1;\n", $bitname);
323 header sprintf ("\t\tunsigned %-10s\t: 1;\n", "");
326 header sprintf ("\t};\n");
329 header sprintf ("} __${reg}bits_t;\n");
330 header sprintf ("extern volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);
331 library sprintf ( "volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);