Added strcmpi.[hc] to gbz80 and z80 VC projects
[fw/sdcc] / as / mcs51 / lkarea.c
index 608e3e151a7d079b7512f2ea34e9c117501437a7..96a91307beec5863a725115295c67055014202bd 100644 (file)
@@ -37,7 +37,7 @@
  *  The function newarea() creates and/or modifies area
  *  and areax structures for each A directive read from
  *  the .rel file(s).  The function lkparea() is called
- *  to find tha area structure associated with this name.
+ *  to find the area structure associated with this name.
  *  If the area does not yet exist then a new area
  *  structure is created and linked to any existing
  *  linked area structures. The area flags are copied
@@ -137,6 +137,11 @@ newarea()
 /*          lkerr++; */
 /*      } */
     }
+    /*
+     * Evaluate area address
+     */
+    skip(-1);
+    axp->a_addr = eval();
     /*
      * Place pointer in header area list
      */
@@ -483,23 +488,74 @@ lnksect(register struct area *tap)
     }
 }
 
-void lnksect2 (struct area *tap, int rloc);
+Addr_T lnksect2 (struct area *tap, int locIndex);
 char idatamap[256];
-long codemap[524288];
+unsigned long codemap[524288];
+unsigned long xdatamap[131072];
 
 /*Modified version of the functions for packing variables in internal data memory*/
 VOID lnkarea2 (void)
 {
     Addr_T rloc[4]={0, 0, 0, 0};
+    Addr_T gs_size = 0;
     int  locIndex;
     char temp[NCPS];
     struct sym *sp;
     int j;
-    struct area *dseg_ap=NULL;
+    struct area *dseg_ap = NULL;
+    struct area *abs_ap = NULL;
+    struct area *gs0_ap = NULL;
     struct sym *sp_dseg_s=NULL, *sp_dseg_l=NULL;
 
     for(j=0; j<256; j++) idatamap[j]=' ';
     memset(codemap, 0, sizeof(codemap));
+    memset(xdatamap, 0, sizeof(xdatamap));
+
+    /* first sort all absolute areas to the front */
+    ap = areap;
+    /* no need to check first area, it's in front anyway */
+    while (ap && ap->a_ap)
+    {
+        if (ap->a_ap->a_flag & A_ABS)
+        {/* next area is absolute, move it to front,
+            reversed sequence is no problem for absolutes */
+            abs_ap = ap->a_ap;
+            ap->a_ap = abs_ap->a_ap;
+            abs_ap->a_ap = areap;
+            areap = abs_ap;
+        }
+        else
+        {
+            ap = ap->a_ap;
+        }
+    }
+
+    /* next accumulate all GSINITx/GSFINAL area sizes
+       into GSINIT so they stay together */
+    ap = areap;
+    while (ap)
+    {
+        if (!strncmp(ap->a_id, "GS", 2))
+        {/* GSxxxxx area */
+            if (ap->a_size == 0)
+            {
+                axp = ap->a_axp;
+                while (axp)
+                {
+                    ap->a_size += axp->a_size;
+                    axp = axp->a_axp;
+                }
+            }
+            gs_size += ap->a_size;
+            if (!strcmp(ap->a_id, "GSINIT0"))
+            {/* GSINIT0 area */
+                gs0_ap = ap;
+            }
+        }
+        ap = ap->a_ap;
+    }
+    if (gs0_ap)
+        gs0_ap->a_size = gs_size;
 
     ap = areap;
     while (ap)
@@ -510,7 +566,7 @@ VOID lnkarea2 (void)
         else if (ap->a_flag & A_BIT)   locIndex = 3;
         else locIndex = 0;
 
-        if (ap->a_flag&A_ABS) /* Absolute sections */
+        if (ap->a_flag & A_ABS) /* Absolute sections */
         {
             lnksect2(ap, locIndex);
         }
@@ -518,12 +574,11 @@ VOID lnkarea2 (void)
         {
             if (ap->a_type == 0)
             {
-                ap->a_addr=rloc[locIndex];
-                ap->a_type=1;
+                ap->a_addr = rloc[locIndex];
+                ap->a_type = 1;
             }
 
-            lnksect2(ap, locIndex);
-            rloc[locIndex] = ap->a_addr + ap->a_size;
+            rloc[locIndex] = lnksect2(ap, locIndex);
         }
 
         /*
@@ -555,7 +610,7 @@ VOID lnkarea2 (void)
         to compute the byte size of BSEG_BYTES: */
         if (!strcmp(ap->a_id, "BSEG"))
         {
-                ap->a_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
+            ap->a_ap->a_axp->a_size = ((ap->a_addr + ap->a_size + 7)/8); /*Bits to bytes*/
         }
         else if (!strcmp(ap->a_id, "DSEG"))
         {
@@ -573,26 +628,93 @@ VOID lnkarea2 (void)
     }
     if(sp_dseg_s!=NULL) sp_dseg_s->s_addr=0;
     if(sp_dseg_l!=NULL) sp_dseg_l->s_addr=dseg_ap->a_size;
+}
 
-#if 0
-    /*Print the memory map*/
-    fprintf(stderr, "Internal RAM layout:\n"
-           "      0 1 2 3 4 5 6 7 8 9 A B C D E F");
-    for(j=0; j<256; j++)
+static
+Addr_T find_empty_space(Addr_T start, Addr_T size, unsigned long *map)
+{
+    int i, j, k;
+    unsigned long mask, b;
+
+    while (1)
     {
-        if(j%16==0) fprintf(stderr, "\n0x%02x:|", j);
-        fprintf(stderr, "%c|", idatamap[j]);
+        Addr_T a = start;
+        i = start >> 5;
+        j = (start + size) >> 5;
+        mask = -(1 << (start & 0x1F));
+
+        while (i < j)
+        {
+            if (map[i] & mask)
+            {
+                k = 32;
+                for (b=0x80000000; b!=0; b>>=1, k--)
+                {
+                    if (map[i] & b)
+                      break;
+                }
+                start = a + k;
+                break;
+            }
+            i++;
+            mask = 0xFFFFFFFF;
+            a += 32;
+        }
+        if (start > a)
+          continue;
+
+        mask &= (1 << ((start + size) & 0x1F)) - 1;
+        if (map[i] & mask)
+        {
+            k = 32;
+            for (b=0x80000000; b!=0; b>>=1, k--)
+            {
+                if (map[i] & b)
+                    break;
+            }
+            start = (a & ~0x1F) + k;
+        }
+        if (start <= a)
+          break;
     }
-    fprintf(stderr, "\n0-3:Reg Banks, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack\n");
-#endif
+    return start;
 }
 
-void lnksect2 (struct area *tap, int rloc)
+static
+Addr_T allocate_space(Addr_T start, Addr_T size, char* id, unsigned long *map)
+{
+    int i, j;
+    unsigned long mask;
+    Addr_T a = start;
+    i = start >> 5;
+    j = (start + size) >> 5;
+    mask = -(1 << (start & 0x1F));
+
+    while (i < j)
+    {
+        if (map[i] & mask)
+        {
+            fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+        }
+        map[i++] |= mask;
+        mask = 0xFFFFFFFF;
+        a += 32;
+    }
+    mask &= (1 << ((start + size) & 0x1F)) - 1;
+    if (map[i] & mask)
+    {
+        fprintf(stderr, "memory overlap near 0x%X for %s\n", a, id);
+    }
+    map[i] |= mask;
+    return start;
+}
+
+Addr_T lnksect2 (struct area *tap, int locIndex)
 {
     register Addr_T size, addr;
     register struct areax *taxp;
     int j, k, ramlimit;
-    char fchar, dchar='a';
+    char fchar=' ', dchar='a';
     char ErrMsg[]="?ASlink-Error-Could not get %d consecutive byte%s"
                   " in internal RAM for area %s.\n";
 
@@ -627,7 +749,7 @@ void lnksect2 (struct area *tap, int rloc)
     taxp = tap->a_axp;
 
     /*Use a letter to identify each area in the internal RAM layout map*/
-    if(rloc==0)
+    if (locIndex==0)
     {
         /**/ if(!strcmp(tap->a_id, "DSEG"))
             fchar='D'; /*It will be converted to letters 'a' to 'z' later for each areax*/
@@ -652,9 +774,15 @@ void lnksect2 (struct area *tap, int rloc)
         else
             fchar=' ';/*???*/
     }
-    else
+    else if (locIndex == 1)
     {
-        fchar=' ';
+        /**/ if(!strcmp(tap->a_id, "GSINIT"))
+            fchar='G';
+    }
+    else if (locIndex == 2)
+    {
+        /**/ if(!strcmp(tap->a_id, "XSTK"))
+            fchar='K';
     }
 
     if (tap->a_flag&A_OVR) /* Overlayed sections */
@@ -736,7 +864,7 @@ void lnksect2 (struct area *tap, int rloc)
                         fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
                         lkerr++;
                     }
-               }
+                }
 
                 for(j=0; j<ramlimit; j++)
                 {
@@ -820,8 +948,38 @@ void lnksect2 (struct area *tap, int rloc)
             taxp = taxp->a_axp;
         }
     }
+    else if (tap->a_flag & A_ABS) /* Absolute sections */
+    {
+        while (taxp)
+        {
+            if (locIndex == 0)
+            {
+                for (j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<ramlimit); j++)
+                    idatamap[j] = 'A';
+            }
+            if (locIndex == 1)
+            {
+                allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, codemap);
+            }
+            if (locIndex == 2)
+            {
+                allocate_space(taxp->a_addr, taxp->a_size, tap->a_id, xdatamap);
+            }
+            taxp->a_addr = 0; /* reset to zero so relative addresses become absolute */
+            size += taxp->a_size;
+            taxp = taxp->a_axp;
+        }
+    }
     else /* Concatenated sections */
     {
+        if ((locIndex == 1) && tap->a_size)
+        {
+            addr = find_empty_space(addr, tap->a_size, codemap);
+        }
+        if ((locIndex == 2) && tap->a_size)
+        {
+            addr = find_empty_space(addr, tap->a_size, xdatamap);
+        }
         while (taxp)
         {
             if( (fchar=='D') || (fchar=='I') )
@@ -880,35 +1038,20 @@ void lnksect2 (struct area *tap, int rloc)
             }
             else /*For concatenated BIT, CODE, and XRAM areax's*/
             {
-                if(!strcmp(tap->a_id, "XSTK") && (taxp->a_size == 1))
+                if((fchar=='K') && (taxp->a_size == 1))
                 {
                     taxp->a_size = 256-(addr & 0xFF);
                 }
-                //should find next unused address now!!!
-                //but let's first just warn for overlaps
-                if (rloc == 1)
+                //find next unused address now
+                if ((locIndex == 1) && taxp->a_size)
                 {
-                    int a = addr;
-                    int i = addr >> 5;
-                    int j = (addr + taxp->a_size) >> 5;
-                    long mask = -(1 << (addr & 0x1F));
-
-                    while (i < j)
-                    {
-                        if (codemap[i] & mask)
-                        {
-                            fprintf(stderr, "memory overlap near 0x%X for %s\n", a, tap->a_id);
-                        }
-                        codemap[i++] |= mask;
-                        mask = 0xFFFFFFFF;
-                        a += 32;
-                    }
-                    mask &= (1 << ((addr + taxp->a_size) & 0x1F)) - 1;
-                    if (codemap[i] & mask)
-                    {
-                        fprintf(stderr, "memory overlap near 0x%X for %s\n", a, tap->a_id);
-                    }
-                    codemap[i] |= mask;
+                    addr = find_empty_space(addr, taxp->a_size, codemap);
+                    allocate_space(addr, taxp->a_size, tap->a_id, codemap);
+                }
+                if ((locIndex == 2) && taxp->a_size)
+                {
+                    addr = find_empty_space(addr, taxp->a_size, xdatamap);
+                    allocate_space(addr, taxp->a_size, tap->a_id, xdatamap);
                 }
                 taxp->a_addr = addr;
                 addr += taxp->a_size;
@@ -932,4 +1075,5 @@ void lnksect2 (struct area *tap, int rloc)
         "\n?ASlink-Warning-Paged Area %8s Boundary Error\n", tap->a_id);
         lkerr++;
     }
+    return addr;
 }