* as/link/lkar.h: sgetl and sputl are independent of endianness
[fw/sdcc] / as / xa51 / xa_link.c
index 7eace8ddf19fc633afd77821906a3cd6e6a3a802..f9a81c75625b672db32ec99eff87e7d3fcfb75b3 100644 (file)
@@ -14,7 +14,9 @@
 
 /* This is a cheap hack. The xa51 has a couple of ways to scramble
    relocation info into it's opcode that the standard linker can't
-   handle. No hash or qsort yet.
+   handle, not to mention word allignment. 
+
+   No hash or qsort yet.
 
    The relocatable format looks like the known one, BUT ISN'T.
 
@@ -29,7 +31,7 @@
    "T xxxx <how> <symbol> 0"
    "R xxxx <how> <symbol> <pc+>" the relocation info. xxxx is the address
      within relative code space. How is something like REL_FF, REL_FFFF, 
-     ABS_F0FF. Symbol is the referenced symbol and pc+ is the program 
+     ABS_70FF. Symbol is the referenced symbol and pc+ is the program 
      counter that will be used to calculate the relative address (that is
      the address of the following instruction).
 
@@ -50,26 +52,31 @@ enum {
   GSINIT=1,
   CSEG,
   XINIT,
-  GSFINAL, // here goes the final output
+
+  // here goes the final output and should be used by the assembler
+  GSFINAL,
 
   // these are only for storage
   BSEG,
   DSEG,
   XSEG,
   XISEG,
+
+  // that's all
   MAX_SEGMENTS
 };
 
 enum {
   REL_FF=1,
   REL_FFFF,
+  BIT_03FF,
+  DIR_07FF,
+  DIR_70FF,
+  DIR_0700FF,
   ABS_0F,
   ABS_FF,
-  ABS_03FF,
-  ABS_07FF,
-  ABS_F0FF,
   ABS_FFFF,
-  ABS_0F00FF,
+  ABS_PC,
   MAX_REFS
 };
 
@@ -77,13 +84,14 @@ char *refModes[]={
   "???",
   "REL_FF",
   "REL_FFFF",
+  "BIT_03FF",
+  "DIR_07FF",
+  "DIR_70FF",
+  "DIR_0700FF",
   "ABS_0F",
   "ABS_FF",
-  "ABS_03FF",
-  "ABS_07FF",
-  "ABS_F0FF",
   "ABS_FFFF",
-  "ABS_0F00FF",
+  "ABS_PC"
 };
 
 #define CODESIZE 0x10000
@@ -141,6 +149,7 @@ struct SYMBOL {
 struct REFERENCE {
   char *name;
   struct MODULE *module;
+  struct SEGMENT *segment;
   int lineno;
   unsigned address, pc;
   short how;
@@ -209,7 +218,7 @@ void addToModules (char *name, int isLib) {
   module=calloc(1, sizeof(struct MODULE));
   module->name=strdup(name);
   for (s=0; s<MAX_SEGMENTS; s++) {
-    module->offset[s]=segments[s]._size;
+    module->offset[s]=(segments[s]._size+1)&0xfffffe;
   }
   module->isLib=isLib;
   if (!modules) {
@@ -226,9 +235,13 @@ void addToRefs(char *ref, int address, char *how, int pc) {
   reference=calloc(1, sizeof(struct REFERENCE));
   reference->name=strdup(ref);
   reference->module=currentModule;
+  reference->segment=currentSegment;
   reference->lineno=currentLine;
   reference->address=address;
   reference->how=howToReference(how);
+  if (reference->how==ABS_PC) {
+    reference->resolved=1;
+  }
   reference->pc=pc;
   if (!references) {
     references=reference;
@@ -241,7 +254,7 @@ void addToRefs(char *ref, int address, char *how, int pc) {
 void resolve() {
   struct REFERENCE *reference;
   for (reference=references; reference; reference=reference->next) {
-    if (findSymbolByName(reference->name)) {
+    if ((reference->how==ABS_PC) || findSymbolByName(reference->name)) {
       reference->resolved=1;
     }
   }
@@ -448,7 +461,6 @@ void readModule(char *module, int isLib) {
       }
     currentLine++;
   }
-  // that's all for now, thanks for watching */
   fclose (relModule);
 }
 
@@ -459,30 +471,24 @@ void writeModule(char *outFileName) {
   unsigned int len;
   unsigned int checksum;
 
-  fprintf (stderr, "writeModule: %s from 0x%04x to 0x%04x\n",
-          outFileName, 
-          address,
-          address+size);
-
   if ((fOut=fopen(outFileName, "w"))==NULL) {
     perror (outFileName);
   }
-  fprintf (fOut, "Just for now, make it a little bit more readable\n");
 
   while (size) {
     len = size>16 ? 16 : size;
     size-=len;
-    fprintf (fOut, ":%02X.%04X.%02X >", len, address, 0);
+    fprintf (fOut, ":%02X%04X%02X", len, address, 0);
     checksum = len + (address>>8) + (address&0xff);
     while (len--) {
       checksum += gsfinalImage[address];
-      fprintf (fOut, " %02X", gsfinalImage[address++]);
+      fprintf (fOut, "%02X", gsfinalImage[address++]);
     }
     checksum &= 0xff;
     if (checksum) {
       checksum = 0x100 - checksum;
     }
-    fprintf (fOut, " < %02X\n", checksum);
+    fprintf (fOut, "%02X\n", checksum);
   }
   fprintf (fOut, ":00000001FF\n");
 
@@ -516,6 +522,11 @@ int relocate() {
   }
 
   // GSFINAL starts at --code-loc ( -b CSEG = 0x1234 )
+  if (segments[CSEG].start & 1) {
+    fprintf (stderr, "*** error: code doesn't start at "
+            "an even address: %04x\n", segments[CSEG].start);
+    exit (1);
+  }
   segments[GSFINAL].start=segments[CSEG].start;
   memset(gsfinalImage, 0xff, CODESIZE);
 
@@ -525,6 +536,9 @@ int relocate() {
   memcpy(to, from, segments[GSINIT]._size);
   segments[GSINIT].start=segments[GSFINAL].start;
   segments[GSFINAL]._size += segments[GSINIT]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
     
   // append cseg to gsfinal
   from=csegImage;
@@ -532,6 +546,9 @@ int relocate() {
   memcpy(to, from, segments[CSEG]._size);
   segments[CSEG].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[CSEG]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
 
   // append xinit to gsfinal
   from=xinitImage;
@@ -539,8 +556,19 @@ int relocate() {
   memcpy(to, from, segments[XINIT]._size);
   segments[XINIT].start=segments[GSFINAL].start+segments[GSFINAL]._size;
   segments[GSFINAL]._size += segments[XINIT]._size;
+  if (segments[GSFINAL]._size & 1) {
+    segments[GSFINAL]._size++;
+  }
 
   // XISEG is located after XSEG
+  if (segments[XSEG].start & 1) {
+    fprintf (stderr, "*** warning: xdata doesn't start at "
+            "an even address: %04x\n", segments[XSEG].start);
+  }
+  if (segments[XSEG]._size & 1) {
+    segments[XSEG]._size++;
+  }
+  
   segments[XISEG].start=segments[XSEG].start + 
     segments[XSEG]._size;  
 
@@ -552,45 +580,70 @@ int relocate() {
   }
   // and the references
   for (reference=references; reference; reference=reference->next) {
-    if (!(symbol=findSymbolByName(reference->name))) {
-      // this reference isn't defined after all
+    symbol=findSymbolByName(reference->name);
+    if (!reference->resolved && !symbol && reference->how!=ABS_PC) {
+      // this reference isn't resolved after all
       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
               reference->module->name, reference->lineno,
               reference->name);
       fatalErrors++;
     } else {
-      reference->address += symbol->segment->start;
-      reference->pc += symbol->segment->start;
+      reference->address += 
+       reference->module->offset[reference->segment->id]+
+       reference->segment->start;
+      reference->pc += 
+       reference->module->offset[reference->segment->id]+
+       reference->segment->start;
       switch (reference->how) 
        {
-       case REL_FFFF: {
-         int rel16 = symbol->address-reference->pc;
-         if (rel16<-65536 || rel16>65534) {
-           fprintf (stderr, 
-                    "rel16 target for %s is out of range in module %s\n",
-                    reference->name, reference->module->name);
+       case REL_FF: {
+         int rel8 = symbol->address-(reference->pc & ~1);
+         if (rel8<-256 || rel8>256) {
+           fprintf (stderr,
+                    "rel8 target for %s is out of range in module %s:%d\n",
+                    reference->name, reference->module->name, 
+                    reference->lineno);
            fatalErrors++;
          }
-         gsinitImage[reference->address+1]=(rel16/2)>>8;
-         gsinitImage[reference->address]=rel16/2;
+         gsfinalImage[reference->address]=rel8/2;
          break;
        }
-       case REL_FF: {
-         int rel8 = symbol->address-reference->pc;
-         if (rel8<-256 || rel8>256) {
-           fprintf (stderr,
-                    "rel8 target for %s is out of range in module %s\n",
-                    reference->name, reference->module->name);
+       case REL_FFFF: {
+         int rel16 = symbol->address-(reference->pc & ~1);
+         if (rel16<-65536 || rel16>65534) {
+           fprintf (stderr, 
+                    "rel16 target for %s is out of range in module %s:%d\n",
+                    reference->name, reference->module->name,
+                    reference->lineno);
            fatalErrors++;
          }
-         gsinitImage[reference->address]=rel8/2;
+         gsfinalImage[reference->address]=(rel16/2)>>8;
+         gsfinalImage[reference->address+1]=rel16/2;
          break;
        }
+       case DIR_70FF:
+         gsfinalImage[reference->address] = 
+           (gsfinalImage[reference->address]&~0x70) + 
+           ((symbol->address>>4)&0x70);
+         gsfinalImage[reference->address+1] = symbol->address;
+         break;
        case ABS_FFFF:
-         gsinitImage[reference->address+1] = symbol->address>>8;
-         // fall through
+         gsfinalImage[reference->address] = symbol->address>>8;
+         gsfinalImage[reference->address+1] = symbol->address;
+         break;
        case ABS_FF:
-         gsinitImage[reference->address] = symbol->address;
+         gsfinalImage[reference->address] = symbol->address;
+         break;
+       case ABS_PC: 
+         {
+           unsigned int address=
+             (gsfinalImage[reference->address]<<8) +
+             gsfinalImage[reference->address+1];
+           address += reference->module->offset[reference->segment->id];
+           address += segments[reference->segment->id].start;
+           gsfinalImage[reference->address] = address>>8;
+           gsfinalImage[reference->address+1] = address;
+         };
          break;
        default:
          fprintf (stderr, "unsupported reference mode %d.\n",
@@ -621,7 +674,6 @@ int scanLibraries(int unresolved) {
   for (nlp=0; nlp<nlibPaths; nlp++) {
     for (nlf=0; nlf<nlibFiles; nlf++) {
       sprintf (libFiles, "%s/%s.lib", libraryPaths[nlp], libraryFiles[nlf]);
-      //fprintf (stderr, "  %s\n", libFiles);
       if ((lfs=fopen(libFiles,"r"))==NULL) {
        continue;
       }
@@ -629,15 +681,13 @@ int scanLibraries(int unresolved) {
        // remove trailing \n
        line[strlen(line)-1]='\0';
        sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
-       //fprintf (stderr, "    %s\n", libFile);
-       if ((lf=fopen(libFile,"r"))==0) {
+       if ((lf=fopen(libFile,"r"))==NULL) {
          continue;
        }
        while (fgets(line, 132, lf)) {
          int dummy; // we need this to get the right count of the next sscanf
          if (sscanf(line, "S %[^ ] Def%04x", symName, &dummy)==2) {
            if (isUnresolved(symName, 1)) {
-             //fprintf (stderr, "%s:%s\n", libFile, symName);
              readModule(libFile,1);
              if (resolved++ == unresolved) {
                // we are done
@@ -746,7 +796,6 @@ int main(int argc, char **argv) {
   addToDefs("s_XISEG", 0, 0);
   addToDefs("l_XISEG", segments[XISEG]._size, 1);
 
-#if 1
   // mark the resolved references
   resolve();
 
@@ -770,7 +819,6 @@ int main(int argc, char **argv) {
   if (unresolved==0) {
     writeModule(outFileName);
   }
-#endif
 
   // the modules
   fprintf (mapOut, "Modules:\n");