Linker places variables in unused register banks. Call using -Wl-Y[stack_size]
authorjesusc <jesusc@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 4 Jan 2004 14:18:23 +0000 (14:18 +0000)
committerjesusc <jesusc@4a8a32a2-be11-0410-ad9d-d568d2c75423>
Sun, 4 Jan 2004 14:18:23 +0000 (14:18 +0000)
git-svn-id: https://sdcc.svn.sourceforge.net/svnroot/sdcc/trunk/sdcc@3077 4a8a32a2-be11-0410-ad9d-d568d2c75423

ChangeLog
as/mcs51/aslink.h
as/mcs51/lkarea.c
as/mcs51/lkdata.c
as/mcs51/lkmain.c
as/mcs51/lkmem.c

index 3b094f6211f94eb83b36436e8fcd7051790207fa..0ad486335ddcdb2fa1c269c0257bd310bf8326e9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,13 @@
+2004-01-04  Jesus Calvino-Fraga <jesusc@ece.ubc.ca>
+
+       * as/mcs51/aslink.h, as/mcs51/lkarea.c, as/mcs51/lkdata.c,
+       as/mcs51/lkmain.c, as/mcs51/lkmem.c: 8051 linker can now pack
+       variables in unused register banks.  Also the SSEG is placed
+       wherever there is enough space for it, and IDATA can be anywhere
+       in internal RAM.  For now compile using -Wl-Y[stack_size].
+       The mem file is different for this option as well, since it
+       makes no sense of talking about DSEG lenght.
+
 2004-01-02 Vangelis Rokas <vrokas@otenet.gr>
 
        * src/SDCClrange.c: fixed bug 869095 that caused segfault
index 263467a07e5d0c3df7609e366ae13a53c4bf05e9..ff4cb8da9842a1970e15641694372821910d9b79 100644 (file)
@@ -244,6 +244,7 @@ struct      area
        struct  areax   *a_axp; /* Area extension link */
        Addr_T  a_addr;         /* Beginning address of area */
        Addr_T  a_size;         /* Total size of the area */
+       Addr_T  a_unaloc;       /* Total number of unalocated bytes, for error reporting */
        char    a_type;         /* Area subtype */
        char    a_flag;         /* Flag byte */
        char    a_id[NCPS];     /* Name */
@@ -577,6 +578,8 @@ extern      int     mflag;          /*      Map output flag
                                 */
 extern int     sflag;          /*      JCF: Memory usage output flag
                                 */
+extern int     packflag_and_stacksize; /*      Pack data memory flag
+                                */
 extern int     jflag;          /*      NoICE output flag
                                 */
 extern int     xflag;          /*      Map file radix type flag
@@ -685,6 +688,7 @@ extern      VOID            chop_crlf();
 /* lkarea.c */
 extern VOID            lkparea();
 extern VOID            lnkarea();
+extern VOID            lnkarea2();
 extern VOID            lnksect();
 extern VOID            newarea();
 
@@ -769,6 +773,7 @@ extern void             DefineNoICE( char *name, Addr_T value, int page );
 
 /* JCF: lkmem.c */
 extern int summary(struct area * xp);
+extern int summary2(struct area * xp);
 
 /* JCF: lkaomf51.c */
 extern void SaveLinkedFilePath(char * filepath);
index d13f104ea186fc9d682e3fa584567ff62fc5b735..4431868284d3c6436bf1a5879fc2a84a7dc48a58 100644 (file)
@@ -474,3 +474,325 @@ register struct area *tap;
            lkerr++;
        }
 }
+
+void lnksect2 (struct area *tap, int rloc);
+char idatamap[256];
+
+/*Modified version of the functions for packing variables in internal data memory*/
+VOID lnkarea2 (void)
+{
+    Addr_T rloc[4]={0, 0, 0, 0};
+       int  locIndex;
+       char temp[NCPS];
+       struct sym *sp;
+       int j;
+    struct area *dseg_ap=NULL;
+       struct sym *sp_dseg_s, *sp_dseg_l;
+
+       for(j=0; j<256; j++) idatamap[j]=' ';
+
+       ap = areap;
+       while (ap)
+       {
+               /* Determine memory space */
+             if (ap->a_flag & A_CODE)  locIndex = 1;
+        else if (ap->a_flag & A_XDATA) locIndex = 2;
+        else if (ap->a_flag & A_BIT)   locIndex = 3;
+        else locIndex = 0;
+
+        if (ap->a_flag&A_ABS) /* Absolute sections */
+               {
+                       lnksect2(ap, locIndex);
+               }
+               else /* Relocatable sections */
+               {
+                       if (ap->a_type == 0)
+            {
+                               ap->a_addr=rloc[locIndex];
+                               ap->a_type=1;
+                       }
+                       
+                       lnksect2(ap, locIndex);
+                       rloc[locIndex] = ap->a_addr + ap->a_size;
+               }
+
+               /*
+                * Create symbols called:
+                *      s_<areaname>    the start address of the area
+                *      l_<areaname>    the length of the area
+                */
+
+               if (! symeq(ap->a_id, _abs_))
+               {
+                       strncpy(temp+2,ap->a_id,NCPS-2);
+                       *(temp+1) = '_';
+
+                       *temp = 's';
+                       sp = lkpsym(temp, 1);
+                       sp->s_addr = ap->a_addr ;
+                       sp->s_type |= S_DEF;
+            if (!strcmp(ap->a_id, "DSEG")) sp_dseg_s=sp;
+
+                       *temp = 'l';
+                       sp = lkpsym(temp, 1);
+                       sp->s_addr = ap->a_size;
+                       sp->s_axp = NULL;
+                       sp->s_type |= S_DEF;
+            if (!strcmp(ap->a_id, "DSEG")) sp_dseg_l=sp;
+               }
+               
+               /*Since area BSEG is defined just before BSEG_BYTES, use the bit size of BSEG
+               to compute the byte size of BSEG_BYTES: */
+               if (!strcmp(ap->a_id, "BSEG"))
+        {
+                       ap->a_ap->a_axp->a_size=(ap->a_addr/8)+((ap->a_size+7)/8); /*Bits to bytes*/
+               }
+        else if (!strcmp(ap->a_id, "DSEG"))
+        {
+            dseg_ap=ap; /*Need it later to set its correct size*/
+        }
+               ap = ap->a_ap;
+       }
+
+    /*Compute the size of DSEG*/
+    dseg_ap->a_addr=0;
+    dseg_ap->a_size=0;
+    for(j=0; j<0x80; j++) if(idatamap[j]!=' ') dseg_ap->a_size++;
+    sp_dseg_s->s_addr=0;
+    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++)
+       {
+               if(j%16==0) fprintf(stderr, "\n0x%02x:|", j);
+               fprintf(stderr, "%c|", idatamap[j]);
+       }
+       fprintf(stderr, "\n0-3:Reg Banks, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack\n");
+#endif
+}
+
+void lnksect2 (struct area *tap, int rloc)
+{
+       register Addr_T size, addr;
+       register struct areax *taxp;
+       int j, k, ramlimit;
+    char fchar, dchar='a';
+    char ErrMsg[]="?ASlink-Error-Could not get %d consecutive byte%s" 
+                  " in internal RAM for area %s.\n";
+
+    tap->a_unaloc=0;
+    
+    /*Notice that only ISEG and SSEG can be in the indirectly addressable internal RAM*/
+    if( (!strcmp(tap->a_id, "ISEG")) || (!strcmp(tap->a_id, "SSEG")) )
+    {
+        if((iram_size<=0)||(iram_size>0x100))
+            ramlimit=0x100;
+        else
+            ramlimit=iram_size;
+    }
+    else
+    {
+        ramlimit=0x80;
+    }
+
+       size = 0;
+       addr = tap->a_addr;
+       if ((tap->a_flag&A_PAG) && (addr & 0xFF))
+    {
+           fprintf(stderr,
+           "\n?ASlink-Warning-Paged Area %8s Boundary Error\n", tap->a_id);
+           lkerr++;
+       }
+       taxp = tap->a_axp;
+
+    /*Use a letter to identify each area in the internal RAM layout map*/
+    if(rloc==0)
+    {
+        /**/ if(!strcmp(tap->a_id, "DSEG"))
+            fchar='D'; /*It will be converted to letters 'a' to 'z' latter for each areax*/
+        else if(!strcmp(tap->a_id, "ISEG"))
+            fchar='I';
+        else if(!strcmp(tap->a_id, "SSEG"))
+            fchar='S';
+        else if(!strcmp(tap->a_id, "OSEG"))
+            fchar='Q';
+        else if(!strcmp(tap->a_id, "REG_BANK_0"))
+            fchar='0';
+        else if(!strcmp(tap->a_id, "REG_BANK_1"))
+            fchar='1';
+        else if(!strcmp(tap->a_id, "REG_BANK_2"))
+            fchar='2';
+        else if(!strcmp(tap->a_id, "REG_BANK_3"))
+            fchar='3';
+        else if(!strcmp(tap->a_id, "BSEG_BYTES"))
+            fchar='B';
+        else
+            fchar=' ';/*???*/
+    }
+    else
+    {
+        fchar=' ';
+    }
+
+       if (tap->a_flag&A_OVR) /* Overlayed sections */
+    {
+        while (taxp)
+        {
+            if ( (fchar=='0')||(fchar=='1')||(fchar=='2')||(fchar=='3') ) /*Reg banks*/
+            {
+                addr=(fchar-'0')*8;
+                taxp->a_addr=addr;
+                size=taxp->a_size;
+                for(j=addr; (j<(int)(addr+taxp->a_size)) && (j<ramlimit); j++)
+                    idatamap[j]=fchar;
+            }
+            else if( (fchar=='S') || (fchar=='Q') ) /*Overlay and stack in internal RAM*/
+            {
+                /*Find the size of the space currently used for this areax overlay*/
+                for(j=0, size=0; j<ramlimit; j++)
+                    if(idatamap[j]==fchar) size++;
+
+                /*If more space required, release the previously allocated areax in 
+                internal RAM and search for a bigger one*/
+                if((int)taxp->a_size>size)
+                {
+                    size=(int)taxp->a_size;
+
+                    for(j=0; j<ramlimit; j++)
+                        if(idatamap[j]==fchar) idatamap[j]=' ';
+               
+                    /*Search for a space large enough in data memory for this overlay areax*/
+                    for(j=0, k=0; j<ramlimit; j++)
+                    {
+                        if(idatamap[j]==' ')
+                            k++;
+                        else
+                            k=0;
+                        if(k==(int)taxp->a_size) break;
+                    }
+
+                    if(k==(int)taxp->a_size)
+                    {
+                        taxp->a_addr = j-k+1;
+                        if(addr<(unsigned int)ramlimit)
+                        {
+                            for(j=ramlimit-1; (j>=0)&&(idatamap[j]==' '); j--);
+                            if(j>=0) addr=j+1;
+                        }
+                    }
+                
+                    /*Mark the memory used for overlay*/
+                    if(k==(int)taxp->a_size)
+                    {
+                        for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<ramlimit); j++)
+                            idatamap[j]=fchar;
+
+                        /*Set the new size of the data memory area*/
+                        size=ramlimit-addr;
+                    }
+                    else /*Couldn't find a chunk big enough: report the problem.*/
+                    {
+                        tap->a_unaloc=taxp->a_size;
+                        fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                        lkerr++;
+                    }
+               }
+                
+                for(j=0; j<ramlimit; j++)
+                {
+                    if (idatamap[j]==fchar)
+                    {
+                        addr=j;
+                        tap->a_addr=addr;
+                                       taxp->a_addr=addr;
+                        break;
+                    }
+                }
+            }
+            else /*Overlay areas not in internal ram*/
+            {
+                           taxp->a_addr = addr;
+                           if (taxp->a_size > size) size = taxp->a_size;
+            }
+            taxp = taxp->a_axp;
+               }
+       }
+    else /* Concatenated sections */
+    {
+               while (taxp)
+        {
+                       if( (fchar=='D') || (fchar=='I') )
+                       {
+                if(taxp->a_size)
+                {
+                    /*Search for a space large enough in internal RAM for this areax*/
+                    for(j=0, k=0; j<ramlimit; j++)
+                    {
+                        if(idatamap[j]==' ')
+                            k++;
+                        else
+                            k=0;
+                        if(k==(int)taxp->a_size) break;
+                    }
+
+                    if(k==(int)taxp->a_size)
+                    {
+                        taxp->a_addr = j-k+1;
+                        if(addr<(unsigned int)ramlimit)
+                        {
+                            for(j=ramlimit-1; (j>=0)&&(idatamap[j]==' '); j--);
+                            if(j>=0) addr=j+1;
+                            size=ramlimit-addr;
+                        }
+                        
+                        for(j=taxp->a_addr; (j<(int)(taxp->a_addr+taxp->a_size)) && (j<ramlimit); j++)
+                            idatamap[j]=(fchar=='D')?dchar:fchar;
+                        if((taxp->a_size>0)&&(fchar=='D'))dchar++;
+                        if((dchar<'a')||(dchar>'z')) dchar='D'; /*Ran out of letters?*/
+                    }
+                    else /*We are in trouble, there is not enough memory for an areax chunk*/
+                    {
+                        taxp->a_addr = addr;
+                        addr += taxp->a_size;
+                                   size += taxp->a_size;
+                        tap->a_unaloc+=taxp->a_size;
+                        fprintf(stderr, ErrMsg, taxp->a_size, taxp->a_size>1?"s":"", tap->a_id);
+                        lkerr++;
+                    }
+               }
+                          taxp = taxp->a_axp;
+                       }
+            else if(fchar=='B')
+            {
+                if(taxp->a_size!=0)
+                {
+                    for(j=0x20+taxp->a_addr; j<((int)(0x20+taxp->a_addr+taxp->a_size)); j++)
+                        idatamap[j]=fchar;
+                }
+
+                               taxp->a_addr = addr;
+                           addr += taxp->a_size;
+                           size += taxp->a_size;
+                           taxp = taxp->a_axp;
+            }
+            else /*For concatenated BIT, CODE, and XRAM areax's*/
+            {
+                               taxp->a_addr = addr;
+                           addr += taxp->a_size;
+                           size += taxp->a_size;
+                           taxp = taxp->a_axp;
+            }
+               }
+       }
+       tap->a_size = size;
+
+       if ((tap->a_flag&A_PAG) && (size > 256))
+       {
+           fprintf(stderr,
+           "\n?ASlink-Warning-Paged Area %8s Length Error\n", tap->a_id);
+           lkerr++;
+       }
+}
index d6a3517539160973f779e6521f2244f90549519a..1840ee794f617f346f777c331855369736e08497 100644 (file)
@@ -55,6 +55,8 @@ int   mflag;          /*      Map output flag
                         */
 int    sflag;          /*      JCF: Memory usage output flag
                         */
+int    packflag_and_stacksize=0;       /*      JCF: Pack internal memory flag
+                        */
 int    aflag;          /*      Overlapping area warning flag
                         */
 int    jflag;          /*      NoICE output flag
index 548a44fdf53ba6e222c337bba8c1681192fff450..fd9e4d070788f16b28036905f9fe5fd0c4f95532 100644 (file)
@@ -79,7 +79,7 @@ void Areas51 (void)
 {
        char * rel[]={
                "XH",
-               "H 7 areas 0 global symbols",
+               "H B areas 0 global symbols",
                "A _CODE size 0 flags 0",               /*Each .rel has one, so...*/
                "A REG_BANK_0 size 0 flags 4",  /*Register banks are overlayable*/
                "A REG_BANK_1 size 0 flags 4",
@@ -87,6 +87,10 @@ void Areas51 (void)
                "A REG_BANK_3 size 0 flags 4",
                "A BSEG size 0 flags 80",               /*BSEG must be just before BITS*/
                "A BSEG_BYTES size 0 flags 0",  /*Size will be obtained from BSEG in lnkarea()*/
+               "A DSEG size 0 flags 0",
+               "A OSEG size 0 flags 4",
+               "A ISEG size 0 flags 0",
+               "A SSEG size 0 flags 4",
                ""
        };
        int j;
@@ -105,6 +109,10 @@ void Areas51 (void)
                else if (!strcmp(ap->a_id, "REG_BANK_2")) { ap->a_addr=0x10; ap->a_type=1; }
                else if (!strcmp(ap->a_id, "REG_BANK_3")) { ap->a_addr=0x18; ap->a_type=1; }
                else if (!strcmp(ap->a_id, "BSEG_BYTES")) { ap->a_addr=0x20; ap->a_type=1; }
+               else if (!strcmp(ap->a_id, "SSEG"))
+        {
+            if(packflag_and_stacksize>1) ap->a_axp->a_size=packflag_and_stacksize;
+        }
        }
 }
 
@@ -308,7 +316,10 @@ char *argv[];
                        /*
                         * Link all area addresses.
                         */
-                       lnkarea();
+                       if(!packflag_and_stacksize)
+                lnkarea();
+            else
+                lnkarea2();
                        /*
                         * Process global definitions.
                         */
@@ -335,9 +346,18 @@ char *argv[];
                                map();
 
                        if (sflag) /*JCF: memory usage summary output*/
-                               if(summary(areap))lkexit(1);
+            {
+                if(!packflag_and_stacksize)
+                {
+                                   if(summary(areap)) lkexit(1);
+                }
+                else
+                {
+                                   if(summary2(areap)) lkexit(1);
+                }
+            }
 
-                       if (iram_size)
+                       if ((iram_size) && (!packflag_and_stacksize))
                                iramcheck();
 
                        /*
@@ -776,10 +796,15 @@ parse()
                                        break;
 
                                case 'y': /*JCF: memory usage summary output*/
-                               case 'Y':
                                        ++sflag;
                                        break;
 
+                case 'Y':
+                    unget(getnb());
+                    /*The stack segment default size is 16 bytes.  Use -Yxx for xx bytes*/
+                    packflag_and_stacksize=(ip && *ip)?expr(0):16;
+                    break;
+
                                case 'j':
                                case 'J':
                                        jflag = 1;
@@ -858,7 +883,7 @@ parse()
                                        return(0);
 
                                case 'z':
-                                case 'Z':
+                case 'Z':
                                        dflag = 1;                                      
                                        return(0);
                                default:
index 54fb0628ab062e98a78ab18222c579c349a55cd9..0184e396c71fea124d438e03c68515b619b44124 100644 (file)
@@ -349,3 +349,157 @@ int summary(struct area * areap)
        fclose(of);
        return toreturn;                
 }
+
+extern char idatamap[]; //0:not used, 1:used
+
+
+int summary2(struct area * areap) 
+{
+       #define EQ(A,B) !as_strcmpi((A),(B))
+       #define MIN_STACK 16
+
+       char buff[128];
+       int j, toreturn=0;
+    long int Stack_Start=0;
+
+       struct area * xp;
+       FILE * of;
+       
+       /*Artifacts used for printing*/
+       char start[15], end[15], size[15], max[15];
+       char format[]="   %-16.16s %-8.8s %-8.8s %-8.8s %-8.8s\n";
+       char line[]="---------------------";
+
+       typedef struct
+       {
+               unsigned long Start;
+               unsigned long Size;
+               unsigned long Max;
+               char Name[NCPS];
+               unsigned long flag;
+       } _Mem;
+       
+       _Mem Stack={0xff,   0,     1, "STACK",                          0x0000};
+       _Mem XRam= {0xffff, 0, 65536, "EXTERNAL RAM",           0x0100};
+       _Mem Rom=  {0xffff, 0, 65536, "ROM/EPROM/FLASH",        0x0200};
+       
+       if(rflag) /*For the DS390*/
+       {
+               XRam.Max=0x1000000; /*24 bits*/
+               XRam.Start=0xffffff;
+               Rom.Max=0x1000000;
+               Rom.Start=0xffffff;
+       }
+
+       /* Open Memory Summary File*/
+       of = afile(linkp->f_idp, "mem", 1);
+       if (of == NULL)
+       {
+               lkexit(1);
+       }
+
+       xp=areap;
+       while (xp)
+       {
+               if( EQ(xp->a_id, "CSEG") || EQ(xp->a_id, "GSINIT") ||
+                                EQ(xp->a_id, "GSFINAL") || EQ(xp->a_id, "HOME") )
+               {
+                       Rom.Size+=xp->a_size;
+                       if(xp->a_addr<Rom.Start) Rom.Start=xp->a_addr;
+               }
+               
+               else if (EQ(xp->a_id, "SSEG"))
+               {
+                       Stack.Size+=xp->a_size;
+                       if(xp->a_addr<Stack.Start) Stack.Start=xp->a_addr;
+               }
+
+               else if (EQ(xp->a_id, "XSEG") || EQ(xp->a_id, "XISEG")) 
+               {
+                       XRam.Size+=xp->a_size;
+                       if(xp->a_addr<XRam.Start) XRam.Start=xp->a_addr;
+               }
+
+               xp=xp->a_ap;
+       }
+
+       /*Report the Ram totals*/
+       fprintf(of, "Internal RAM layout:\n");
+       fprintf(of, "      0 1 2 3 4 5 6 7 8 9 A B C D E F");
+    for(j=0; j<256; j++)
+       {
+               if(j%16==0) fprintf(of, "\n0x%02x:|", j);
+               fprintf(of, "%c|", idatamap[j]);
+       }
+       fprintf(of, "\n0-3:Reg Banks, a-z:Data, B:Bits, Q:Overlay, I:iData, S:Stack\n");
+
+    for(j=0; j<256; j++)
+    {
+        if(idatamap[j]=='S')
+        {
+            Stack_Start=j;
+            break;
+        }
+    }
+    
+       xp=areap;
+       while (xp)
+    {
+        if(xp->a_unaloc>0)
+        {
+            fprintf(of, "\nERROR: Couldn't get %d byte%s allocated" 
+                        " in internal RAM for area %s.",
+                        xp->a_unaloc, xp->a_unaloc>1?"s":"", xp->a_id);
+            toreturn=1;
+        }
+               xp=xp->a_ap;
+    }
+
+       /*Report the position of the begining of the stack*/
+    if(Stack_Start!=256)
+           fprintf(of, "\n%stack starts at: 0x%02lx (sp set to 0x%02lx)",
+                   rflag ? "16 bit mode initial s" : "S", Stack_Start, Stack_Start-1);
+    else
+        fprintf(of, "\nI don't have a clue where the stack ended up! Sorry...");
+
+       fprintf(of, "\n\nOther memory:\n");
+       fprintf(of, format, "Name", "Start", "End", "Size", "Max");
+       fprintf(of, format, line, line, line, line, line);
+
+       /*Report XRam totals:*/
+       sprintf(start, "0x%04lx", XRam.Start);
+       if(XRam.Size==0)
+               end[0]=0;/*Empty string*/
+       else
+               sprintf(end,  "0x%04lx", XRam.Size+XRam.Start-1);
+       sprintf(size, "%5lu", XRam.Size);
+       sprintf(max, "%5lu", xram_size<0?XRam.Max:xram_size);
+       fprintf(of, format, XRam.Name, start, end, size, max);
+
+       /*Report Rom/Flash totals:*/
+       sprintf(start, "0x%04lx", Rom.Start);
+       if(Rom.Size==0)
+               end[0]=0;/*Empty string*/
+       else
+               sprintf(end,  "0x%04lx", Rom.Size+Rom.Start-1);
+       sprintf(size, "%5lu", Rom.Size);
+       sprintf(max, "%5lu", code_size<0?Rom.Max:code_size);
+       fprintf(of, format, Rom.Name, start, end, size, max);
+
+       /*Report any excess:*/
+       if( ((XRam.Start+XRam.Size)>XRam.Max) ||
+               (((int)XRam.Size>xram_size)&&(xram_size>=0)) )
+       {
+               sprintf(buff, "Insufficient EXTERNAL RAM memory.\n");
+               REPORT_ERROR(buff, 1);
+       }
+       if( ((Rom.Start+Rom.Size)>Rom.Max) ||
+               (((int)Rom.Size>code_size)&&(code_size>=0)) )
+       {
+               sprintf(buff, "Insufficient ROM/EPROM/FLASH memory.\n");
+               REPORT_ERROR(buff, 1);
+       }
+
+       fclose(of);
+       return toreturn;                
+}