Address space 'z' was missing.
[fw/sdcc] / as / xa51 / xa_link.c
index c083f9294e71204d9f98ae29c475630ec3935227..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
 
 /* 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.
 
 
    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, 
    "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).
 
      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,
   GSINIT=1,
   CSEG,
   XINIT,
-  //GSFINAL, // do we need this?
+
+  // here goes the final output and should be used by the assembler
+  GSFINAL,
 
   // these are only for storage
   BSEG,
   DSEG,
   XSEG,
   XISEG,
 
   // these are only for storage
   BSEG,
   DSEG,
   XSEG,
   XISEG,
+
+  // that's all
   MAX_SEGMENTS
 };
 
 enum {
   REL_FF=1,
   REL_FFFF,
   MAX_SEGMENTS
 };
 
 enum {
   REL_FF=1,
   REL_FFFF,
+  BIT_03FF,
+  DIR_07FF,
+  DIR_70FF,
+  DIR_0700FF,
   ABS_0F,
   ABS_FF,
   ABS_0F,
   ABS_FF,
-  ABS_03FF,
-  ABS_07FF,
-  ABS_F0FF,
   ABS_FFFF,
   ABS_FFFF,
-  ABS_0F00FF,
+  ABS_PC,
   MAX_REFS
 };
 
   MAX_REFS
 };
 
@@ -77,23 +84,24 @@ char *refModes[]={
   "???",
   "REL_FF",
   "REL_FFFF",
   "???",
   "REL_FF",
   "REL_FFFF",
+  "BIT_03FF",
+  "DIR_07FF",
+  "DIR_70FF",
+  "DIR_0700FF",
   "ABS_0F",
   "ABS_FF",
   "ABS_0F",
   "ABS_FF",
-  "ABS_03FF",
-  "ABS_07FF",
-  "ABS_F0FF",
   "ABS_FFFF",
   "ABS_FFFF",
-  "ABS_0F00FF",
+  "ABS_PC"
 };
 
 #define CODESIZE 0x10000
 
 int fatalErrors=0;
 
 };
 
 #define CODESIZE 0x10000
 
 int fatalErrors=0;
 
-char gsinitImage[CODESIZE];
-char csegImage[CODESIZE];
-char xinitImage[CODESIZE];
-//char gsfinalImage[CODESIZE];
+unsigned char gsinitImage[CODESIZE];
+unsigned char csegImage[CODESIZE];
+unsigned char xinitImage[CODESIZE];
+unsigned char gsfinalImage[CODESIZE];
 
 struct SEGMENT {
   short id;
 
 struct SEGMENT {
   short id;
@@ -109,7 +117,7 @@ struct SEGMENT {
   {GSINIT,  "GSINIT",  0, 0, 0, 0, gsinitImage},
   {CSEG,    "CSEG",    0, 0, 0, 0, csegImage},
   {XINIT,   "XINIT",   0, 0, 0, 0, xinitImage},
   {GSINIT,  "GSINIT",  0, 0, 0, 0, gsinitImage},
   {CSEG,    "CSEG",    0, 0, 0, 0, csegImage},
   {XINIT,   "XINIT",   0, 0, 0, 0, xinitImage},
-  //{GSFINAL, "GSFINAL", 0, 0, 0, 0, NULL},
+  {GSFINAL, "GSFINAL", 0, 0, 0, 0, gsfinalImage},
 
   {BSEG,    "BSEG",    0, 0, 0, 0, NULL},
   {DSEG,    "DSEG",    0, 0, 0, 0, NULL},
 
   {BSEG,    "BSEG",    0, 0, 0, 0, NULL},
   {DSEG,    "DSEG",    0, 0, 0, 0, NULL},
@@ -141,6 +149,7 @@ struct SYMBOL {
 struct REFERENCE {
   char *name;
   struct MODULE *module;
 struct REFERENCE {
   char *name;
   struct MODULE *module;
+  struct SEGMENT *segment;
   int lineno;
   unsigned address, pc;
   short how;
   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=calloc(1, sizeof(struct MODULE));
   module->name=strdup(name);
   for (s=0; s<MAX_SEGMENTS; s++) {
-    module->offset[s]=segments[s].current;
+    module->offset[s]=(segments[s]._size+1)&0xfffffe;
   }
   module->isLib=isLib;
   if (!modules) {
   }
   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=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);
   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;
   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) {
 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;
     }
   }
       reference->resolved=1;
     }
   }
@@ -365,6 +378,7 @@ void readModule(char *module, int isLib) {
        }
        // double check repeated 'A' records
        if (currentModule->size[currentSegment->id]) {
        }
        // double check repeated 'A' records
        if (currentModule->size[currentSegment->id]) {
+         // pleased to meet you again, I hope ...
          if (currentModule->size[currentSegment->id] != size) {
            fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
                     module, currentLine,
          if (currentModule->size[currentSegment->id] != size) {
            fprintf (stderr, "*** %s:%d error %s size %d != %d\n",
                     module, currentLine,
@@ -372,13 +386,10 @@ void readModule(char *module, int isLib) {
                     currentModule->size[currentSegment->id], 
                     size);
            fatalErrors++;
                     currentModule->size[currentSegment->id], 
                     size);
            fatalErrors++;
-         } else {
-           // pleased to meet you again
          }
        } else {
          }
        } else {
-         currentModule->size[currentSegment->id]=size;
-         currentModule->offset[currentSegment->id]+=currentSegment->_size;
          currentSegment->_size += size;
          currentSegment->_size += size;
+         currentModule->size[currentSegment->id] = size;
        }
        // never mind about the flags for now
        break;
        }
        // never mind about the flags for now
        break;
@@ -413,7 +424,6 @@ void readModule(char *module, int isLib) {
        char *tline=NULL;
        if (currentSegment->id!=CSEG && 
            currentSegment->id!=GSINIT &&
        char *tline=NULL;
        if (currentSegment->id!=CSEG && 
            currentSegment->id!=GSINIT &&
-           //currentSegment->id!=GSFINAL &&
            currentSegment->id!=XINIT) {
          fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
                   module, currentLine, currentSegment->name);
            currentSegment->id!=XINIT) {
          fprintf (stderr, "%s:%d cannot emit bytes in %s\n",
                   module, currentLine, currentSegment->name);
@@ -423,7 +433,9 @@ void readModule(char *module, int isLib) {
          fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
          fatalErrors++;
        }
          fprintf (stderr, "%s:%d error in T record\n", module, currentLine);
          fatalErrors++;
        }
-       address+=currentSegment->current;
+
+       address+=currentModule->offset[currentSegment->id];
+       //address+=currentSegment->current;
        for ( ;
              (tline=strtok(NULL, " \t\n")) && 
                (sscanf(tline, "%02x", &byte)==1);
        for ( ;
              (tline=strtok(NULL, " \t\n")) && 
                (sscanf(tline, "%02x", &byte)==1);
@@ -434,11 +446,11 @@ void readModule(char *module, int isLib) {
        break;
       }
       case 'R': {
        break;
       }
       case 'R': {
-       unsigned address, from;
+       unsigned address, pc;
        char symbol[132];
        char how[32];
        char symbol[132];
        char how[32];
-       sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &from);
-       addToRefs (symbol, address, how, from);
+       sscanf (line, "R %x %[^ ] %[^ ] %x", &address, how, symbol, &pc);
+       addToRefs (symbol, address, how, pc);
        break;
       }
       default:
        break;
       }
       default:
@@ -449,17 +461,37 @@ void readModule(char *module, int isLib) {
       }
     currentLine++;
   }
       }
     currentLine++;
   }
-  // that's all for now, thanks for watching */
   fclose (relModule);
 }
 
 void writeModule(char *outFileName) {
   FILE *fOut;
   fclose (relModule);
 }
 
 void writeModule(char *outFileName) {
   FILE *fOut;
+  unsigned int address=segments[GSFINAL].start;
+  unsigned int size=segments[GSFINAL]._size;
+  unsigned int len;
+  unsigned int checksum;
 
   if ((fOut=fopen(outFileName, "w"))==NULL) {
     perror (outFileName);
   }
 
   if ((fOut=fopen(outFileName, "w"))==NULL) {
     perror (outFileName);
   }
-  // oops, forgot something :) */
+
+  while (size) {
+    len = size>16 ? 16 : size;
+    size-=len;
+    fprintf (fOut, ":%02X%04X%02X", len, address, 0);
+    checksum = len + (address>>8) + (address&0xff);
+    while (len--) {
+      checksum += gsfinalImage[address];
+      fprintf (fOut, "%02X", gsfinalImage[address++]);
+    }
+    checksum &= 0xff;
+    if (checksum) {
+      checksum = 0x100 - checksum;
+    }
+    fprintf (fOut, "%02X\n", checksum);
+  }
+  fprintf (fOut, ":00000001FF\n");
+
   fclose (fOut);
 }
 
   fclose (fOut);
 }
 
@@ -467,9 +499,9 @@ int relocate() {
   struct SYMBOL *symbol;
   struct REFERENCE *reference;
   char *from, *to;
   struct SYMBOL *symbol;
   struct REFERENCE *reference;
   char *from, *to;
-  int length=segments[GSINIT].current +
-    segments[CSEG].current +
-    segments[XINIT].current;
+  int length=segments[GSINIT]._size +
+    segments[CSEG]._size +
+    segments[XINIT]._size;
   int unresolved=0;
 
   // first check if it will fit
   int unresolved=0;
 
   // first check if it will fit
@@ -489,23 +521,57 @@ int relocate() {
     return unresolved;
   }
 
     return unresolved;
   }
 
-  // GSINIT gets the --code-loc
-  segments[GSINIT].start=segments[CSEG].start;
-  segments[CSEG].start=segments[GSINIT].start+segments[GSINIT]._size;
-  // concat cseg and gsinit
+  // 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);
+
+  // copy gsinit to gsfinal
+  from = gsinitImage;
+  to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
+  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;
   from=csegImage;
-  to=&gsinitImage[segments[GSINIT].start+segments[GSINIT]._size];
+  to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
   memcpy(to, from, segments[CSEG]._size);
   memcpy(to, from, segments[CSEG]._size);
-  segments[XINIT].start=segments[CSEG].start+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;
   from=xinitImage;
-  to+=segments[CSEG]._size;
+  to = gsfinalImage + segments[GSFINAL].start + segments[GSFINAL]._size;
   memcpy(to, from, segments[XINIT]._size);
   memcpy(to, from, segments[XINIT]._size);
-#if 0
-  from=gsfinalImage;
-  to+=segments[XINIT]._size;
-  memcpy(to, from, segments[GSFINAL]._size);
-#endif
-  segments[XISEG].start=segments[XSEG].start+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;  
+
   // now relocate the defined symbols
   for (symbol=symbols; symbol; symbol=symbol->next) {
     if (!symbol->absolute) {
   // now relocate the defined symbols
   for (symbol=symbols; symbol; symbol=symbol->next) {
     if (!symbol->absolute) {
@@ -514,44 +580,70 @@ int relocate() {
   }
   // and the references
   for (reference=references; reference; reference=reference->next) {
   }
   // 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 {
       fprintf (stderr, "*** %s:%d undefined symbol %s\n",
               reference->module->name, reference->lineno,
               reference->name);
       fatalErrors++;
     } else {
-      reference->address += 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) 
        {
       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++;
          }
            fatalErrors++;
          }
-         gsinitImage[reference->address+1]=(rel16/2)>>8;
-         gsinitImage[reference->address]=rel16/2;
+         gsfinalImage[reference->address]=rel8/2;
          break;
        }
          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++;
          }
            fatalErrors++;
          }
-         gsinitImage[reference->address]=rel8/2;
+         gsfinalImage[reference->address]=(rel16/2)>>8;
+         gsfinalImage[reference->address+1]=rel16/2;
          break;
        }
          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:
        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:
        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",
          break;
        default:
          fprintf (stderr, "unsupported reference mode %d.\n",
@@ -582,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]);
   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;
       }
       if ((lfs=fopen(libFiles,"r"))==NULL) {
        continue;
       }
@@ -590,15 +681,13 @@ int scanLibraries(int unresolved) {
        // remove trailing \n
        line[strlen(line)-1]='\0';
        sprintf (libFile, "%s/%s", libraryPaths[nlp], line);
        // 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)) {
          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
              readModule(libFile,1);
              if (resolved++ == unresolved) {
                // we are done
@@ -701,11 +790,11 @@ int main(int argc, char **argv) {
 
   // add the segment symbols
   currentSegment=findSegmentByName("XINIT");
 
   // add the segment symbols
   currentSegment=findSegmentByName("XINIT");
-  addToDefs("s_XINIT", segments[XINIT].start, 0);
-  addToDefs("l_XINIT", segments[XINIT]._size, 0);
+  addToDefs("s_XINIT", 0, 0);
+  addToDefs("l_XINIT", segments[XINIT]._size, 1);
   currentSegment=findSegmentByName("XISEG");
   currentSegment=findSegmentByName("XISEG");
-  addToDefs("s_XISEG", segments[XISEG].start, 0);
-  addToDefs("l_XISEG", segments[XISEG]._size, 0);
+  addToDefs("s_XISEG", 0, 0);
+  addToDefs("l_XISEG", segments[XISEG]._size, 1);
 
   // mark the resolved references
   resolve();
 
   // mark the resolved references
   resolve();
@@ -738,7 +827,8 @@ int main(int argc, char **argv) {
     for (s=0; s<MAX_SEGMENTS; s++) {
       if (module->size[s]) {
        fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
     for (s=0; s<MAX_SEGMENTS; s++) {
       if (module->size[s]) {
        fprintf (mapOut, "\t\t%s:0x%04x-0x%04x\n", segments[s].name,
-                module->offset[s], module->offset[s]+module->size[s]);
+                module->offset[s]+segments[s].start,
+                module->offset[s]+segments[s].start+module->size[s]);
       }
     }
   }
       }
     }
   }
@@ -763,7 +853,6 @@ int main(int argc, char **argv) {
             symbol->address, symbol->module->name);
   }
 
             symbol->address, symbol->module->name);
   }
 
-  writeModule(outFileName);
   fclose(mapOut);
   return fatalErrors? 1 : 0;
 }
   fclose(mapOut);
   return fatalErrors? 1 : 0;
 }