5 # Parse MPASM include files to extract SDCC header/device library files
6 # This script is (c) 2007 by Raphael Neider <rneider AT web.de>,
7 # it is licensed under the terms of the GPL v2.
9 # Usage: perl inc2h-pic16.pl /path/to/pDEVICE.inc
10 # where pDEVICE.inc might be contained in a gputils(.sf.net) package.
12 # Steps to add a new target device to SDCC/PIC16:
14 # 1. Create picDEVICE.c and picDEVICE.h from pDEVICE.inc using
15 # perl inc2h-pic16.pl /path/to/pDEVICE.inc
16 # 2. mv picDEVICE.h $SDCC/device/include/pic16
17 # 3. mv picDEVICE.c $SDCC/device/lib/pic16/libdev
18 # 4. add DEVICE to $SDCC/device/lib/pic16/pics.all (and .build)
19 # 5. adjust $SDCC/device/lib/pic16/libio/*.ignore if the device
20 # does not support ADC, I2C, or USART
21 # 6. edit $SDCC/device/include/pic16/pic18fregs.h
22 # 7. edit $SDCC/src/pic16/devices.inc
24 # The file format of steps 6 and 7 is self explanatory, in most
25 # if not all cases you can copy and paste another device's records
26 # and adjust them to the newly added device.
30 $SCRIPT =~ s/.*\///g; # remove path prefix
35 if ($a < $b) { return $b; }
52 my $header = "pic${proc}.h";
53 my $library = "pic${proc}.c";
54 open (HEADER, '>', "$header") or die "Could not open header file $header: $!";
55 open (LIBRARY, '>', "$library") or die "Could not open library file $library: $!.";
60 print HEADER <<"HEREDOC"
62 * $header - device specific declarations
64 * This file is part of the GNU PIC library for SDCC,
65 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
67 * It has been automatically generated by $SCRIPT,
68 * (c) 2007 by Raphael Neider <rneider AT web.de>
71 #ifndef __PIC${proc}_H__
72 #define __PIC${proc}_H__ 1
77 print LIBRARY <<"HEREDOC"
79 * $library - device specific definitions
81 * This file is part of the GNU PIC library for SDCC,
82 * originally devised by Vangelis Rokas <vrokas AT otenet.gr>
84 * It has been automatically generated by $SCRIPT,
85 * (c) 2007 by Raphael Neider <rneider AT web.de>
96 print HEADER <<HEREDOC
103 print LIBRARY <<HEREDOC
131 my ($name, $val, $comment) = @_;
132 header (sprintf("#define\t%-20s\t%s", $name, $val));
133 if (defined $comment) { header ("\t // $comment"); }
137 #######################
139 #######################
143 my ($processor, $name);
146 # extract processor type
151 if (/IFNDEF _*(18.*[0-9]+)/i) {
153 #LOG "Found processor: $processor.\n";
158 # extract SFR declarations
159 if (/;--.*Register Files.*--/i) {
162 if ($state == 1 and /(\w+) EQU H'([0-9a-f]+)/i) {
163 my $addr = oct("0x" . $2);
165 $sfrs->{"$name"} = { "addr" => $addr,
177 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
179 } elsif ($state == 1 and /(\w+) EQU ([0-9]+)/i) {
182 $sfrs->{"$name"} = { "addr" => $addr,
194 #LOG sprintf("Found register definition: $name @ 0x%X.\n", $addr);
198 # extract device id positions
199 if (/(_DEVID[0-9a-f]*) EQU H'([0-9a-f]+)/i) {
200 my $addr = oct("0x" . $2);
201 #LOG sprintf("Found device ID $1 at 0x%X.\n", $addr);
203 #print "\n// device IDs\n";
206 DEFINE ($1, sprintf ("0x%X", $addr));
210 if (/(_IDLOC[0-9a-f]*) EQU H'([90-9a-f]+)/i) {
211 my $addr = oct("0x" . $2);
212 #LOG sprintf("Found ID location: $1 at 0x%X.\n", $addr);
214 #print "\n// ID locations\n";
217 DEFINE ($1, sprintf ("0x%X", $addr));
221 # extract configuration bits
222 if (/Configuration Bits/i) {
224 #print "\n\n// Configuration Bits\n";
225 header "\n\n// Configuration Bits\n";
229 if ($state == 3 and /(_\w+) EQU H'([0-9a-f]+)/i) {
231 my $addr = oct("0x" . $2);
232 # convert to double underscore form for SDCC internal consistency
235 #LOG sprintf("Found config word $1 at 0x%X.\n", $addr);
236 DEFINE ($name, sprintf ("0x%X", $addr));
240 if (($state == 3 or $state == 4) and /;--+ ((\w+) Options) --/i) {
247 if ($state == 4 and /(\w+) EQU H'([0-9a-f]+)(.*)/i) {
249 my $mask = oct ("0x" . $2);
251 if ($comment =~ /[^;]*;\s*(.*)$/) {
254 #LOG sprintf ("Found config option $option, mask 0x%X in $name; comment: $comment.\n", $mask);
255 DEFINE ($option, sprintf("0x%X", $mask), $comment);
259 # extract bit definitions
260 if (/;\s*-+\s*(\w+)\s*(Bits)?\s*-+/i) {
265 if ($state == 2 and /(\w+) EQU H'([0-9a-f]+)/i) {
266 my $bit = oct("0x" . $2);
267 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
268 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
269 $sfrs->{"$name"}->{"maxnames"} = max(
270 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
271 $sfrs->{"$name"}->{"maxnames"}
274 } elsif ($state == 2 and /(\w+) EQU ([0-9]+)/i) {
275 #print "@@@@ FOUND $1 $2 for $name\n";
277 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
278 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
279 $sfrs->{"$name"}->{"maxnames"} = max(
280 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
281 $sfrs->{"$name"}->{"maxnames"}
286 # unknown/unhandled line
293 foreach my $reg (keys %$sfrs) {
294 if (!defined $namelut->{$sfrs->{"$reg"}->{"addr"}}) {
295 $namelut->{$sfrs->{"$reg"}->{"addr"}} = ();
297 push @{$namelut->{$sfrs->{"$reg"}->{"addr"}}}, $reg;
300 foreach my $idx (sort keys %$namelut) {
301 foreach my $reg (sort @{$namelut->{$idx}}) {
302 my $names = $sfrs->{"$reg"}->{"maxnames"};
304 header sprintf ("extern __sfr __at (0x%03X) %s;\n", $idx, $reg);
305 library sprintf ( "__sfr __at (0x%03X) %s;\n", $idx, $reg);
307 #print sprintf ("$reg @ %X (<= %d bit names)\n", $sfrs->{"$reg"}->{"addr"}, $names);
309 header sprintf ("typedef union {\n");
311 for (my $j=0; $j < $names; $j++) {
312 header sprintf ("\tstruct {\n");
313 for (my $bit=0; $bit < 8; $bit++) {
314 my $bitname = $sfrs->{"$reg"}->{"bit$bit"}->[$j];
315 if (defined $bitname) {
316 header sprintf ("\t\tunsigned %-10s\t: 1;\n", $bitname);
318 header sprintf ("\t\tunsigned %-10s\t: 1;\n", "");
321 header sprintf ("\t};\n");
324 header sprintf ("} __${reg}bits_t;\n");
325 header sprintf ("extern volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);
326 library sprintf ( "volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);