]> git.sur5r.net Git - cc65/blobdiff - src/ca65/segment.c
More lineinfo usage.
[cc65] / src / ca65 / segment.c
index b1ea4da56c2fa7b9a3143a7b31034e333a6dae98..b94123058e82f81ba21431782141708e7c6259f5 100644 (file)
@@ -6,8 +6,8 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2003 Ullrich von Bassewitz                                       */
-/*               Römerstraße 52                                              */
+/* (C) 1998-2007 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
 /*               D-70794 Filderstadt                                         */
 /* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
@@ -37,6 +37,8 @@
 #include <errno.h>
 
 /* common */
+#include "addrsize.h"
+#include "mmodel.h"
 #include "segnames.h"
 #include "xmalloc.h"
 
@@ -50,6 +52,7 @@
 #include "objfile.h"
 #include "segment.h"
 #include "spool.h"
+#include "studyexpr.h"
 #include "symtab.h"
 
 
 
 
 
-/* Are we in absolute mode or in relocatable mode? */
-int            RelocMode = 1;
-unsigned long  AbsPC     = 0;          /* PC if in absolute mode */
+/* If OrgPerSeg is false, all segments share the RelocMode flag and a PC
+ * used when in absolute mode. OrgPerSeg may be set by .feature org_per_seg
+ */
+static int              RelocMode = 1;
+static unsigned long    AbsPC    = 0;          /* PC if in absolute mode */
 
 /* Segment initializer macro */
 #define SEG(segdef, num, prev)      \
-    { prev, 0, 0, 0, num, 0, 0, segdef }
+    { prev, 0, 0, 0, num, 0, 1, 0, 0, segdef }
 
 /* Definitions for predefined segments */
 SegDef NullSegDef     = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL,     ADDR_SIZE_ABS);
@@ -88,7 +93,7 @@ static Segment CodeSeg     = SEG (&CodeSegDef,     0, &RODataSeg);
 static unsigned SegmentCount = 6;
 
 /* List of all segments */
-static Segment* SegmentList = &CodeSeg;
+Segment* SegmentList = &CodeSeg;
 static Segment* SegmentLast = &NullSeg;
 
 /* Currently active segment */
@@ -102,7 +107,7 @@ Segment* ActiveSeg = &CodeSeg;
 
 
 
-static Segment* NewSegment (const char* Name, unsigned AddrSize)
+static Segment* NewSegment (const char* Name, unsigned char AddrSize)
 /* Create a new segment, insert it into the global list and return it */
 {
     Segment* S;
@@ -127,7 +132,9 @@ static Segment* NewSegment (const char* Name, unsigned AddrSize)
     S->FragCount = 0;
     S->Num       = SegmentCount++;
     S->Align     = 0;
+    S->RelocMode = 1;
     S->PC        = 0;
+    S->AbsPC     = 0;
     S->Def       = NewSegDef (Name, AddrSize);
 
     /* Insert it into the segment list */
@@ -167,8 +174,16 @@ Fragment* GenFragment (unsigned char Type, unsigned short Len)
 
     /* Increment the program counter */
     ActiveSeg->PC += F->Len;
-    if (!RelocMode) {
-       AbsPC += F->Len;
+    if (OrgPerSeg) {
+        /* Relocatable mode is switched per segment */
+        if (!ActiveSeg->RelocMode) {
+            ActiveSeg->AbsPC += F->Len;
+        }
+    } else {
+        /* Relocatable mode is switched globally */
+        if (!RelocMode) {
+            AbsPC += F->Len;
+        }
     }
 
     /* Return the fragment */
@@ -211,16 +226,61 @@ void UseSeg (const SegDef* D)
 unsigned long GetPC (void)
 /* Get the program counter of the current segment */
 {
-    return RelocMode? ActiveSeg->PC : AbsPC;
+    if (OrgPerSeg) {
+        /* Relocatable mode is switched per segment */
+        return ActiveSeg->RelocMode? ActiveSeg->PC : ActiveSeg->AbsPC;
+    } else {
+        /* Relocatable mode is switched globally */
+        return RelocMode? ActiveSeg->PC : AbsPC;
+    }
 }
 
 
 
-void SetAbsPC (unsigned long PC)
-/* Set the program counter in absolute mode */
+void EnterAbsoluteMode (unsigned long PC)
+/* Enter absolute (non relocatable mode). Depending on the OrgPerSeg flag,
+ * this will either switch the mode globally or for the current segment.
+ */
 {
-    RelocMode = 0;
-    AbsPC = PC;
+    if (OrgPerSeg) {
+        /* Relocatable mode is switched per segment */
+        ActiveSeg->RelocMode = 0;
+        ActiveSeg->AbsPC = PC;
+    } else {
+        /* Relocatable mode is switched globally */
+        RelocMode = 0;
+        AbsPC = PC;
+    }
+}
+
+
+
+int GetRelocMode (void)
+/* Return true if we're currently in relocatable mode */
+{
+    if (OrgPerSeg) {
+        /* Relocatable mode is switched per segment */
+        return ActiveSeg->RelocMode;
+    } else {
+        /* Relocatable mode is switched globally */
+        return RelocMode;
+    }
+}
+
+
+
+void EnterRelocMode (void)
+/* Enter relocatable mode. Depending on the OrgPerSeg flag, this will either
+ * switch the mode globally or for the current segment.
+ */
+{
+    if (OrgPerSeg) {
+        /* Relocatable mode is switched per segment */
+        ActiveSeg->RelocMode = 1;
+    } else {
+        /* Relocatable mode is switched globally */
+        RelocMode = 1;
+    }
 }
 
 
@@ -261,7 +321,7 @@ void SegAlign (unsigned Power, int Val)
 
 
 
-unsigned GetSegAddrSize (unsigned SegNum)
+unsigned char GetSegAddrSize (unsigned SegNum)
 /* Return the address size of the segment with the given number */
 {
     /* Search for the segment */
@@ -290,36 +350,45 @@ void SegCheck (void)
        Fragment* F = S->Root;
        while (F) {
                    if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
-                long Val;
-                       if (IsConstExpr (F->V.Expr, &Val)) {
-                   /* We are able to evaluate the expression. Check for
-                    * range errors.
-                    */
-                   unsigned I;
+
+                /* We have an expression, study it */
+                ExprDesc ED;
+                ED_Init (&ED);
+                StudyExpr (F->V.Expr, &ED);
+
+                /* Try to simplify it before looking further */
+                F->V.Expr = SimplifyExpr (F->V.Expr, &ED);
+
+                /* Check if the expression is constant */
+                if (ED_IsConst (&ED)) {
+
+                           /* The expression is constant. Check for range errors. */
                    int Abs = (F->Type != FRAG_SEXPR);
+                    long Val = ED.Val;
+                   unsigned I;
 
                    if (F->Len == 1) {
-                       if (Abs) {
-                           /* Absolute value */
-                           if (Val > 255) {
-                               PError (&F->Pos, "Range error");
-                           }
-                       } else {
-                           /* PC relative value */
-                           if (Val < -128 || Val > 127) {
-                               PError (&F->Pos, "Range error");
-                           }
-                       }
+                       if (Abs) {
+                           /* Absolute value */
+                           if (Val > 255) {
+                               LIError (&F->LI, "Range error (%ld not in [0..255])", Val);
+                           }
+                       } else {
+                           /* PC relative value */
+                           if (Val < -128 || Val > 127) {
+                               LIError (&F->LI, "Range error (%ld not in [-128..127])", Val);
+                           }
+                       }
                    } else if (F->Len == 2) {
                        if (Abs) {
-                           /* Absolute value */
-                           if (Val > 65535) {
-                               PError (&F->Pos, "Range error");
-                           }
-                       } else {
-                           /* PC relative value */
-                           if (Val < -32768 || Val > 32767) {
-                               PError (&F->Pos, "Range error");
+                           /* Absolute value */
+                           if (Val > 65535) {
+                               LIError (&F->LI, "Range error (%ld not in [0..65535])", Val);
+                           }
+                       } else {
+                           /* PC relative value */
+                           if (Val < -32768 || Val > 32767) {
+                               LIError (&F->LI, "Range error (%ld not in [-32768..32767])", Val);
                            }
                        }
                    }
@@ -333,15 +402,22 @@ void SegCheck (void)
                        Val >>= 8;
                    }
                    F->Type = FRAG_LITERAL;
-               } else {
+
+               } else if (ED.AddrSize != ADDR_SIZE_DEFAULT) {
+
                    /* We cannot evaluate the expression now, leave the job for
-                    * the linker. However, we are able to check for explicit
-                    * byte expressions and we will do so.
+                    * the linker. However, we can check if the address size
+                     * matches the fragment size, and we will do so.
                     */
-                   if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
-                       PError (&F->Pos, "Range error");
+                    if ((F->Len == 1 && ED.AddrSize > ADDR_SIZE_ZP)  ||
+                        (F->Len == 2 && ED.AddrSize > ADDR_SIZE_ABS) ||
+                        (F->Len == 3 && ED.AddrSize > ADDR_SIZE_FAR)) {
+                       LIError (&F->LI, "Range error");
                    }
                }
+
+                /* Release memory allocated for the expression decriptor */
+                ED_Done (&ED);
            }
            F = F->Next;
        }
@@ -401,7 +477,6 @@ static void WriteOneSeg (Segment* Seg)
 /* Write one segment to the object file */
 {
     Fragment* Frag;
-    unsigned LineInfoIndex;
     unsigned long DataSize;
     unsigned long EndPos;
 
@@ -465,14 +540,8 @@ static void WriteOneSeg (Segment* Seg)
 
        }
 
-               /* Write the file position of this fragment */
-       ObjWritePos (&Frag->Pos);
-
-       /* Write extra line info for this fragment. Zero is considered
-        * "no line info", so add one to the value.
-        */
-       LineInfoIndex = Frag->LI? Frag->LI->Index + 1 : 0;
-       ObjWriteVar (LineInfoIndex);
+               /* Write the line infos for this fragment */
+               WriteLineInfo (&Frag->LI);
 
        /* Next fragment */
        Frag = Frag->Next;
@@ -488,6 +557,36 @@ static void WriteOneSeg (Segment* Seg)
 
 
 
+void InitSegments (void)
+/* Initialize segments */
+{
+    /* Initialize segment sizes. The segment definitions do already contain
+     * the correct values for the default case (near), so we must only change
+     * things that should be different.
+     */
+    switch (MemoryModel) {
+
+        case MMODEL_NEAR:
+            break;
+
+        case MMODEL_FAR:
+            CodeSegDef.AddrSize = ADDR_SIZE_FAR;
+            break;
+
+        case MMODEL_HUGE:
+            CodeSegDef.AddrSize   = ADDR_SIZE_FAR;
+            DataSegDef.AddrSize   = ADDR_SIZE_FAR;
+            BssSegDef.AddrSize    = ADDR_SIZE_FAR;
+            RODataSegDef.AddrSize = ADDR_SIZE_FAR;
+            break;
+
+        default:
+            Internal ("Invalid memory model: %d", MemoryModel);
+    }
+}
+
+
+
 void WriteSegments (void)
 /* Write the segment data to the object file */
 {
@@ -514,3 +613,4 @@ void WriteSegments (void)
 
 
 
+