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 printf "\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 #LOG sprintf("Found config word $1 at 0x%X.\n", $addr);
233 DEFINE ($name, sprintf ("0x%X", $addr));
237 if (($state == 3 or $state == 4) and /;--+ ((\w+) Options) --/i) {
244 if ($state == 4 and /(\w+) EQU H'([0-9a-f]+)(.*)/i) {
246 my $mask = oct ("0x" . $2);
248 if ($comment =~ /[^;]*;\s*(.*)$/) {
251 #LOG sprintf ("Found config option $option, mask 0x%X in $name; comment: $comment.\n", $mask);
252 DEFINE ($option, sprintf("0x%X", $mask), $comment);
256 # extract bit definitions
257 if (/;\s*-+\s*(\w+)\s*(Bits)?\s*-+/i) {
262 if ($state == 2 and /(\w+) EQU H'([0-9a-f]+)/i) {
263 my $bit = oct("0x" . $2);
264 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
265 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
266 $sfrs->{"$name"}->{"maxnames"} = max(
267 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
268 $sfrs->{"$name"}->{"maxnames"}
271 } elsif ($state == 2 and /(\w+) EQU ([0-9]+)/i) {
272 print "@@@@ FOUND $1 $2 for $name\n";
274 #LOG "Found bit declaration: $1 as bit $bit in reg $name.\n";
275 push @{$sfrs->{"$name"}->{"bit$bit"}}, $1;
276 $sfrs->{"$name"}->{"maxnames"} = max(
277 scalar @{$sfrs->{"$name"}->{"bit$bit"}},
278 $sfrs->{"$name"}->{"maxnames"}
283 # unknown/unhandled line
290 foreach my $reg (keys %$sfrs) {
291 if (!defined $namelut->{$sfrs->{"$reg"}->{"addr"}}) {
292 $namelut->{$sfrs->{"$reg"}->{"addr"}} = ();
294 push @{$namelut->{$sfrs->{"$reg"}->{"addr"}}}, $reg;
297 foreach my $idx (sort keys %$namelut) {
298 foreach my $reg (sort @{$namelut->{$idx}}) {
299 my $names = $sfrs->{"$reg"}->{"maxnames"};
301 header sprintf ("extern __sfr __at (0x%03X) %s;\n", $idx, $reg);
302 library sprintf ( "__sfr __at (0x%03X) %s;\n", $idx, $reg);
304 print sprintf ("$reg @ %X (<= %d bit names)\n", $sfrs->{"$reg"}->{"addr"}, $names);
306 header sprintf ("typedef union {\n");
308 for (my $j=0; $j < $names; $j++) {
309 header sprintf ("\tstruct {\n");
310 for (my $bit=0; $bit < 8; $bit++) {
311 my $bitname = $sfrs->{"$reg"}->{"bit$bit"}->[$j];
312 if (defined $bitname) {
313 header sprintf ("\t\tunsigned %-10s\t: 1;\n", $bitname);
315 header sprintf ("\t\tunsigned %-10s\t: 1;\n", "");
318 header sprintf ("\t};\n");
321 header sprintf ("} __${reg}bits_t;\n");
322 header sprintf ("extern volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);
323 library sprintf ( "volatile __${reg}bits_t __at (0x%03X) ${reg}bits;\n", $idx);