]> git.sur5r.net Git - cc65/blobdiff - src/ca65/objcode.c
Correct sweet16 addressing bug with SUB instr. Patch by Gabriele Galeotti.
[cc65] / src / ca65 / objcode.c
index da6d3e3bbbb3b82455be1a5d71001214f43eade8..f9032a0764d4fc525d6061bb483943eea3644e30 100644 (file)
@@ -6,10 +6,10 @@
 /*                                                                           */
 /*                                                                           */
 /*                                                                           */
-/* (C) 1998-2000 Ullrich von Bassewitz                                       */
-/*               Wacholderweg 14                                             */
-/*               D-70597 Stuttgart                                           */
-/* EMail:        uz@musoftware.de                                            */
+/* (C) 1998-2008 Ullrich von Bassewitz                                       */
+/*               Roemerstrasse 52                                            */
+/*               D-70794 Filderstadt                                         */
+/* EMail:        uz@cc65.org                                                 */
 /*                                                                           */
 /*                                                                           */
 /* This software is provided 'as-is', without any expressed or implied       */
 #include <string.h>
 #include <errno.h>
 
-/* common */
-#include "chartype.h"
-#include "check.h"
-#include "segdefs.h"
-#include "xmalloc.h"
-
 /* cc65 */
 #include "error.h"
 #include "fragment.h"
-#include "global.h"
-#include "listing.h"
-#include "objfile.h"
-#include "scanner.h"
-#include "symtab.h"
 #include "objcode.h"
-
-
-
-/*****************************************************************************/
-/*                                          Data                                    */
-/*****************************************************************************/
-
-
-
-/* Are we in absolute mode or in relocatable mode? */
-int            RelocMode = 1;
-unsigned long  AbsPC     = 0;          /* PC if in absolute mode */
-
-
-
-typedef struct Segment_ Segment;
-struct Segment_ {
-    Segment*               List;               /* List of all segments */
-    Fragment*              Root;               /* Root of fragment list */
-    Fragment*              Last;               /* Pointer to last fragment */
-    unsigned char   Align;             /* Segment alignment */
-    unsigned char   SegType;                   /* True if zero page segment */
-    unsigned long   PC;
-    unsigned               Num;                /* Segment number */
-    char*                  Name;               /* Segment name */
-};
-
-
-
-/* Predefined segments */
-static Segment NullSeg = {
-    0, 0, 0, 0, SEGTYPE_ABS, 0, 5, "NULL"
-};
-static Segment ZeropageSeg = {
-    &NullSeg, 0, 0, 0, SEGTYPE_ZP, 0, 4, "ZEROPAGE"
-};
-static Segment DataSeg = {
-    &ZeropageSeg, 0, 0, 0, SEGTYPE_ABS, 0, 3, "DATA"
-};
-static Segment BssSeg = {
-    &DataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 2, "BSS"
-};
-static Segment RODataSeg = {
-    &BssSeg, 0, 0, 0, SEGTYPE_ABS, 0, 1, "RODATA"
-};
-static Segment CodeSeg = {
-    &RODataSeg, 0, 0, 0, SEGTYPE_ABS, 0, 0, "CODE"
-};
-
-/* Number of segments */
-static unsigned SegmentCount = 6;
-
-/* List of all segments */
-static Segment* SegmentList = &CodeSeg;
-static Segment* SegmentLast = &NullSeg;
-
-/* Currently active segment */
-static Segment*        ActiveSeg = &CodeSeg;
-
-
-
-/*****************************************************************************/
-/*                                   Segment management                             */
-/*****************************************************************************/
-
-
-
-static Segment* NewSegment (const char* Name, unsigned SegType)
-/* Create a new segment, insert it into the global list and return it */
-{
-    Segment* S;
-    const char* N;
-
-    /* Check for too many segments */
-    if (SegmentCount >= 256) {
-       Fatal (FAT_TOO_MANY_SEGMENTS);
-    }
-
-    /* Check the segment name for invalid names */
-    N = Name;
-    if ((*N != '_' && !IsAlpha (*N)) || strlen (Name) > 80) {
-       Error (ERR_ILLEGAL_SEGMENT, Name);
-    }
-    do {
-       if (*N != '_' && !IsAlNum (*N)) {
-           Error (ERR_ILLEGAL_SEGMENT, Name);
-           break;
-       }
-       ++N;
-    } while (*N);
-
-    /* Create a new segment */
-    S = xmalloc (sizeof (*S));
-
-    /* Initialize it */
-    S->List    = 0;
-    S->Root    = 0;
-    S->Last    = 0;
-    S->Align   = 0;
-    S->SegType = SegType;
-    S->PC      = 0;
-    S->Num     = SegmentCount++;
-    S->Name    = xstrdup (Name);
-
-    /* Insert it into the segment list */
-    SegmentLast->List = S;
-    SegmentLast = S;
-
-    /* And return it... */
-    return S;
-}
-
-
-
-void UseCodeSeg (void)
-/* Use the code segment */
-{
-    ActiveSeg = &CodeSeg;
-}
-
-
-
-void UseRODataSeg (void)
-/* Use the r/o data segment */
-{
-    ActiveSeg = &RODataSeg;
-}
-
-
-
-void UseDataSeg (void)
-/* Use the data segment */
-{
-    ActiveSeg = &DataSeg;
-}
-
-
-
-void UseBssSeg (void)
-/* Use the BSS segment */
-{
-    ActiveSeg = &BssSeg;
-}
-
-
-
-void UseZeropageSeg (void)
-/* Use the zero page segment */
-{
-    ActiveSeg = &ZeropageSeg;
-}
-
-
-
-void UseNullSeg (void)
-/* Use the null segment */
-{
-    ActiveSeg = &NullSeg;
-}
-
-
-
-void UseSeg (const char* Name, unsigned SegType)
-/* Use the segment with the given name */
-{
-    Segment* Seg = SegmentList;
-    while (Seg) {
-       if (strcmp (Seg->Name, Name) == 0) {
-           /* We found this segment. Check if the type is identical */
-           if (SegType != SEGTYPE_DEFAULT && Seg->SegType != SegType) {
-               Error (ERR_SEG_ATTR_MISMATCH);
-               /* Use the new attribute to avoid errors */
-               Seg->SegType = SegType;
-                   }
-                   ActiveSeg = Seg;
-           return;
-       }
-       /* Check next segment */
-       Seg = Seg->List;
-    }
-
-    /* Segment is not in list, create a new one */
-    if (SegType == SEGTYPE_DEFAULT) {
-       SegType = SEGTYPE_ABS;
-    }
-    Seg = NewSegment (Name, SegType);
-    ActiveSeg = Seg;
-}
-
-
-
-unsigned long GetPC (void)
-/* Get the program counter of the current segment */
-{
-    return RelocMode? ActiveSeg->PC : AbsPC;
-}
-
-
-
-void SetAbsPC (unsigned long PC)
-/* Set the program counter in absolute mode */
-{
-    RelocMode = 0;
-    AbsPC = PC;
-}
-
-
-
-unsigned GetSegNum (void)
-/* Get the number of the current segment */
-{
-    return ActiveSeg->Num;
-}
-
-
-
-void SegAlign (unsigned Power, int Val)
-/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
- * actual fill value will be determined by the linker), otherwise use the
- * given value.
- */
-{
-    unsigned char Data [4];
-    unsigned long Align = (1UL << Power) - 1;
-    unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
-    unsigned long Count = NewPC - ActiveSeg->PC;
-
-    if (Val != -1) {
-       /* User defined fill value */
-       memset (Data, Val, sizeof (Data));
-       while (Count) {
-           if (Count > sizeof (Data)) {
-               EmitData (Data, sizeof (Data));
-               Count -= sizeof (Data);
-           } else {
-               EmitData (Data, Count);
-               Count = 0;
-           }
-       }
-    } else {
-       /* Linker defined fill value */
-       EmitFill (Count);
-    }
-
-    /* Remember the alignment in the header */
-    if (ActiveSeg->Align < Power) {
-       ActiveSeg->Align = Power;
-    }
-}
-
-
-
-int IsZPSeg (void)
-/* Return true if the current segment is a zeropage segment */
-{
-    return (ActiveSeg->SegType == SEGTYPE_ZP);
-}
-
-
-
-int IsFarSeg (void)
-/* Return true if the current segment is a far segment */
-{
-    return (ActiveSeg->SegType == SEGTYPE_FAR);
-}
-
-
-
-unsigned GetSegType (unsigned SegNum)
-/* Return the type of the segment with the given number */
-{
-    /* Search for the segment */
-    Segment* S = SegmentList;
-    while (S && SegNum) {
-       --SegNum;
-       S = S->List;
-    }
-
-    /* Did we find it? */
-    if (S == 0) {
-       FAIL ("Invalid segment number");
-    }
-
-    /* Return the segment type */
-    return S->SegType;
-}
-
-
-
-void SegCheck (void)
-/* Check the segments for range and other errors */
-{
-    Segment* S = SegmentList;
-    while (S) {
-       Fragment* F = S->Root;
-       while (F) {
-                   if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
-                       F->V.Expr = FinalizeExpr (F->V.Expr);
-                       if (IsConstExpr (F->V.Expr)) {
-                   /* We are able to evaluate the expression. Get the value
-                    * and check for range errors.
-                    */
-                   unsigned I;
-                   long Val = GetExprVal (F->V.Expr);
-                   int Abs = (F->Type != FRAG_SEXPR);
-
-                   if (F->Len == 1) {
-                       if (Abs) {
-                           /* Absolute value */
-                           if (Val > 255) {
-                               PError (&F->Pos, ERR_RANGE);
-                           }
-                       } else {
-                           /* PC relative value */
-                           if (Val < -128 || Val > 127) {
-                               PError (&F->Pos, ERR_RANGE);
-                           }
-                       }
-                   } else if (F->Len == 2) {
-                       if (Abs) {
-                           /* Absolute value */
-                           if (Val > 65535) {
-                               PError (&F->Pos, ERR_RANGE);
-                           }
-                       } else {
-                           /* PC relative value */
-                           if (Val < -32768 || Val > 32767) {
-                               PError (&F->Pos, ERR_RANGE);
-                           }
-                       }
-                   }
-
-                   /* Convert the fragment into a literal fragment */
-                   for (I = 0; I < F->Len; ++I) {
-                       F->V.Data [I] = Val & 0xFF;
-                       Val >>= 8;
-                   }
-                   F->Type = FRAG_LITERAL;
-               } else {
-                   /* 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.
-                    */
-                   if (F->Type == FRAG_EXPR && F->Len == 1 && !IsByteExpr (F->V.Expr)) {
-                       PError (&F->Pos, ERR_RANGE);
-                   }
-               }
-           }
-           F = F->Next;
-       }
-       S = S->List;
-    }
-}
-
-
-
-void SegDump (void)
-/* Dump the contents of all segments */
-{
-    unsigned X = 0;
-    Segment* S = SegmentList;
-    printf ("\n");
-    while (S) {
-       unsigned I;
-       Fragment* F;
-       int State = -1;
-               printf ("New segment: %s", S->Name);
-       F = S->Root;
-       while (F) {
-           if (F->Type == FRAG_LITERAL) {
-               if (State != 0) {
-                   printf ("\n  Literal:");
-                   X = 15;
-                   State = 0;
-               }
-               for (I = 0; I < F->Len; ++I) {
-                   printf (" %02X", F->V.Data [I]);
-                   X += 3;
-               }
-           } else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
-                       State = 1;
-               printf ("\n  Expression (%u): ", F->Len);
-               DumpExpr (F->V.Expr);
-           } else if (F->Type == FRAG_FILL) {
-               State = 1;
-               printf ("\n  Fill bytes (%u)", F->Len);
-           } else {
-               Internal ("Unknown fragment type: %u", F->Type);
-           }
-                   if (X > 65) {
-               State = -1;
-           }
-           F = F->Next;
-       }
-       printf ("\n  End PC = $%04X\n", (unsigned)(S->PC & 0xFFFF));
-       S = S->List;
-    }
-    printf ("\n");
-}
-
-
-
-static void WriteOneSeg (Segment* Seg)
-/* Write one segment to the object file */
-{
-    Fragment* Frag;
-    Fragment* F;
-    unsigned long Size;
-
-    /* Write the segment name followed by the byte count in this segment */
-    ObjWriteStr (Seg->Name);
-    ObjWrite32 (Seg->PC);
-    ObjWrite8 (Seg->Align);
-    ObjWrite8 (Seg->SegType);
-
-    /* Now walk through the fragment list for this segment and write the
-     * fragments.
-     */
-    Frag = Seg->Root;
-    while (Frag) {
-
-       /* Write data depending on the type */
-               switch (Frag->Type) {
-
-           case FRAG_LITERAL:
-               /* To make the object file somewhat smaller, write all literal
-                * data of this and the following fragments preceeded by the
-                * length.
-                */
-               F = Frag;
-               Size = 0;
-               while (F && F->Type == FRAG_LITERAL) {
-                   Size += F->Len;
-                   F = F->Next;
-               }
-               ObjWrite8 (FRAG_LITERAL);
-               ObjWriteVar (Size);
-
-               /* Now write the literal data */
-               F = Frag;
-               while (F && F->Type == FRAG_LITERAL) {
-                   ObjWriteData (F->V.Data, F->Len);
-                   Frag = F;
-                   F = F->Next;
-               }
-               break;
-
-           case FRAG_EXPR:
-               switch (Frag->Len) {
-                   case 1:   ObjWrite8 (FRAG_EXPR8);   break;
-                   case 2:   ObjWrite8 (FRAG_EXPR16);  break;
-                   case 3:   ObjWrite8 (FRAG_EXPR24);  break;
-                   case 4:   ObjWrite8 (FRAG_EXPR32);  break;
-                   default:  Internal ("Invalid fragment size: %u", Frag->Len);
-               }
-               WriteExpr (Frag->V.Expr);
-               break;
-
-           case FRAG_SEXPR:
-               switch (Frag->Len) {
-                   case 1:   ObjWrite8 (FRAG_SEXPR8);  break;
-                   case 2:   ObjWrite8 (FRAG_SEXPR16); break;
-                   case 3:   ObjWrite8 (FRAG_SEXPR24); break;
-                   case 4:   ObjWrite8 (FRAG_SEXPR32); break;
-                   default:  Internal ("Invalid fragment size: %u", Frag->Len);
-               }
-               WriteExpr (Frag->V.Expr);
-               break;
-
-           case FRAG_FILL:
-               ObjWrite8 (FRAG_FILL);
-                       ObjWriteVar (Frag->Len);
-               break;
-
-           default:
-               Internal ("Invalid fragment type: %u", Frag->Type);
-
-       }
-
-               /* Write the file position of this fragment */
-       ObjWritePos (&Frag->Pos);
-
-       /* Next fragment */
-       Frag = Frag->Next;
-    }
-}
-
-
-
-void WriteSegments (void)
-/* Write the segment data to the object file */
-{
-    Segment* Seg;
-
-    /* Tell the object file module that we're about to start the seg list */
-    ObjStartSegments ();
-
-    /* First thing is segment count */
-    ObjWriteVar (SegmentCount);
-
-    /* Now walk through all segments and write them to the object file */
-    Seg = SegmentList;
-    while (Seg) {
-       /* Write one segment */
-       WriteOneSeg (Seg);
-       /* Next segment */
-       Seg = Seg->List;
-    }
-
-    /* Done writing segments */
-    ObjEndSegments ();
-}
+#include "segment.h"
 
 
 
@@ -572,75 +50,10 @@ void WriteSegments (void)
 
 
 
-static void IncPC (unsigned Value)
-/* Increment the PC counter */
-{
-    ActiveSeg->PC += Value;
-    if (!RelocMode) {
-       AbsPC += Value;
-    }
-}
-
-
-
-static Fragment* NewFragment (unsigned char Type, unsigned short Len)
-/* Create, initialize and return a new fragment. The fragment will be inserted
- * into the current segment.
- */
-{
-    Fragment* F;
-
-    /* Create a new fragment */
-    F = xmalloc (sizeof (*F));
-
-    /* Initialize it */
-    F->List    = 0;
-    F->Next    = 0;
-    F->LineList = 0;
-    F->Pos     = CurPos;
-    F->Len     = Len;
-    F->Type    = Type;
-
-    /* Insert it into the list of all segments */
-    if (FragList == 0) {
-       FragList = F;
-    } else {
-       FragLast->List = F;
-    }
-    FragLast = F;
-
-    /* Insert it into the current segment */
-    if (ActiveSeg->Root) {
-       ActiveSeg->Last->Next = F;
-       ActiveSeg->Last = F;
-    } else {
-       ActiveSeg->Root = ActiveSeg->Last = F;
-    }
-
-    /* Add this fragment to the current listing line */
-    if (LineCur) {
-       if (LineCur->FragList == 0) {
-           LineCur->FragList = F;
-       } else {
-                   LineCur->FragLast->LineList = F;
-       }
-       LineCur->FragLast = F;
-    }
-
-    /* Increment the program counter */
-    IncPC (Len);
-
-    /* And return it */
-    return F;
-}
-
-
-
 void Emit0 (unsigned char OPC)
 /* Emit an instruction with a zero sized operand */
 {
-    /* First fragment, wrong type or out of space, create new one */
-    Fragment* F = NewFragment (FRAG_LITERAL, 1);
+    Fragment* F = GenFragment (FRAG_LITERAL, 1);
     F->V.Data [0] = OPC;
 }
 
@@ -673,12 +86,11 @@ void Emit3 (unsigned char OPC, ExprNode* Expr)
 
 
 
-void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
-/* Emit an instruction with a three byte argument and separate bank */
+void EmitSigned (ExprNode* Expr, unsigned Size)
+/* Emit a signed expression with the given size */
 {
-    Emit0 (OPC);
-    EmitWord (Expr);
-    EmitByte (Bank);
+    Fragment* F = GenFragment (FRAG_SEXPR, Size);
+    F->V.Expr = Expr;
 }
 
 
@@ -686,29 +98,30 @@ void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank)
 void EmitPCRel (unsigned char OPC, ExprNode* Expr, unsigned Size)
 /* Emit an opcode with a PC relative argument of one or two bytes */
 {
-    Fragment* F;
     Emit0 (OPC);
-    F = NewFragment (FRAG_SEXPR, Size);
-    F->V.Expr = Expr;
+    EmitSigned (Expr, Size);
 }
 
 
 
-void EmitData (const unsigned char* Data, unsigned Size)
+void EmitData (const void* D, unsigned Size)
 /* Emit data into the current segment */
 {
+    /* Make a useful pointer from Data */
+    const unsigned char* Data = D;
+
     /* Create lots of fragments for the data */
     while (Size) {
-       Fragment* F;
+       Fragment* F;
 
-       /* Determine the length of the next fragment */
-       unsigned Len = Size;
+       /* Determine the length of the next fragment */
+       unsigned Len = Size;
                if (Len > sizeof (F->V.Data)) {
            Len = sizeof (F->V.Data);
                }
 
        /* Create a new fragment */
-       F = NewFragment (FRAG_LITERAL, Len);
+       F = GenFragment (FRAG_LITERAL, Len);
 
        /* Copy the data */
        memcpy (F->V.Data, Data, Len);
@@ -722,24 +135,23 @@ void EmitData (const unsigned char* Data, unsigned Size)
 
 
 
+void EmitStrBuf (const StrBuf* Data)
+/* Emit a string into the current segment */
+{
+    /* Use EmitData to output the data */
+    EmitData (SB_GetConstBuf (Data), SB_GetLen (Data));
+}
+
+
+
 void EmitByte (ExprNode* Expr)
 /* Emit one byte */
 {
-    if (IsConstExpr (Expr)) {
-       /* Constant expression, emit literal byte */
-       long Val = GetExprVal (Expr);
-       FreeExpr (Expr);
-       if ((Val & ~0xFF) != 0) {
-           Error (ERR_RANGE);
-       }
-       Emit0 (Val & 0xFF);
-    } else {
-       /* Create a new fragment */
-       Fragment* F = NewFragment (FRAG_EXPR, 1);
+    /* Create a new fragment */
+    Fragment* F = GenFragment (FRAG_EXPR, 1);
 
-       /* Set the data */
-       F->V.Expr = Expr;
-    }
+    /* Set the data */
+    F->V.Expr = Expr;
 }
 
 
@@ -747,22 +159,11 @@ void EmitByte (ExprNode* Expr)
 void EmitWord (ExprNode* Expr)
 /* Emit one word */
 {
-    if (IsConstExpr (Expr)) {
-       /* Constant expression, emit literal byte */
-       long Val = GetExprVal (Expr);
-       FreeExpr (Expr);
-               if ((Val & ~0xFFFF) != 0) {
-           Error (ERR_RANGE);
-       }
-       Emit0 (Val & 0xFF);
-       Emit0 ((Val >> 8) & 0xFF);
-    } else {
-       /* Create a new fragment */
-       Fragment* F = NewFragment (FRAG_EXPR, 2);
+    /* Create a new fragment */
+    Fragment* F = GenFragment (FRAG_EXPR, 2);
 
-       /* Set the data */
-       F->V.Expr = Expr;
-    }
+    /* Set the data */
+    F->V.Expr = Expr;
 }
 
 
@@ -770,23 +171,11 @@ void EmitWord (ExprNode* Expr)
 void EmitFarAddr (ExprNode* Expr)
 /* Emit a 24 bit expression */
 {
-    if (IsConstExpr (Expr)) {
-       /* Constant expression, emit literal byte */
-       long Val = GetExprVal (Expr);
-       FreeExpr (Expr);
-               if ((Val & ~0xFFFFFF) != 0) {
-           Error (ERR_RANGE);
-       }
-       Emit0 (Val & 0xFF);
-       Emit0 ((Val >> 8) & 0xFF);
-       Emit0 ((Val >> 16) & 0xFF);
-    } else {
-       /* Create a new fragment */
-       Fragment* F = NewFragment (FRAG_EXPR, 3);
+    /* Create a new fragment */
+    Fragment* F = GenFragment (FRAG_EXPR, 3);
 
-       /* Set the data */
-       F->V.Expr = Expr;
-    }
+    /* Set the data */
+    F->V.Expr = Expr;
 }
 
 
@@ -794,21 +183,11 @@ void EmitFarAddr (ExprNode* Expr)
 void EmitDWord (ExprNode* Expr)
 /* Emit one dword */
 {
-    if (IsConstExpr (Expr)) {
-       /* Constant expression, emit literal byte */
-       long Val = GetExprVal (Expr);
-       FreeExpr (Expr);
-       Emit0 (Val & 0xFF);
-       Emit0 ((Val >> 8) & 0xFF);
-               Emit0 ((Val >> 16) & 0xFF);
-       Emit0 ((Val >> 24) & 0xFF);
-    } else {
-       /* Create a new fragment */
-       Fragment* F = NewFragment (FRAG_EXPR, 4);
+    /* Create a new fragment */
+    Fragment* F = GenFragment (FRAG_EXPR, 4);
 
-       /* Set the data */
-       F->V.Expr = Expr;
-    }
+    /* Set the data */
+    F->V.Expr = Expr;
 }
 
 
@@ -822,7 +201,7 @@ void EmitFill (unsigned long Count)
        Count -= Chunk;
 
        /* Emit one chunk */
-       NewFragment (FRAG_FILL, Chunk);
+       GenFragment (FRAG_FILL, Chunk);
     }
 }