]> git.sur5r.net Git - cc65/blobdiff - src/ca65/segment.c
More lineinfo usage.
[cc65] / src / ca65 / segment.c
index 2f67c6ed04a8555abb2d1789044047a8ff31ea09..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                                                 */
 /*                                                                           */
 
 
 
-/* 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);
@@ -130,7 +132,9 @@ static Segment* NewSegment (const char* Name, unsigned char 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 */
@@ -170,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 */
@@ -214,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 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.
+ */
+{
+    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 SetAbsPC (unsigned long PC)
-/* Set the program counter in absolute mode */
+void EnterRelocMode (void)
+/* Enter 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 = 1;
+    } else {
+        /* Relocatable mode is switched globally */
+        RelocMode = 1;
+    }
 }
 
 
@@ -314,24 +371,24 @@ void SegCheck (void)
                        if (Abs) {
                            /* Absolute value */
                            if (Val > 255) {
-                               PError (&F->Pos, "Range error");
+                               LIError (&F->LI, "Range error (%ld not in [0..255])", Val);
                            }
                        } else {
                            /* PC relative value */
                            if (Val < -128 || Val > 127) {
-                               PError (&F->Pos, "Range error");
+                               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");
+                               LIError (&F->LI, "Range error (%ld not in [0..65535])", Val);
                            }
                        } else {
                            /* PC relative value */
                            if (Val < -32768 || Val > 32767) {
-                               PError (&F->Pos, "Range error");
+                               LIError (&F->LI, "Range error (%ld not in [-32768..32767])", Val);
                            }
                        }
                    }
@@ -355,12 +412,7 @@ void SegCheck (void)
                     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)) {
-                        printf ("Range error\n");
-                        printf ("F->Len = %u, ED.AddrSize = %s\n",
-                                F->Len, AddrSizeToStr (ED.AddrSize));
-                        DumpExpr (F->V.Expr, SymResolve);
-                        printf ("-------------------------------------------\n");
-                       PError (&F->Pos, "Range error");
+                       LIError (&F->LI, "Range error");
                    }
                }
 
@@ -425,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;
 
@@ -489,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;
@@ -568,3 +613,4 @@ void WriteSegments (void)
 
 
 
+