]> git.sur5r.net Git - cc65/commitdiff
Added handling of memory areas references in expressions for o65
authorcuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 27 Sep 2003 19:53:09 +0000 (19:53 +0000)
committercuz <cuz@b7a2c559-68d2-44c3-8de9-860c34a00d81>
Sat, 27 Sep 2003 19:53:09 +0000 (19:53 +0000)
git-svn-id: svn://svn.cc65.org/cc65/trunk@2453 b7a2c559-68d2-44c3-8de9-860c34a00d81

src/ld65/o65.c

index f945cc1e283c9b5badc708574c62f68bf424956d..c831b8595957f92ce667177c5929cfaf7b26c3eb 100644 (file)
@@ -35,6 +35,7 @@
 
 #include <stdio.h>
 #include <string.h>
+#include <limits.h>
 #include <errno.h>
 #include <time.h>
 
@@ -175,6 +176,7 @@ struct ExprDesc {
     O65Desc*               D;                  /* File format descriptor */
     long                   Val;                /* The offset value */
     int                    TooComplex;         /* Expression too complex */
+    Memory*         MemRef;             /* Memory reference if any */
     Segment*        SegRef;             /* Segment reference if any */
     Section*               SecRef;             /* Section reference if any */
     ExtSym*                ExtRef;             /* External reference if any */
@@ -194,6 +196,7 @@ static ExprDesc* InitExprDesc (ExprDesc* ED, O65Desc* D)
     ED->D         = D;
     ED->Val       = 0;
     ED->TooComplex = 0;
+    ED->MemRef     = 0;
     ED->SegRef     = 0;
     ED->SecRef     = 0;
     ED->ExtRef     = 0;
@@ -236,6 +239,60 @@ static unsigned O65SegType (const SegDesc* S)
 
 
 
+static void CvtMemoryToSegment (ExprDesc* ED)
+/* Convert a memory area into a segment by searching the list of run segments
+ * in this memory area and assigning the nearest one.
+ */
+{
+    /* Get the memory area from the expression */
+    Memory* M = ED->MemRef;
+
+    /* Get the list of segments in this memory area */
+    MemListNode* N = M->SegList;
+
+    /* Remember the "nearest" segment and its offset */
+    Segment* Nearest   = 0;
+    unsigned long Offs = ULONG_MAX;
+
+    /* Walk over all segments */
+    while (N != 0) {
+
+        /* Get the segment from this node and check if it's a run segment */
+        SegDesc* S = N->Seg;
+        if (S->Run == M) {
+
+            unsigned long O;
+
+            /* Get the segment from the segment descriptor */
+            Segment* Seg = S->Seg;
+
+            /* Check the PC. */
+            if ((long) Seg->PC <= ED->Val && (O = (ED->Val - Seg->PC)) < Offs) {
+                /* This is the nearest segment for now */
+                Offs = O;
+                Nearest = Seg;
+
+                /* If we found an exact match, don't look further */
+                if (Offs == 0) {
+                    break;
+                }
+            }
+        }
+
+        /* Next segment */
+        N = N->Next;
+    }
+
+    /* If we found a segment, use it and adjust the offset */
+    if (Nearest) {
+        ED->SegRef = Nearest;
+        ED->MemRef = 0;
+        ED->Val    -= Nearest->PC;
+    }
+}
+
+
+
 static const SegDesc* FindSeg (SegDesc** const List, unsigned Count, const Segment* S)
 /* Search for a segment in the given list of segment descriptors and return
  * the descriptor for a segment if we found it, and NULL if not.
@@ -366,6 +423,25 @@ static void O65ParseExpr (ExprNode* Expr, ExprDesc* D, int Sign)
            }
            break;
 
+        case EXPR_MEMAREA:
+           if (D->MemRef) {
+               /* We cannot handle more than one memory reference in o65 */
+               D->TooComplex = 1;
+           } else {
+               /* Remember the memory area reference */
+                       D->MemRef = Expr->V.Mem;
+                /* Add the start address of the memory area to the constant
+                 * value
+                 */
+                Val = D->MemRef->Start;
+                if (Sign < 0) {
+                    D->Val -= Val;
+                } else {
+                    D->Val += Val;
+                }
+           }
+           break;
+
        case EXPR_PLUS:
            O65ParseExpr (Expr->Left, D, Sign);
            O65ParseExpr (Expr->Right, D, Sign);
@@ -587,11 +663,23 @@ static unsigned O65WriteExpr (ExprNode* E, int Signed, unsigned Size,
     O65ParseExpr (Expr, InitExprDesc (&ED, D), 1);
 
     /* We cannot handle more than one external reference */
-    RefCount = (ED.SegRef != 0) + (ED.SecRef != 0) + (ED.ExtRef != 0);
+    RefCount = (ED.MemRef != 0) + (ED.SegRef != 0) +
+               (ED.SecRef != 0) + (ED.ExtRef != 0);
     if (RefCount > 1) {
                ED.TooComplex = 1;
     }
 
+    /* If we have a memory area reference, we need to convert it into a
+     * segment reference. If we cannot do that, we cannot handle the
+     * expression.
+     */
+    if (ED.MemRef) {
+        CvtMemoryToSegment (&ED);
+        if (ED.SegRef == 0) {
+            return SEG_EXPR_TOO_COMPLEX;
+        }
+    }
+
     /* Bail out if we cannot handle the expression */
     if (ED.TooComplex) {
                return SEG_EXPR_TOO_COMPLEX;