X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=support%2Fscripts%2Finc2h.pl;h=7fa4151cec9422067e9d39873dc8adb05f706eda;hb=c8934872083d18882ef5a9c33f05eb37f42da68d;hp=805f81965b43594c846462019d112668f4d9c5a5;hpb=f970f0e6603401042048d98927927133a0f9f255;p=fw%2Fsdcc diff --git a/support/scripts/inc2h.pl b/support/scripts/inc2h.pl index 805f8196..7fa4151c 100755 --- a/support/scripts/inc2h.pl +++ b/support/scripts/inc2h.pl @@ -1,4 +1,6 @@ -#!/usr/bin/perl +#!/usr/bin/perl -w + +use strict; # Copyright (c) 2002 Kevin L. Pauba @@ -10,23 +12,122 @@ # but explicitly does not cover any code or objects generated by sdcc. # We have not yet decided on a license for the run time libraries, but # it will not put any requirements on code linked against it. See: -# +# # http://www.gnu.org/copyleft/gpl.html # # See http://sdcc.sourceforge.net/ for the latest information on sdcc. - -$rcsid = q~$Id$~; -($junk, $file, $version, $date, $time, $programmer, $status) +##################################################################### +# >>> How to add a new device to SDCC PIC14 port? +# +# This description assumes that you have a copy of SDCC's sources +# in /path/to/sdcc and a (source or installed) version of gputils +# in /path/to/gputils (the only important point here is that +# /path/to/gputils/headers must exist and contain "p.inc"). +# Furthermore, I assume you want to add support for the 16f887 device +# (note: no 'pic' or 'p' prefix!), change this as desired. +# inc2h.pl can only deal with one single device at a time; repeat the +# ../inc2h.pl-step as often as required. +# +# The proposed sequence of commands is then: +# +# $ cd /path/to/sdcc/support/scripts +# $ mkdir build && cd build +# $ ../inc2h.pl 16f887 /path/to/gputils +# $ mv pic16f887.c /path/to/sdcc/device/lib/pic/libdev +# $ mv pic16f887.h /path/to/sdcc/device/include/pic +# $ vim /path/to/sdcc/device/include/pic/pic14devices.inc +# +# # Use any pure text editor you like (`[Esc]:q![Enter]' quits Vim ;-)). +# # Add a record for the new device to the file; usually you can copy +# # the record of a similar device and adjust the values using the +# # datasheet. The format of pic14devices.txt is explained in the file +# # itself. Please keep the file sorted. +# # When you are done: +# +# $ cd /path/to/sdcc/device/lib +# $ make model-pic14 +# $ make install +# +# Congratulations, you have just added support for a new device to +# the port. You may consider posting your (changes to) +# pic14devices.txt and the generated files (picDEVICE.[ch]) to +# have them included into the official source tree. +# Some testing beforehand would be appreciated, though. +##################################################################### + +my $rcsid = q~$Id$~; +my ($junk, $file, $version, $date, $time, $programmer, $status) = split(/\s+/, $rcsid); -($programName) = ($file =~ /(\S+),v/); +my ($programName) = ($file =~ /(\S+)/); if ($#ARGV < 0 || $#ARGV > 1 ) { Usage(); } -$processor = uc(shift); -$path = shift; +my $processor = uc(shift); +my $path = shift; +my %sfrs = (); +my %alias = (); +my %bits = (); +my %bitmasks = (); +my %addr = (); +my %ram = (); +my $path_delim = "/"; +my $devices = ""; +my %types = (); +my $type = ""; + +# just in time fixes for some register names +sub fixname { + my $name = shift; + $name =~ s/COMCON/CMCON/ig; + # use OPTION_REG instead of OPTION as OPTION is a assembler directive + $name =~ s/OPTION(_REG)?/OPTION_REG/ig; + # often declared as LCDDATn, but bits defined for LCDDATAn, 0 <= n <= 10 + $name =~ s/LCDDAT([^A])/LCDDATA$1/ig; + # LCDSE2 is missing in some headers, but LCDSE3 is declared... + $name =~ s/LCDSE3/LCDSE2/ig; + # XXX: should this be named LININTF or LINPRT? + $name =~ s/LININTF/LINPRT/ig; + # FIXME: duplicate declarations for n in {0,1,2} + $name =~ s/UEPn/UEP0/ig; + + return $name; +} +sub checkname { + my $name = shift; + if (not exists $sfrs{$name}) { + print "SFR $name not defined (yet).\n"; + # Find similar ones. + if (exists $sfrs{$name."0"}) { + print " but ".$name."0 exists---using that instead.\n"; + return $name."0"; + } + my $try = $name; + $try =~ s/[0-9]$//; + if (exists $sfrs{$try}) { + print " but $try exists---using that instead.\n"; + return $try; + } + die "Not found a similar SFR---aborting.\n"; + } + return $name; +} + +# exists clone for arrays---does this not exist in Perl?!? +sub contained { + my $name = shift; + my $arr = shift; + + foreach my $item (@$arr) { + return 1 if ($name eq $item); + } + return 0; +} + + +$path = "" if (!defined $path); if ($^O eq 'MSWin32') { if ($path eq '') { if (defined($path = $ENV{'GPUTILS_HEADER_PATH'}) || defined($path = $ENV{'GPUTILS_LKR_PATH'})) { @@ -45,6 +146,8 @@ else { $path = "/usr/share/gputils"; } elsif ( -x "/usr/share/gpasm") { $path = "/usr/share/gpasm"; + } elsif ( -x "/usr/local/share/gputils") { + $path = "/usr/local/share/gputils"; } else { die "Could not find gpasm includes.\n"; } @@ -64,7 +167,7 @@ while () { # Some MPASM include files are not entirely consistent # with sfr names. # - $alias{$2} = $1; + $alias{fixname($2)} = fixname($1); } elsif (/^\s*address\s+(\S+)\s+(\S+)/) { # # Set a default address for a special function register. @@ -72,22 +175,22 @@ while () { # of all registers. # # $addr{"$1"} = $2; - foreach $device (split(/[,\s]+/, $devices)) { + foreach my $device (split(/[,\s]+/, $devices)) { $addr{"p$device", "$1"} = $2; } } elsif (/^\s*bitmask\s+(\S+)\s+/) { # # Set the bitmask that will be used in the 'memmap' pragma. # - $bitmask = "$1"; - foreach $register (split(/\s+/, $')) { - $bitmask{"$register"} = $bitmask; + my $bitmask = "$1"; + foreach my $register (split(/\s+/, $')) { + $bitmasks{"$register"} = $bitmask; } } elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) { # This info is now provided in "include/pic/pic14devices.txt". #$lo = $1; #$hi = $2; - #$bitmask = $3; + #my $bitmask = $3; #foreach $device (split(/[,\s]+/, $devices)) { # $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'"; #} @@ -97,12 +200,12 @@ while () { } elsif (/^\s*(\S+)/) { $type = $1; $_ = $'; - foreach $key (split) { - eval "\$type{'$key'} = $type;"; + foreach my $key (split) { + eval "\$types{'$key'} = $type;"; } } else { - foreach $key (split) { - eval "\$type{'$key'} = $type;"; + foreach my $key (split) { + eval "\$types{'$key'} = $type;"; } } } @@ -131,8 +234,8 @@ while () { # } # Create header for pic${processor}.c file -$lcproc = "pic" . lc($processor); -$c_head = <) { - if (/^;-+ (\S+) Bits/i) { + + if (/^;-+ Register Files/i) { + $defaultType = 'sfr'; + s/;/\/\//; + $body .= "$_"; + } elsif (/^;-+\s*(\S+)\s+Bits/i || /^;-+\s*(\S+)\s+-+/i) { + # The second case is usually bits, but the word Bits is missing # also accept "UIE/UIR Bits" - foreach $name (split(/\//, $1)) { + foreach my $name (split(/\//, $1)) { + $name = fixname($name); + $name = checkname($name); + if (defined($alias{$name})) { $defaultType = "bits $alias{$name}"; } else { @@ -163,10 +282,6 @@ while (
) { } s/;/\/\//; $body .= "$_"; - } elsif (/^;-+ Register Files/i) { - $defaultType = 'sfr'; - s/;/\/\//; - $body .= "$_"; } elsif (/^;=+/i) { $defaultType = ''; s/;/\/\//; @@ -176,7 +291,7 @@ while (
) { # Convert ASM comments to C style. # $body .= "//$'"; - } elsif (/^\s*IFNDEF __(\S+)/) { + } elsif (/^\s*IFNDEF\s+__(\S+)/) { # # Processor type. # @@ -186,35 +301,37 @@ while (
) { # # Useful bit of information. # - $name = $1; - $value = $2; - $rest = $'; + my $name = $1; + my $value = $2; + my $rest = $'; + my $bitmask = "0x0000"; + $rest =~ s/;/\/\//; chomp($rest); - if (defined($type{"p$processor", "$name"})) { - $type = $type{"p$processor", "$name"}; - } elsif (defined($type{"$name"})) { - $type = $type{"$name"}; + if (defined($types{"p$processor", "$name"})) { + $type = $types{"p$processor", "$name"}; + } elsif (defined($types{"$name"})) { + $type = $types{"$name"}; } else { $type = $defaultType; } + #print "$name --> $type\n"; ## DEBUG - if (defined($bitmask{"p$processor", "$name"})) { - $bitmask = $bitmask{"p$processor", "$name"}; -# } elsif (defined($bitmask{"$name"})) { -# $bitmask = $bitmask{"$name"}; - } else { - $bitmask = "0x000"; + if (defined($bitmasks{"p$processor", "$name"})) { + $bitmask = $bitmasks{"p$processor", "$name"}; +# } elsif (defined($bitmasks{"$name"})) { +# $bitmask = $bitmasks{"$name"}; } if ($type eq 'sfr') { # # A special function register. # - $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR " - . "SFR %s\t// %s\n", - $name, $name, $bitmask, $name); +# $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR " +# . "SFR %s\t// %s\n", +# $name, $name, $bitmask, $name); + $name = fixname($name); if (defined $addr{"p$processor", "$name"}) { $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"}); } else { @@ -223,14 +340,16 @@ while (
) { $body .= sprintf("extern __sfr __at %-30s $name;$rest\n", "(${name}_ADDR)" ); $c_head .= sprintf("__sfr __at %-30s $name;\n", "(${name}_ADDR)"); $addr{"p$processor", "$name"} = "0x$value"; + $sfrs{$name}=1; } elsif ($type eq 'volatile') { # # A location that can change without # direct program manipulation. # - $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR " - . "SFR %s\t// %s\n", - $name, $name, $bitmask, $name); + $name = fixname($name); +# $pragmas .= sprintf("#pragma memmap %s_ADDR %s_ADDR " +# . "SFR %s\t// %s\n", +# $name, $name, $bitmask, $name); $body .= sprintf("extern __data __at %-30s $name;$rest\n", "(${name}_ADDR) volatile char"); $c_head .= sprintf("__data __at %-30s $name;\n", "(${name}_ADDR) volatile char"); if (defined $addr{"p$processor", "$name"}) { @@ -239,20 +358,36 @@ while (
) { $addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value); } } elsif ($type =~ /^bits/) { - ($junk, $register) = split(/\s/, $type); - $bit = hex($value); - $addr = $addr{"$register"}; + my ($junk, $register) = split(/\s/, $type); + my $bit = hex($value); + my $addr = $addr{"$register"}; + # prepare struct declaration - for ($k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) { + if (0) { # DEBUG + foreach my $key (keys %bits) { + print " $key\n"; + } + print "$register // $bit // ".$bits{"$register"}."\n"; + } + if (!defined $bits{"$register"}) { + $bits{"$register"} = {}; # reference to empty hash + } + if (!defined $bits{"$register"}->{oct($bit)}) { + $bits{"$register"}->{oct($bit)} = []; # reference to empty array + } + for (my $k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) { $name = "" if ($bits{"$register"}->{oct($bit)} eq $name) } - if ($name ne "") { + if (($name ne "") + and (1 != contained($name, \@{$bits{"$register"}->{oct($bit)}})) + ) { push @{$bits{"$register"}->{oct($bit)}}, $name; } } else { # # Other registers, bits and/or configurations. # + $name = fixname($name); if ($type eq 'other') { # # A known symbol. @@ -274,7 +409,10 @@ while (
) { # $body .= "\n"; } elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) { - $maxram .= "//\n// Memory organization.\n//\n"; + my $maxram .= "//\n// Memory organization.\n//\n"; + if (!defined $ram{"p$processor"}) { + $ram{"p$processor"} = ""; + } $pragmas = $maxram . $ram{"p$processor"} . "\n" . $pragmas; @@ -323,18 +461,73 @@ $c_head .= <) { + s/\r//g; chomp; + if(/^\s*(\*|\w*)\s*([ABCDE0-7,-]+)\s*$/) { + if(lc($1) eq lc($processor)) { + die if defined $pinfo; + $pinfo = $2; + } elsif($1 eq "*") { + die if defined $defpinfo; + $defpinfo = $2; + } + } elsif(/^\s*#/ || /^\s*$/) { + # ignore blanks, comments + } else { + die "bad line in pic14ports '$_'"; + } + } + close P14PORTS; + }; + $defpinfo = "A0-5,B0-7,C0-7,D0-7,E0-2" unless defined $defpinfo; + $pinfo = $defpinfo unless defined $pinfo; + + if(defined $pinfo) { + foreach (split /,/, $pinfo) { + if(/^([ABCDE])([0-7])-([0-7])$/) { + my($prt, $low, $high) = ($1, $2, $3); + next unless defined $sfrs{"PORT$prt"} && defined $sfrs{"TRIS$prt"}; + next if defined $bits{"PORT$prt"}; + for(my $i = $low; $i <= $high; $i++) { + push @{$bits{"PORT$prt"}->{oct($i)}}, "R$prt".$i; + } + next if defined $bits{"TRIS$prt"}; + for(my $i = $low; $i <= $high; $i++) { + push @{$bits{"TRIS$prt"}->{oct($i)}}, "TRIS$prt".$i; + } + } else { die } + } + } +} + +my $structs = ""; ## create struct declarations -foreach $reg (sort keys %bits) +foreach my $reg (sort keys %bits) { $structs .= "// ----- $reg bits --------------------\n"; $structs .= "typedef union {\n"; - $idx = 0; $max = 1; + my $idx = 0; + my $max = 1; do { $structs .= " struct {\n"; - for ($i=0; $i < 8; $i++) + for (my $i=0; $i < 8; $i++) { - @names = @{$bits{$reg}->{oct($i)}}; + if (!defined $bits{$reg}) { + #print "bits{$reg} undefined\n"; + } + if (!defined $bits{$reg}->{oct($i)}) { + #print "bits{$reg}->{".oct($i)."} undefined\n"; + $bits{$reg}->{oct($i)} = []; # empty array reference + } + my @names = @{$bits{$reg}->{oct($i)}}; if ($max < scalar @names) { $max = scalar @names; } if ($idx >= scalar @names) { $structs .= " unsigned char :1;\n"; @@ -352,26 +545,32 @@ foreach $reg (sort keys %bits) $idx++; } while ($idx < $max); $structs .= "} __${reg}_bits_t;\n"; - $structs .= "extern volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n\n"; - $c_head .= "volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n"; + #if(defined $sfrs{$reg}) { + $structs .= "extern volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n\n"; + $c_head .= "volatile __${reg}_bits_t __at(${reg}_ADDR) ${reg}_bits;\n"; + #} # emit defines for individual bits - for ($i=0; $i < 8; $i++) + $structs .= "#ifndef NO_BIT_DEFINES\n"; + for (my $i=0; $i < 8; $i++) { - @names = @{$bits{$reg}->{oct($i)}}; - foreach $field (@names) { + my @names = @{$bits{$reg}->{oct($i)}}; + foreach my $field (@names) { $structs .= sprintf("#define %-20s ${reg}_bits.$field\n", $field); } # foreach } + $structs .= "#endif /* NO_BIT_DEFINES */\n"; $structs .= "\n"; } # foreach -print $header +open(HEAD, ">$headFile") or die "Could not open $headFile for writing."; +print HEAD $header . $addresses . "\n" . $pragmas . "\n\n" . $body . "\n" . $structs . "#endif\n"; +close(HEAD); open(DEFS, ">$defsFile") or die "Could not open $defsFile for writing."; print DEFS $c_head . "\n";