/* */
/* */
/* (C) 1998-2003 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* Römerstraße 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
#include <errno.h>
/* common */
+#include "addrsize.h"
+#include "mmodel.h"
#include "segnames.h"
#include "xmalloc.h"
#include "objfile.h"
#include "segment.h"
#include "spool.h"
+#include "studyexpr.h"
#include "symtab.h"
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 long FragCount; /* Number of fragments */
- unsigned Num; /* Segment number */
- unsigned Align; /* Segment alignment */
- unsigned long PC;
- SegDef* Def; /* Segment definition (name and type) */
-};
-
-
+/* Segment initializer macro */
#define SEG(segdef, num, prev) \
{ prev, 0, 0, 0, num, 0, 0, segdef }
/* Definitions for predefined segments */
-SegDef NullSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL, SEGTYPE_ABS);
-SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_ZEROPAGE, SEGTYPE_ZP);
-SegDef DataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_DATA, SEGTYPE_ABS);
-SegDef BssSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_BSS, SEGTYPE_ABS);
-SegDef RODataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_RODATA, SEGTYPE_ABS);
-SegDef CodeSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_CODE, SEGTYPE_ABS);
+SegDef NullSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_NULL, ADDR_SIZE_ABS);
+SegDef ZeropageSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_ZEROPAGE, ADDR_SIZE_ZP);
+SegDef DataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_DATA, ADDR_SIZE_ABS);
+SegDef BssSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_BSS, ADDR_SIZE_ABS);
+SegDef RODataSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_RODATA, ADDR_SIZE_ABS);
+SegDef CodeSegDef = STATIC_SEGDEF_INITIALIZER (SEGNAME_CODE, ADDR_SIZE_ABS);
/* Predefined segments */
static Segment NullSeg = SEG (&NullSegDef, 5, NULL);
static unsigned SegmentCount = 6;
/* List of all segments */
-static Segment* SegmentList = &CodeSeg;
+Segment* SegmentList = &CodeSeg;
static Segment* SegmentLast = &NullSeg;
/* Currently active segment */
-static Segment* ActiveSeg = &CodeSeg;
+Segment* ActiveSeg = &CodeSeg;
-static Segment* NewSegment (const char* Name, unsigned SegType)
+static Segment* NewSegment (const char* Name, unsigned char AddrSize)
/* Create a new segment, insert it into the global list and return it */
{
Segment* S;
/* Check for too many segments */
if (SegmentCount >= 256) {
- Fatal (FAT_TOO_MANY_SEGMENTS);
+ Fatal ("Too many segments");
}
/* Check the segment name for invalid names */
if (!ValidSegName (Name)) {
- Error (ERR_ILLEGAL_SEGMENT, Name);
+ Error ("Illegal segment name: `%s'", Name);
}
/* Create a new segment */
S->Num = SegmentCount++;
S->Align = 0;
S->PC = 0;
- S->Def = NewSegDef (Name, SegType);
+ S->Def = NewSegDef (Name, AddrSize);
/* Insert it into the segment list */
SegmentLast->List = S;
while (Seg) {
if (strcmp (Seg->Def->Name, D->Name) == 0) {
/* We found this segment. Check if the type is identical */
- if (D->Type != SEGTYPE_DEFAULT && Seg->Def->Type != D->Type) {
- Error (ERR_SEG_ATTR_MISMATCH);
+ if (D->AddrSize != ADDR_SIZE_DEFAULT &&
+ Seg->Def->AddrSize != D->AddrSize) {
+ Error ("Segment attribute mismatch");
/* Use the new attribute to avoid errors */
- Seg->Def->Type = D->Type;
+ Seg->Def->AddrSize = D->AddrSize;
}
ActiveSeg = Seg;
return;
}
/* Segment is not in list, create a new one */
- if (D->Type == SEGTYPE_DEFAULT) {
- Seg = NewSegment (D->Name, SEGTYPE_ABS);
+ if (D->AddrSize == ADDR_SIZE_DEFAULT) {
+ Seg = NewSegment (D->Name, ADDR_SIZE_ABS);
} else {
- Seg = NewSegment (D->Name, D->Type);
+ Seg = NewSegment (D->Name, D->AddrSize);
}
ActiveSeg = Seg;
}
-const SegDef* GetCurrentSeg (void)
-/* Get a pointer to the segment defininition of the current segment */
-{
- return ActiveSeg->Def;
-}
-
-
-
-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
-int IsZPSeg (void)
-/* Return true if the current segment is a zeropage segment */
-{
- return (ActiveSeg->Def->Type == SEGTYPE_ZP);
-}
-
-
-
-int IsFarSeg (void)
-/* Return true if the current segment is a far segment */
-{
- return (ActiveSeg->Def->Type == SEGTYPE_FAR);
-}
-
-
-
-unsigned GetSegType (unsigned SegNum)
-/* Return the type of the segment with the given number */
+unsigned char GetSegAddrSize (unsigned SegNum)
+/* Return the address size of the segment with the given number */
{
/* Search for the segment */
Segment* S = SegmentList;
FAIL ("Invalid segment number");
}
- /* Return the segment type */
- return S->Def->Type;
+ /* Return the address size */
+ return S->Def->AddrSize;
}
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);
+
+ /* 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, ERR_RANGE);
- }
- } else {
- /* PC relative value */
- if (Val < -128 || Val > 127) {
- PError (&F->Pos, ERR_RANGE);
- }
- }
+ if (Abs) {
+ /* Absolute value */
+ if (Val > 255) {
+ PError (&F->Pos, "Range error (%ld not in [0..255])", Val);
+ }
+ } else {
+ /* PC relative value */
+ if (Val < -128 || Val > 127) {
+ PError (&F->Pos, "Range error (%ld not in [-128..127])", Val);
+ }
+ }
} 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);
- }
- }
- }
+ /* Absolute value */
+ if (Val > 65535) {
+ PError (&F->Pos, "Range error (%ld not in [0..65535])", Val);
+ }
+ } else {
+ /* PC relative value */
+ if (Val < -32768 || Val > 32767) {
+ PError (&F->Pos, "Range error (%ld not in [-32768..32767])", Val);
+ }
+ }
+ }
/* We don't need the expression tree any longer */
FreeExpr (F->V.Expr);
- /* Convert the fragment into a literal fragment */
- for (I = 0; I < F->Len; ++I) {
- F->V.Data [I] = Val & 0xFF;
- Val >>= 8;
+ /* 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;
+ F->Type = FRAG_LITERAL;
+
+ } else if (ED.AddrSize != ADDR_SIZE_DEFAULT) {
+
+ /* We cannot evaluate the expression now, leave the job for
+ * the linker. However, we can check if the address size
+ * matches the fragment size, and we will do so.
+ */
+ 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)) {
+ PError (&F->Pos, "Range error");
+ }
+ }
+
+ /* Release memory allocated for the expression decriptor */
+ ED_Done (&ED);
+ }
+ F = F->Next;
+ }
+ S = S->List;
}
}
} else if (F->Type == FRAG_EXPR || F->Type == FRAG_SEXPR) {
State = 1;
printf ("\n Expression (%u): ", F->Len);
- DumpExpr (F->V.Expr);
+ DumpExpr (F->V.Expr, SymResolve);
} else if (F->Type == FRAG_FILL) {
State = 1;
printf ("\n Fill bytes (%u)", F->Len);
ObjWriteVar (GetStringId (Seg->Def->Name)); /* Name of the segment */
ObjWrite32 (Seg->PC); /* Size */
ObjWrite8 (Seg->Align); /* Segment alignment */
- ObjWrite8 (Seg->Def->Type); /* Type of the segment */
+ ObjWrite8 (Seg->Def->AddrSize); /* Address size of the segment */
ObjWriteVar (Seg->FragCount); /* Number of fragments */
/* Now walk through the fragment list for this segment and write the
+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 */
{