$rcsid = q~$Id$~;
($junk, $file, $version, $date, $time, $programmer, $status)
= split(/\s+/, $rcsid);
-($programName) = ($file =~ /(\S+),v/);
+($programName) = ($file =~ /(\S+)/);
if ($#ARGV < 0 || $#ARGV > 1 ) {
Usage();
}
-$processor = shift;
+$processor = uc(shift);
$path = shift;
-$processor = uc $processor;
-$path = "/usr/share/gpasm" if ($path eq '');
+
+# 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";
+ }
+ $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;
+}
+
+
+if ($^O eq 'MSWin32') {
+ if ($path eq '') {
+ if (defined($path = $ENV{'GPUTILS_HEADER_PATH'}) || defined($path = $ENV{'GPUTILS_LKR_PATH'})) {
+ $path .= '\\..';
+ }
+ else {
+ die "Could not find gpasm includes.\n";
+ }
+ }
+ $path_delim = '\\';
+}
+else {
+ # Nathan Hurst <njh@mail.csse.monash.edu.au>: find gputils on Debian
+ if ($path eq '') {
+ if ( -x "/usr/share/gputils") {
+ $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";
+ }
+ }
+ $path_delim = '/';
+}
#
# Read the symbols at the end of this file.
# 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.
$bitmask{"$register"} = $bitmask;
}
} elsif (/^\s*ram\s+(\S+)\s+(\S+)\s+(\S+)/) {
- $lo = $1;
- $hi = $2;
- $bitmask = $3;
- foreach $device (split(/[,\s]+/, $devices)) {
- $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
- }
+ # This info is now provided in "include/pic/pic14devices.txt".
+ #$lo = $1;
+ #$hi = $2;
+ #$bitmask = $3;
+ #foreach $device (split(/[,\s]+/, $devices)) {
+ # $ram{"p$device"} .= "#pragma memmap $lo $hi RAM $bitmask$'";
+ #}
} elsif (/^\s*processor\s+/) {
$devices = $';
$type = '';
# }
# }
+# Create header for pic${processor}.c file
+$lcproc = "pic" . lc($processor);
+$c_head = <<EOT;
+/* Register definitions for $lcproc.
+ * This file was automatically generated by:
+ * $programName V$version
+ * Copyright (c) 2002, Kevin L. Pauba, All Rights Reserved
+ */
+#include <${lcproc}.h>
+
+EOT
+
#
# Convert the file.
#
+%sfrs = ();
$defaultType = 'other';
-$includeFile = "$path/header/p" . lc $processor . ".inc";
+$includeFile = $path.$path_delim.'header'.$path_delim.'p'.lc($processor).'.inc';
+$headFile = "pic" . lc($processor) . ".h";
+$defsFile = "pic" . lc($processor) . ".c";
open(HEADER, "<$includeFile")
|| die "$programName: Error: Cannot open include file $includeFile ($!)\n";
while (<HEADER>) {
- if (/^;-* (\S+) Bits/i) {
- if (defined($alias{$1})) {
- $defaultType = "bits $alias{$1}";
- } else {
- $defaultType = "bits $1";
- }
+
+ if (/^;-+ Register Files/i) {
+ $defaultType = 'sfr';
s/;/\/\//;
$body .= "$_";
- } elsif (/^;-* Register Files/i) {
- $defaultType = 'sfr';
+ } 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)) {
+ $name = fixname($name);
+ $name = checkname($name);
+
+ if (defined($alias{$name})) {
+ $defaultType = "bits $alias{$name}";
+ } else {
+ $defaultType = "bits $name";
+ }
+ }
s/;/\/\//;
$body .= "$_";
- } elsif (/^;=*/i) {
+ } elsif (/^;=+/i) {
$defaultType = '';
s/;/\/\//;
$body .= "$_";
# Convert ASM comments to C style.
#
$body .= "//$'";
- } elsif (/^\s*IFNDEF __(\S+)/) {
+ } elsif (/^\s*IFNDEF\s+__(\S+)/) {
#
# Processor type.
#
#
# 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 {
$addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $value);
}
- $body .= sprintf("sfr at %-30s %s;$rest\n", "${name}_ADDR", $name);
+ $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);
- $body .= sprintf("data at %-30s %s;$rest\n", "${name}_ADDR volatile char", $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"}) {
$addresses .= sprintf("#define %s_ADDR\t0x%s\n", $name, $addr{"p$processor", "$name"});
} else {
($junk, $register) = split(/\s/, $type);
$bit = hex($value);
$addr = $addr{"$register"};
- $body .= "BIT_AT(${register}_ADDR,$bit)\t$name;$rest\n";
+ # prepare struct declaration
+ for ($k=0; $k < scalar @{$bits{"$register"}->{oct($bit)}}; $k++) {
+ $name = "" if ($bits{"$register"}->{oct($bit)} eq $name)
+ }
+ 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.
#
$body .= "\n";
} elsif (/__MAXRAM\s+H'([0-9a-fA-F]+)'/) {
- $maxram .= "//\n// Memory organization.\n//\n"
- . sprintf("#pragma maxram 0x%s\n\n", $1);
+ $maxram .= "//\n// Memory organization.\n//\n";
$pragmas = $maxram
. $ram{"p$processor"} . "\n"
. $pragmas;
#ifndef P${processor}_H
#define P${processor}_H
-#ifndef BIT_AT
-#define BIT_AT(base,bitno) bit at ((base<<3)+bitno)
-#endif
-
//
// Register addresses.
//
EOT
-print $header
+$c_head .= <<EOT;
+
+//
+// bitfield definitions
+//
+EOT
+
+# Add PORT* and TRIS* bit entries
+# file format is:
+# 16f84 A0-4,B0-7
+# * A0-5,B0-7,C0-7,D0-7,E0-2
+{
+ my $pinfo = undef;
+ my $defpinfo = undef;
+ open(P14PORTS, "< pic14ports.txt") && do {
+ while(<P14PORTS>) {
+ 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 }
+ }
+ }
+}
+
+$structs = "";
+## create struct declarations
+foreach $reg (sort keys %bits)
+{
+ $structs .= "// ----- $reg bits --------------------\n";
+ $structs .= "typedef union {\n";
+ $idx = 0; $max = 1;
+ do {
+ $structs .= " struct {\n";
+ for ($i=0; $i < 8; $i++)
+ {
+ @names = @{$bits{$reg}->{oct($i)}};
+ if ($max < scalar @names) { $max = scalar @names; }
+ if ($idx >= scalar @names) {
+ $structs .= " unsigned char :1;\n";
+ } else { # (1 == scalar @names) {
+ $structs .= " unsigned char " . $names[$idx] . ":1;\n";
+# } else {
+# $structs .= " union {\n";
+# foreach $name (@names) {
+# $structs .= " unsigned char " . $name . ":1;\n";
+# } # foreach
+# $structs .= " };\n";
+ }
+ } # for
+ $structs .= " };\n";
+ $idx++;
+ } while ($idx < $max);
+ $structs .= "} __${reg}_bits_t;\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++)
+ {
+ @names = @{$bits{$reg}->{oct($i)}};
+ foreach $field (@names) {
+ $structs .= sprintf("#define %-20s ${reg}_bits.$field\n", $field);
+ } # foreach
+ }
+ $structs .= "\n";
+} # foreach
+
+open(HEAD, ">$headFile") or die "Could not open $headFile for writing.";
+print HEAD $header
. $addresses . "\n"
. $pragmas . "\n\n"
- . $body
+ . $body . "\n"
+ . $structs
. "#endif\n";
+close(HEAD);
+
+open(DEFS, ">$defsFile") or die "Could not open $defsFile for writing.";
+print DEFS $c_head . "\n";
+close DEFS;
sub Usage {
print STDERR <<EOT;
alias OPTION_REG OPTION
volatile INDF PCL
-
-#
-# bitmask settings.
-#
-processor 16F84
- bitmask 0x080 INDF PCL STATUS FSR PCLATH INTCON
-
-processor 16F873, 16F874, 16F877, 16F627, 16F628, 16F876
- bitmask 0x180 INDF PCL STATUS FSR PCLATH INTCON
- bitmask 0x100 TMR0 OPTION_REG PORTB TRISB
-
-#
-# Memory maps.
-#
-processor 16F84
- ram 0x000C 0x004f 0x080
-
-processor 16F627, 16F628
- ram 0x0020 0x006f 0x000
- ram 0x0070 0x007f 0x180
- ram 0x00a0 0x00ef 0x000
- ram 0x0120 0x014f 0x000
-
-processor 16F876, 16F877
- ram 0x0020 0x006f 0x000
- ram 0x0070 0x007f 0x180
- ram 0x00a0 0x00ef 0x000
- ram 0x0110 0x016f 0x000
- ram 0x0190 0x01ef 0x000
-
-processor 16F873, 16F874
- ram 0x0020 0x007f 0x100
- ram 0x00a0 0x00ff 0x100
-