]> git.sur5r.net Git - cc65/blobdiff - src/ld65/config.c
Finish support for .BANK.
[cc65] / src / ld65 / config.c
index e9ee811390bb9e07a2d9470f447b4025e73c1881..54d88e6b8a0e8401e30e58fae97225fc9d166618 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,7 @@
 #include "bitops.h"
 #include "check.h"
 #include "print.h"
+#include "segdefs.h"
 #include "xmalloc.h"
 #include "xsprintf.h"
 
@@ -102,6 +103,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;
@@ -405,13 +407,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 +445,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 +468,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 +483,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");
 
@@ -1809,6 +1817,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.
              */
@@ -1859,16 +1870,30 @@ unsigned CfgProcess (void)
                     Addr = NewAddr;
                 }
 
+                /* If the segment has .BANK expressions referring to it, it
+                 * must be placed into a memory area that has the bank
+                 * attribute.
+                 */
+                if ((S->Seg->Flags & SEG_FLAG_BANKREF) != 0 && M->BankExpr == 0) {
+                    CfgError (GetSourcePos (S->LI),
+                              "Segment `%s' is refered to by .BANK, but the "
+                              "memory area `%s' it is placed into has no BANK "
+                              "attribute",
+                              GetString (S->Name),
+                              GetString (M->Name));
+                }
+
                 /* Set the start address of this segment, set the readonly flag
                  * in the segment and and remember if the segment is in a
                  * relocatable file or not.
                  */
                 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) {
 
@@ -1910,6 +1935,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 +1972,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);
         }
     }