]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Replaced builtin linker configs with ordinary .cfg files.
[cc65] / src / ld65 / config.c
index e9ee811390bb9e07a2d9470f447b4025e73c1881..70fa63b545f064c329c7fcda08283f495c9eaedb 100644 (file)
@@ -6,7 +6,7 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2011, Ullrich von Bassewitz                                      */
+/* (C) 1998-2012, Ullrich von Bassewitz                                      */
 /*                Roemerstrasse 52                                           */
 /*                D-70794 Filderstadt                                        */
 /* EMail:         uz@cc65.org                                                */
@@ -47,6 +47,8 @@
 #include "bitops.h"
 #include "check.h"
 #include "print.h"
+#include "segdefs.h"
+#include "target.h"
 #include "xmalloc.h"
 #include "xsprintf.h"
 
@@ -102,6 +104,7 @@ static Collection       MemoryAreas = STATIC_COLLECTION_INITIALIZER;
 #define MA_DEFINE              0x0010
 #define MA_FILL                0x0020
 #define MA_FILLVAL             0x0040
+#define MA_BANK         0x0080
 
 /* Segment list */
 static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
@@ -116,6 +119,7 @@ static Collection       SegDescList = STATIC_COLLECTION_INITIALIZER;
 #define SA_OFFSET      0x0040
 #define SA_START       0x0080
 #define SA_OPTIONAL     0x0100
+#define SA_FILLVAL      0x0200
 
 /* Symbol types used in the CfgSymbol structure */
 typedef enum {
@@ -351,6 +355,7 @@ static SegDesc* NewSegDesc (unsigned Name)
     S->Seg           = 0;
     S->Attr          = 0;
     S->Flags         = 0;
+    S->FillVal       = 0;
     S->RunAlignment  = 1;
     S->LoadAlignment = 1;
 
@@ -405,13 +410,14 @@ static void ParseMemory (void)
 /* Parse a MEMORY section */
 {
     static const IdentTok Attributes [] = {
-               {   "START",    CFGTOK_START    },
-       {   "SIZE",     CFGTOK_SIZE     },
-        {   "TYPE",     CFGTOK_TYPE     },
-        {   "FILE",     CFGTOK_FILE     },
+        {   "BANK",     CFGTOK_BANK     },
         {   "DEFINE",   CFGTOK_DEFINE   },
+        {   "FILE",     CFGTOK_FILE     },
        {   "FILL",     CFGTOK_FILL     },
                {   "FILLVAL",  CFGTOK_FILLVAL  },
+       {   "SIZE",     CFGTOK_SIZE     },
+               {   "START",    CFGTOK_START    },
+        {   "TYPE",     CFGTOK_TYPE     },
     };
     static const IdentTok Types [] = {
                {   "RO",       CFGTOK_RO       },
@@ -442,21 +448,17 @@ static void ParseMemory (void)
            /* Check which attribute was given */
            switch (AttrTok) {
 
-               case CFGTOK_START:
-                   FlagAttr (&M->Attr, MA_START, "START");
-                    M->StartExpr = CfgExpr ();
-                   break;
-
-               case CFGTOK_SIZE:
-                   FlagAttr (&M->Attr, MA_SIZE, "SIZE");
-                   M->SizeExpr = CfgExpr ();
+               case CFGTOK_BANK:
+                   FlagAttr (&M->Attr, MA_BANK, "BANK");
+                   M->BankExpr = CfgExpr ();
                    break;
 
-               case CFGTOK_TYPE:
-                   FlagAttr (&M->Attr, MA_TYPE, "TYPE");
-                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
-                   if (CfgTok == CFGTOK_RO) {
-                       M->Flags |= MF_RO;
+               case CFGTOK_DEFINE:
+                   FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
+                   /* Map the token to a boolean */
+                   CfgBoolToken ();
+                   if (CfgTok == CFGTOK_TRUE) {
+                       M->Flags |= MF_DEFINE;
                    }
                     CfgNextTok ();
                    break;
@@ -469,16 +471,6 @@ static void ParseMemory (void)
                     CfgNextTok ();
                    break;
 
-               case CFGTOK_DEFINE:
-                   FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
-                   /* Map the token to a boolean */
-                   CfgBoolToken ();
-                   if (CfgTok == CFGTOK_TRUE) {
-                       M->Flags |= MF_DEFINE;
-                   }
-                    CfgNextTok ();
-                   break;
-
                case CFGTOK_FILL:
                    FlagAttr (&M->Attr, MA_FILL, "FILL");
                    /* Map the token to a boolean */
@@ -494,6 +486,25 @@ static void ParseMemory (void)
                    M->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
                    break;
 
+               case CFGTOK_SIZE:
+                   FlagAttr (&M->Attr, MA_SIZE, "SIZE");
+                   M->SizeExpr = CfgExpr ();
+                   break;
+
+               case CFGTOK_START:
+                   FlagAttr (&M->Attr, MA_START, "START");
+                    M->StartExpr = CfgExpr ();
+                   break;
+
+               case CFGTOK_TYPE:
+                   FlagAttr (&M->Attr, MA_TYPE, "TYPE");
+                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "TYPE");
+                   if (CfgTok == CFGTOK_RO) {
+                       M->Flags |= MF_RO;
+                   }
+                    CfgNextTok ();
+                   break;
+
                default:
                    FAIL ("Unexpected attribute token");
 
@@ -629,6 +640,7 @@ static void ParseSegments (void)
         {   "ALIGN",            CFGTOK_ALIGN            },
         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
         {   "DEFINE",           CFGTOK_DEFINE           },
+        {   "FILLVAL",          CFGTOK_FILLVAL          },
                {   "LOAD",             CFGTOK_LOAD             },
        {   "OFFSET",           CFGTOK_OFFSET           },
         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
@@ -698,6 +710,12 @@ static void ParseSegments (void)
                     CfgNextTok ();
                    break;
 
+                case CFGTOK_FILLVAL:
+                   FlagAttr (&S->Attr, SA_FILLVAL, "FILLVAL");
+                   S->FillVal = (unsigned char) CfgCheckedConstExpr (0, 0xFF);
+                    S->Flags |= SF_FILLVAL;
+                   break;
+
                case CFGTOK_LOAD:
                    FlagAttr (&S->Attr, SA_LOAD, "LOAD");
                    S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
@@ -1025,11 +1043,12 @@ static void ParseConDes (void)
 /* Parse the CONDES feature */
 {
     static const IdentTok Attributes [] = {
-               {   "SEGMENT",          CFGTOK_SEGMENT          },
-       {   "LABEL",            CFGTOK_LABEL            },
        {   "COUNT",            CFGTOK_COUNT            },
-       {   "TYPE",             CFGTOK_TYPE             },
+        {   "IMPORT",           CFGTOK_IMPORT           },
+       {   "LABEL",            CFGTOK_LABEL            },
        {   "ORDER",            CFGTOK_ORDER            },
+               {   "SEGMENT",          CFGTOK_SEGMENT          },
+       {   "TYPE",             CFGTOK_TYPE             },
     };
 
     static const IdentTok Types [] = {
@@ -1044,9 +1063,10 @@ static void ParseConDes (void)
     };
 
     /* Attribute values. */
-    unsigned SegName = INVALID_STRING_ID;
-    unsigned Label   = INVALID_STRING_ID;
     unsigned Count   = INVALID_STRING_ID;
+    unsigned Label   = INVALID_STRING_ID;
+    unsigned SegName = INVALID_STRING_ID;
+    ConDesImport Import;
     /* Initialize to avoid gcc warnings: */
     int Type = -1;
     ConDesOrder Order = cdIncreasing;
@@ -1054,11 +1074,12 @@ static void ParseConDes (void)
     /* Bitmask to remember the attributes we got already */
     enum {
        atNone          = 0x0000,
-       atSegName       = 0x0001,
-       atLabel         = 0x0002,
-       atCount         = 0x0004,
-       atType          = 0x0008,
-       atOrder         = 0x0010
+       atCount         = 0x0001,
+        atImport        = 0x0002,
+       atLabel         = 0x0004,
+       atOrder         = 0x0008,
+       atSegName       = 0x0010,
+       atType          = 0x0020,
     };
     unsigned AttrFlags = atNone;
 
@@ -1077,50 +1098,34 @@ static void ParseConDes (void)
        /* Check which attribute was given */
        switch (AttrTok) {
 
-           case CFGTOK_SEGMENT:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atSegName, "SEGMENT");
+           case CFGTOK_COUNT:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atCount, "COUNT");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               SegName = GetStrBufId (&CfgSVal);
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               Count = GetStrBufId (&CfgSVal);
                break;
 
-           case CFGTOK_LABEL:
+           case CFGTOK_IMPORT:
                /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atLabel, "LABEL");
+               FlagAttr (&AttrFlags, atImport, "IMPORT");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Label = GetStrBufId (&CfgSVal);
-               break;
+               CfgAssureIdent ();
+               /* Remember value and position for later */
+                       Import.Name = GetStrBufId (&CfgSVal);
+                Import.Pos = CfgErrorPos;
+                Import.AddrSize = ADDR_SIZE_ABS;
+               break;
 
-           case CFGTOK_COUNT:
+           case CFGTOK_LABEL:
                /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atCount, "COUNT");
+               FlagAttr (&AttrFlags, atLabel, "LABEL");
                /* We expect an identifier */
-               CfgAssureIdent ();
-               /* Remember the value for later */
-               Count = GetStrBufId (&CfgSVal);
-               break;
-
-           case CFGTOK_TYPE:
-               /* Don't allow this twice */
-               FlagAttr (&AttrFlags, atType, "TYPE");
-               /* The type may be given as id or numerical */
-               if (CfgTok == CFGTOK_INTCON) {
-                   CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
-                   Type = (int) CfgIVal;
-               } else {
-                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
-                   switch (CfgTok) {
-                       case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
-                       case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
-                        case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
-                       default: FAIL ("Unexpected type token");
-                   }
-               }
-               break;
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               Label = GetStrBufId (&CfgSVal);
+               break;
 
            case CFGTOK_ORDER:
                /* Don't allow this twice */
@@ -1133,6 +1138,33 @@ static void ParseConDes (void)
                }
                break;
 
+           case CFGTOK_SEGMENT:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atSegName, "SEGMENT");
+               /* We expect an identifier */
+               CfgAssureIdent ();
+               /* Remember the value for later */
+               SegName = GetStrBufId (&CfgSVal);
+               break;
+
+           case CFGTOK_TYPE:
+               /* Don't allow this twice */
+               FlagAttr (&AttrFlags, atType, "TYPE");
+               /* The type may be given as id or numerical */
+               if (CfgTok == CFGTOK_INTCON) {
+                   CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
+                   Type = (int) CfgIVal;
+               } else {
+                   CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
+                   switch (CfgTok) {
+                       case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
+                       case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
+                        case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
+                       default: FAIL ("Unexpected type token");
+                   }
+               }
+               break;
+
            default:
                FAIL ("Unexpected attribute token");
 
@@ -1167,6 +1199,9 @@ static void ParseConDes (void)
     if (AttrFlags & atCount) {
        ConDesSetCountSym (Type, Count);
     }
+    if (AttrFlags & atImport) {
+       ConDesSetImport (Type, &Import);
+    }
     if (AttrFlags & atOrder) {
        ConDesSetOrder (Type, Order);
     }
@@ -1553,22 +1588,22 @@ static void ProcessSegments (void)
     while (I < CollCount (&SegDescList)) {
 
         /* Get the next segment descriptor */
-       SegDesc* S = CollAtUnchecked (&SegDescList, I);
+       SegDesc* S = CollAtUnchecked (&SegDescList, I);
 
         /* Search for the actual segment in the input files. The function may
          * return NULL (no such segment), this is checked later.
          */
         S->Seg = SegFind (S->Name);
 
-       /* If the segment is marked as BSS style, and if the segment exists
+       /* If the segment is marked as BSS style, and if the segment exists
          * in any of the object file, check that there's no initialized data
          * in the segment.
-        */
-       if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
+        */
+       if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
                    CfgWarning (GetSourcePos (S->LI),
                         "Segment `%s' with type `bss' contains initialized data",
-                       GetString (S->Name));
-       }
+                       GetString (S->Name));
+       }
 
        /* If this segment does exist in any of the object files, insert the
                 * segment into the load/run memory areas. Otherwise print a warning
@@ -1584,6 +1619,9 @@ static void ProcessSegments (void)
                MemoryInsert (S->Load, S);
            }
 
+            /* Use the fill value from the config */
+            S->Seg->FillVal = S->FillVal;
+
             /* Process the next segment descriptor in the next run */
             ++I;
 
@@ -1809,6 +1847,9 @@ unsigned CfgProcess (void)
            /* Get the segment */
            SegDesc* S = CollAtUnchecked (&M->SegList, J);
 
+            /* Remember the start address before handling this segment */
+            unsigned long StartAddr = Addr;
+
             /* Some actions depend on wether this is the load or run memory
              * area.
              */
@@ -1865,10 +1906,11 @@ unsigned CfgProcess (void)
                  */
                 S->Seg->PC = Addr;
                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
-                S->Seg->Relocatable = M->Relocatable;
 
-                /* Remember that this segment is placed */
-                S->Seg->Placed = 1;
+                /* Remember the run memory for this segment, which is also a
+                 * flag that the segment has been placed.
+                 */
+                S->Seg->MemArea = M;
 
             } else if (S->Load == M) {
 
@@ -1882,6 +1924,13 @@ unsigned CfgProcess (void)
 
             }
 
+            /* If this is the load memory area and the segment doesn't have a
+             * fill value defined, use the one from the memory area.
+             */
+            if (S->Load == M && (S->Flags & SF_FILLVAL) == 0) {
+                S->Seg->FillVal = M->FillVal;
+            }
+
            /* Increment the fill level of the memory area and check for an
             * overflow.
             */
@@ -1910,6 +1959,11 @@ unsigned CfgProcess (void)
            /* Calculate the new address */
            Addr += S->Seg->Size;
 
+            /* If this segment goes out to the file, increase the file size */
+            if ((S->Flags & SF_BSS) == 0 && S->Load == M) {
+                M->F->Size += Addr - StartAddr;
+            }
+
        }
 
        /* If requested, define symbols for start, size and offset of the
@@ -1942,11 +1996,11 @@ unsigned CfgProcess (void)
             SB_Done (&Buf);
        }
 
-        /* Grow the file by the size of the memory area */
-        if (M->Flags & MF_FILL) {
-            M->F->Size += M->Size;
-        } else {
-            M->F->Size += M->FillLevel;
+        /* If we didn't have an overflow and are requested to fill the memory
+         * area, acount for that in the file size.
+         */
+        if ((M->Flags & MF_OVERFLOW) == 0 && (M->Flags & MF_FILL) != 0) {
+            M->F->Size += (M->Size - M->FillLevel);
         }
     }