5 # Copyright (c) 2002 Kevin L. Pauba
10 # SDCC is licensed under the GNU Public license (GPL) v2. Note that
11 # this license covers the code to the compiler and other executables,
12 # but explicitly does not cover any code or objects generated by sdcc.
13 # We have not yet decided on a license for the run time libraries, but
14 # it will not put any requirements on code linked against it. See:
16 # http://www.gnu.org/copyleft/gpl.html
18 # See http://sdcc.sourceforge.net/ for the latest information on sdcc.
20 #####################################################################
21 # >>> How to add a new device to SDCC PIC14 port?
23 # This description assumes that you have a copy of SDCC's sources
24 # in /path/to/sdcc and a (source or installed) version of gputils
25 # in /path/to/gputils (the only important point here is that
26 # /path/to/gputils/headers must exist and contain "p<DEVICE>.inc").
27 # Furthermore, I assume you want to add support for the 16f887 device
28 # (note: no 'pic' or 'p' prefix!), change this as desired.
29 # inc2h.pl can only deal with one single device at a time; repeat the
30 # ../inc2h.pl-step as often as required.
32 # The proposed sequence of commands is then:
34 # $ cd /path/to/sdcc/support/scripts
35 # $ mkdir build && cd build
36 # $ ../inc2h.pl 16f887 /path/to/gputils
37 # $ mv pic16f887.c /path/to/sdcc/device/lib/pic/libdev
38 # $ mv pic16f887.h /path/to/sdcc/device/include/pic
39 # $ vim /path/to/sdcc/device/include/pic/pic14devices.inc
41 # # Use any pure text editor you like (`[Esc]:q![Enter]' quits Vim ;-)).
42 # # Add a record for the new device to the file; usually you can copy
43 # # the record of a similar device and adjust the values using the
44 # # datasheet. The format of pic14devices.txt is explained in the file
45 # # itself. Please keep the file sorted.
46 # # When you are done:
48 # $ cd /path/to/sdcc/device/lib
52 # Congratulations, you have just added support for a new device to
53 # the port. You may consider posting your (changes to)
54 # pic14devices.txt and the generated files (picDEVICE.[ch]) to
55 # have them included into the official source tree.
56 # Some testing beforehand would be appreciated, though.
57 #####################################################################
59 my $rcsid = q~$Id: inc2h.pl 4850 2007-06-12 21:49:18Z tecodev $~;
60 my ($junk, $file, $version, $date, $time, $programmer, $status)
61 = split(/\s+/, $rcsid);
62 my ($programName) = ($file =~ /(\S+)/);
64 if ($#ARGV < 0 || $#ARGV > 1 ) {
67 my $processor = uc(shift);
80 # just in time fixes for some register names
83 $name =~ s/COMCON/CMCON/ig;
84 # use OPTION_REG instead of OPTION as OPTION is a assembler directive
85 $name =~ s/OPTION(_REG)?/OPTION_REG/ig;
86 # often declared as LCDDATn, but bits defined for LCDDATAn, 0 <= n <= 10
87 $name =~ s/LCDDAT([^A])/LCDDATA$1/ig;
88 # LCDSE2 is missing in some headers, but LCDSE3 is declared...
89 $name =~ s/LCDSE3/LCDSE2/ig;
90 # XXX: should this be named LININTF or LINPRT?
91 $name =~ s/LININTF/LINPRT/ig;
92 # FIXME: duplicate declarations for n in {0,1,2}
93 $name =~ s/UEPn/UEP0/ig;
100 if (not exists $sfrs{$name}) {
101 print "SFR $name not defined (yet).\n";
103 if (exists $sfrs{$name."0"}) {
104 print " but ".$name."0 exists---using that instead.\n";
109 if (exists $sfrs{$try}) {
110 print " but $try exists---using that instead.\n";
113 die "Not found a similar SFR---aborting.\n";
118 # exists clone for arrays---does this not exist in Perl?!?
123 foreach my $item (@$arr) {
124 return 1 if ($name eq $item);
130 $path = "" if (!defined $path);
131 if ($^O eq 'MSWin32') {
133 if (defined($path = $ENV{'GPUTILS_HEADER_PATH'}) || defined($path = $ENV{'GPUTILS_LKR_PATH'})) {
137 die "Could not find gpasm includes.\n";
143 # Nathan Hurst <njh@mail.csse.monash.edu.au>: find gputils on Debian
145 if ( -x "/usr/share/gputils") {
146 $path = "/usr/share/gputils";
147 } elsif ( -x "/usr/share/gpasm") {
148 $path = "/usr/share/gpasm";
149 } elsif ( -x "/usr/local/share/gputils") {
150 $path = "/usr/local/share/gputils";
152 die "Could not find gpasm includes.\n";
159 # Read the symbols at the end of this file.
164 if (/^\s*alias\s+(\S+)\s+(\S+)/) {
166 # Set an alias for a special function register.
167 # Some MPASM include files are not entirely consistent
170 $alias{fixname($2)} = fixname($1);
171 } elsif (/^\s*address\s+(\S+)\s+(\S+)/) {
173 # Set a default address for a special function register.
174 # Some MPASM include files don't specify the address
178 foreach my $device (split(/[,\s]+/, $devices)) {
179 $addr{"p$device", "$1"} = $2;
181 } elsif (/^\s*bitmask\s+(\S+)\s+/) {
183 # Set the bitmask that will be used in the 'memmap' pragma.
186 foreach my $register (split(/\s+/, $')) {
187 $bitmasks{"$register"} = $bitmask;
189 } elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) {
190 # This info is now provided in "include/pic/pic14devices.txt".
194 #foreach $device (split(/[,\s]+/, $devices)) {
195 # $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
197 } elsif (/^\s*processor\s+/) {
200 } elsif (/^\s*(\S+)/) {
203 foreach my $key (split) {
204 eval "\$types{'$key'} = $type;";
207 foreach my $key (split) {
208 eval "\$types{'$key'} = $type;";
214 # Read the linker file.
216 # $linkFile = "$path/lkr/" . lc $processor . ".lkr";
217 # open(LINK, "<$linkFile")
218 # || die "$programName: Error: Cannot open linker file $linkFile ($!)\n";
220 # if (/^(\S+)\s+NAME=(\S+)\s+START=(\S+)\s+END=(\S+)\s+(PROTECTED)?/) {
225 # $protected = 1 if ($5 =~ /protected/i);
227 # if ($type =~ /(SHAREBANK)|(DATABANK)/i) {
228 # $ram{"p$processor"} .=
229 # sprintf("#pragma memmap %7s %7s RAM 0x000\t// $name\n",
232 # } elsif (/^SECTION\s+NAME=(\S+)\s+ROM=(\S+)\s+/) {
236 # Create header for pic${processor}.c file
237 my $lcproc = "pic" . lc($processor);
239 /* Register definitions for $lcproc.
240 * This file was automatically generated by:
241 * $programName V$version
242 * Copyright (c) 2002, Kevin L. Pauba, All Rights Reserved
244 #include <${lcproc}.h>
251 my $defaultType = 'other';
252 my $includeFile = $path.$path_delim.'header'.$path_delim.'p'.lc($processor).'.inc';
253 my $headFile = "pic" . lc($processor) . ".h";
254 my $defsFile = "pic" . lc($processor) . ".c";
261 open(HEADER, "<$includeFile")
262 || die "$programName: Error: Cannot open include file $includeFile ($!)\n";
266 if (/^;-+ Register Files/i) {
267 $defaultType = 'sfr';
270 } elsif (/^;-+\s*(\S+)\s+Bits/i || /^;-+\s*(\S+)\s+-+/i) {
271 # The second case is usually bits, but the word Bits is missing
272 # also accept "UIE/UIR Bits"
273 foreach my $name (split(/\//, $1)) {
274 $name = fixname($name);
275 $name = checkname($name);
277 if (defined($alias{$name})) {
278 $defaultType = "bits $alias{$name}";
280 $defaultType = "bits $name";
291 # Convert ASM comments to C style.
294 } elsif (/^\s*IFNDEF\s+__(\S+)/) {
300 } elsif (/^\s*(\S+)\s+EQU\s+H'(.+)'/) {
302 # Useful bit of information.
307 my $bitmask = "0x0000";
312 if (defined($types{"p$processor", "$name"})) {
313 $type = $types{"p$processor", "$name"};
314 } elsif (defined($types{"$name"})) {
315 $type = $types{"$name"};
317 $type = $defaultType;
319 #print "$name --> $type\n"; ## DEBUG
321 if (defined($bitmasks{"p$processor", "$name"})) {
322 $bitmask = $bitmasks{"p$processor", "$name"};
323 # } elsif (defined($bitmasks{"$name"})) {
324 # $bitmask = $bitmasks{"$name"};
327 if ($type eq 'sfr') {
329 # A special function register.
331 # $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
332 # . "SFR %s\t// %s\n",
333 # $name, $name, $bitmask, $name);
334 $name = fixname($name);
335 if (defined $addr{"p$processor", "$name"}) {
336 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
338 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
340 $body .= sprintf("extern __sfr __at %-30s $name;$rest\n", "(${name}_ADDR)" );
341 $c_head .= sprintf("__sfr __at %-30s $name;\n", "(${name}_ADDR)");
342 $addr{"p$processor", "$name"} = "0x$value";
344 } elsif ($type eq 'volatile') {
346 # A location that can change without
347 # direct program manipulation.
349 $name = fixname($name);
350 # $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR "
351 # . "SFR %s\t// %s\n",
352 # $name, $name, $bitmask, $name);
353 $body .= sprintf("extern __data __at %-30s $name;$rest\n", "(${name}_ADDR) volatile char");
354 $c_head .= sprintf("__data __at %-30s $name;\n", "(${name}_ADDR) volatile char");
355 if (defined $addr{"p$processor", "$name"}) {
356 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
358 $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
360 } elsif ($type =~ /^bits/) {
361 my ($junk, $register) = split(/\s/, $type);
362 my $bit = hex($value);
363 my $addr = $addr{"$register"};
365 # prepare struct declaration
367 foreach my $key (keys %bits) {
370 print "$register // $bit // ".$bits{"$register"}."\n";
372 if (!defined $bits{"$register"}) {
373 $bits{"$register"} = {}; # reference to empty hash
375 if (!defined $bits{"$register"}->{oct($bit)}) {
376 $bits{"$register"}->{oct($bit)} = []; # reference to empty array
378 for (my $k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) {
379 $name = "" if ($bits{"$register"}->{oct($bit)} eq $name)
382 and (1 != contained($name, \@{$bits{"$register"}->{oct($bit)}}))
384 push @{$bits{"$register"}->{oct($bit)}}, $name;
388 # Other registers, bits and/or configurations.
390 $name = fixname($name);
391 if ($type eq 'other') {
395 $body .= sprintf("#define %-20s 0x%s$rest\n", $name, $value);
398 # A symbol that isn't defined in the data
399 # section at the end of the file. Let's
400 # add a comment so that we can add it later.
402 $body .= sprintf("#define %-20s 0x%s$rest\n",
411 } elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) {
412 my $maxram .= "//\n// Memory organization.\n//\n";
413 if (!defined $ram{"p$processor"}) {
414 $ram{"p$processor"} = "";
417 . $ram{"p$processor"} . "\n"
422 # Anything else we'll just comment out.
429 // Register Declarations for Microchip $processor Processor
432 // This header file was automatically generated by:
434 //\t$programName V$version
436 //\tCopyright (c) 2002, Kevin L. Pauba, All Rights Reserved
438 //\tSDCC is licensed under the GNU Public license (GPL) v2. Note that
439 //\tthis license covers the code to the compiler and other executables,
440 //\tbut explicitly does not cover any code or objects generated by sdcc.
441 //\tWe have not yet decided on a license for the run time libraries, but
442 //\tit will not put any requirements on code linked against it. See:
444 //\thttp://www.gnu.org/copyleft/gpl/html
446 //\tSee http://sdcc.sourceforge.net/ for the latest information on sdcc.
449 #ifndef P${processor}_H
450 #define P${processor}_H
453 // Register addresses.
460 // bitfield definitions
464 # Add PORT* and TRIS* bit entries
467 # * A0-5,B0-7,C0-7,D0-7,E0-2
470 my $defpinfo = undef;
471 open(P14PORTS, "< pic14ports.txt") && do {
474 if(/^\s*(\*|\w*)\s*([ABCDE0-7,-]+)\s*$/) {
475 if(lc($1) eq lc($processor)) {
476 die if defined $pinfo;
479 die if defined $defpinfo;
482 } elsif(/^\s*#/ || /^\s*$/) {
483 # ignore blanks, comments
485 die "bad line in pic14ports '$_'";
490 $defpinfo = "A0-5,B0-7,C0-7,D0-7,E0-2" unless defined $defpinfo;
491 $pinfo = $defpinfo unless defined $pinfo;
494 foreach (split /,/, $pinfo) {
495 if(/^([ABCDE])([0-7])-([0-7])$/) {
496 my($prt, $low, $high) = ($1, $2, $3);
497 next unless defined $sfrs{"PORT$prt"} && defined $sfrs{"TRIS$prt"};
498 next if defined $bits{"PORT$prt"};
499 for(my $i = $low; $i <= $high; $i++) {
500 push @{$bits{"PORT$prt"}->{oct($i)}}, "R$prt".$i;
502 next if defined $bits{"TRIS$prt"};
503 for(my $i = $low; $i <= $high; $i++) {
504 push @{$bits{"TRIS$prt"}->{oct($i)}}, "TRIS$prt".$i;
512 ## create struct declarations
513 foreach my $reg (sort keys %bits)
515 $structs .= "// ----- $reg bits --------------------\n";
516 $structs .= "typedef union {\n";
520 $structs .= " struct {\n";
521 for (my $i=0; $i < 8; $i++)
523 if (!defined $bits{$reg}) {
524 #print "bits{$reg} undefined\n";
526 if (!defined $bits{$reg}->{oct($i)}) {
527 #print "bits{$reg}->{".oct($i)."} undefined\n";
528 $bits{$reg}->{oct($i)} = []; # empty array reference
530 my @names = @{$bits{$reg}->{oct($i)}};
531 if ($max < scalar @names) { $max = scalar @names; }
532 if ($idx >= scalar @names) {
533 $structs .= " unsigned char :1;\n";
534 } else { # (1 == scalar @names) {
535 $structs .= " unsigned char " . $names[$idx] . ":1;\n";
537 # $structs .= " union {\n";
538 # foreach $name (@names) {
539 # $structs .= " unsigned char " . $name . ":1;\n";
541 # $structs .= " };\n";
546 } while ($idx < $max);
547 $structs .= "} __${reg}_bits_t;\n";
548 #if(defined $sfrs{$reg}) {
549 $structs .= "extern volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n\n";
550 $c_head .= "volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n";
553 # emit defines for individual bits
554 $structs .= "#ifndef NO_BIT_DEFINES\n";
555 for (my $i=0; $i < 8; $i++)
557 my @names = @{$bits{$reg}->{oct($i)}};
558 foreach my $field (@names) {
559 $structs .= sprintf("#define %-20s ${reg}_bits.$field\n", $field);
562 $structs .= "#endif /* NO_BIT_DEFINES */\n";
566 open(HEAD, ">$headFile") or die "Could not open $headFile for writing.";
575 open(DEFS, ">$defsFile") or die "Could not open $defsFile for writing.";
576 print DEFS $c_head . "\n";
582 inc2h.pl - A utility to convert MPASM include files to header files
583 suitable for the SDCC compiler.
585 License: Copyright (c) 2002 Kevin L. Pauba
587 SDCC is licensed under the GNU Public license (GPL) v2; see
588 http://www.gnu.org/copyleft/gpl.html See http://sdcc.sourceforge.net/
589 for the latest information on sdcc.
591 Usage: $programName processor [path]
595 processor The name of the processor (16f84, 16f877, etc.)
597 path The path to the parent of the "header" and "lkr"
598 directories. The default is "/usr/share/gpasm".
600 The header file will be written to the standard output.
610 # processor <processor_name>
611 # address <register_name> <hex_address>
612 # bitmask <bitmask> <register_list>
613 # ram <lo_address> <hi_address> <bitmask>
614 # sfr <register_list>
615 # volatile <address_list>
619 alias OPTION_REG OPTION