From cb57a213eb3555dcafd860d90736deb6f8f158c1 Mon Sep 17 00:00:00 2001 From: cuz Date: Tue, 21 Oct 2003 20:34:56 +0000 Subject: [PATCH] Move the segment handling stuff from objcode to a separate module git-svn-id: svn://svn.cc65.org/cc65/trunk@2555 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/expr.c | 5 +- src/ca65/fragment.c | 37 ++- src/ca65/fragment.h | 23 +- src/ca65/listing.c | 2 +- src/ca65/main.c | 2 +- src/ca65/make/gcc.mak | 1 + src/ca65/make/watcom.mak | 1 + src/ca65/objcode.c | 555 +------------------------------------- src/ca65/objcode.h | 75 +----- src/ca65/pseudo.c | 1 + src/ca65/segment.c | 559 +++++++++++++++++++++++++++++++++++++++ src/ca65/segment.h | 124 +++++++++ src/ca65/symtab.c | 9 +- 13 files changed, 751 insertions(+), 643 deletions(-) create mode 100644 src/ca65/segment.c create mode 100644 src/ca65/segment.h diff --git a/src/ca65/expr.c b/src/ca65/expr.c index 616564b16..5cbd71bdc 100644 --- a/src/ca65/expr.c +++ b/src/ca65/expr.c @@ -47,15 +47,16 @@ /* ca65 */ #include "error.h" +#include "expr.h" #include "global.h" #include "instr.h" #include "nexttok.h" -#include "objcode.h" +/* #include "objcode.h" */ #include "objfile.h" +#include "segment.h" #include "symtab.h" #include "toklist.h" #include "ulabel.h" -#include "expr.h" diff --git a/src/ca65/fragment.c b/src/ca65/fragment.c index bd0e70493..0d5a4b2e5 100644 --- a/src/ca65/fragment.c +++ b/src/ca65/fragment.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -33,19 +33,42 @@ +/* common */ +#include "xmalloc.h" + +/* ca65 */ #include "fragment.h" +#include "lineinfo.h" +#include "scanner.h" /*****************************************************************************/ -/* struct Fragment */ +/* Code */ /*****************************************************************************/ -/* List of all fragments */ -Fragment* FragList = 0; -Fragment* FragLast = 0; +Fragment* NewFragment (unsigned char Type, unsigned short Len) +/* Create, initialize and return a new fragment. The fragment will be inserted + * into the current segment. + */ +{ + /* Create a new fragment */ + Fragment* F = xmalloc (sizeof (*F)); + + /* Initialize it */ + F->Next = 0; + F->LineList = 0; + F->Pos = CurPos; + F->LI = UseLineInfo (CurLineInfo); + F->Len = Len; + F->Type = Type; + + /* And return it */ + return F; +} + diff --git a/src/ca65/fragment.h b/src/ca65/fragment.h index 2235f55d6..a020813af 100644 --- a/src/ca65/fragment.h +++ b/src/ca65/fragment.h @@ -44,16 +44,6 @@ -/*****************************************************************************/ -/* Forwards */ -/*****************************************************************************/ - - - -struct LineInfo; - - - /*****************************************************************************/ /* struct Fragment */ /*****************************************************************************/ @@ -76,6 +66,19 @@ struct Fragment { +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +Fragment* NewFragment (unsigned char Type, unsigned short Len); +/* Create, initialize and return a new fragment. The fragment will be inserted + * into the current segment. + */ + + + /* End of fragment.h */ #endif diff --git a/src/ca65/listing.c b/src/ca65/listing.c index a7d6d3c99..99e8273c3 100644 --- a/src/ca65/listing.c +++ b/src/ca65/listing.c @@ -48,8 +48,8 @@ #include "error.h" #include "filetab.h" #include "global.h" -#include "objcode.h" #include "listing.h" +#include "segment.h" diff --git a/src/ca65/main.c b/src/ca65/main.c index 972a8869c..95452f2c5 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -61,11 +61,11 @@ #include "listing.h" #include "macro.h" #include "nexttok.h" -#include "objcode.h" #include "objfile.h" #include "options.h" #include "pseudo.h" #include "scanner.h" +#include "segment.h" #include "spool.h" #include "symtab.h" #include "ulabel.h" diff --git a/src/ca65/make/gcc.mak b/src/ca65/make/gcc.mak index 424f5476a..053cc26e1 100644 --- a/src/ca65/make/gcc.mak +++ b/src/ca65/make/gcc.mak @@ -35,6 +35,7 @@ OBJS = asserts.o \ pseudo.o \ repeat.o \ scanner.o \ + segment.o \ spool.o \ symtab.o \ toklist.o \ diff --git a/src/ca65/make/watcom.mak b/src/ca65/make/watcom.mak index 82f85bde5..61af0f1e9 100644 --- a/src/ca65/make/watcom.mak +++ b/src/ca65/make/watcom.mak @@ -68,6 +68,7 @@ OBJS = asserts.obj \ pseudo.obj \ repeat.obj \ scanner.obj \ + segment.obj \ spool.obj \ symtab.obj \ toklist.obj \ diff --git a/src/ca65/objcode.c b/src/ca65/objcode.c index bf61ebfaa..2d56f9384 100644 --- a/src/ca65/objcode.c +++ b/src/ca65/objcode.c @@ -36,491 +36,11 @@ #include #include -/* common */ -#include "chartype.h" -#include "check.h" -#include "fragdefs.h" -#include "segdefs.h" -#include "segnames.h" -#include "xmalloc.h" - /* cc65 */ #include "error.h" #include "fragment.h" -#include "global.h" -#include "lineinfo.h" -#include "listing.h" #include "objcode.h" -#include "objfile.h" -#include "scanner.h" -#include "spool.h" -#include "symtab.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 long FragCount; /* Number of fragments */ - unsigned Num; /* Segment number */ - unsigned Align; /* Segment alignment */ - unsigned long PC; - SegDef* Def; /* Segment definition (name and type) */ -}; - - -#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); - -/* Predefined segments */ -static Segment NullSeg = SEG (&NullSegDef, 5, NULL); -static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg); -static Segment DataSeg = SEG (&DataSegDef, 3, &ZeropageSeg); -static Segment BssSeg = SEG (&BssSegDef, 2, &DataSeg); -static Segment RODataSeg = SEG (&RODataSegDef, 1, &BssSeg); -static Segment CodeSeg = SEG (&CodeSegDef, 0, &RODataSeg); - -/* 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; - - /* Check for too many segments */ - if (SegmentCount >= 256) { - Fatal (FAT_TOO_MANY_SEGMENTS); - } - - /* Check the segment name for invalid names */ - if (!ValidSegName (Name)) { - Error (ERR_ILLEGAL_SEGMENT, Name); - } - - /* Create a new segment */ - S = xmalloc (sizeof (*S)); - - /* Initialize it */ - S->List = 0; - S->Root = 0; - S->Last = 0; - S->FragCount = 0; - S->Num = SegmentCount++; - S->Align = 0; - S->PC = 0; - S->Def = NewSegDef (Name, SegType); - - /* Insert it into the segment list */ - SegmentLast->List = S; - SegmentLast = S; - - /* And return it... */ - return S; -} - - - -void UseSeg (const SegDef* D) -/* Use the segment with the given name */ -{ - Segment* Seg = SegmentList; - 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); - /* Use the new attribute to avoid errors */ - Seg->Def->Type = D->Type; - } - ActiveSeg = Seg; - return; - } - /* Check next segment */ - Seg = Seg->List; - } - - /* Segment is not in list, create a new one */ - if (D->Type == SEGTYPE_DEFAULT) { - Seg = NewSegment (D->Name, SEGTYPE_ABS); - } else { - Seg = NewSegment (D->Name, D->Type); - } - 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; -} - - - -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 - * 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->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 */ -{ - /* 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->Def->Type; -} - - - -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->Def->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; - unsigned LineInfoIndex; - unsigned long DataSize; - unsigned long EndPos; - - /* Remember the file position, then write a dummy for the size of the - * following data - */ - unsigned long SizePos = ObjGetFilePos (); - ObjWrite32 (0); - - /* Write the segment data */ - 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 */ - ObjWriteVar (Seg->FragCount); /* Number of fragments */ - - /* 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: - ObjWrite8 (FRAG_LITERAL); - ObjWriteVar (Frag->Len); - ObjWriteData (Frag->V.Data, Frag->Len); - 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); - - /* 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); - - /* Next fragment */ - Frag = Frag->Next; - } - - /* Calculate the size of the data, seek back and write it */ - EndPos = ObjGetFilePos (); /* Remember where we are */ - DataSize = EndPos - SizePos - 4; /* Don't count size itself */ - ObjSetFilePos (SizePos); /* Seek back to the size */ - ObjWrite32 (DataSize); /* Write the size */ - ObjSetFilePos (EndPos); /* Seek back to the end */ -} - - - -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" @@ -530,67 +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->Next = 0; - F->LineList = 0; - F->Pos = CurPos; - F->LI = UseLineInfo (CurLineInfo); - F->Len = Len; - F->Type = Type; - - /* Insert the fragment into the current segment */ - if (ActiveSeg->Root) { - ActiveSeg->Last->Next = F; - ActiveSeg->Last = F; - } else { - ActiveSeg->Root = ActiveSeg->Last = F; - } - ++ActiveSeg->FragCount; - - /* 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 */ { - Fragment* F = NewFragment (FRAG_LITERAL, 1); + Fragment* F = GenFragment (FRAG_LITERAL, 1); F->V.Data [0] = OPC; } @@ -636,7 +99,7 @@ void Emit3b (unsigned char OPC, ExprNode* Expr, ExprNode* Bank) void EmitSigned (ExprNode* Expr, unsigned Size) /* Emit a signed expression with the given size */ { - Fragment* F = NewFragment (FRAG_SEXPR, Size); + Fragment* F = GenFragment (FRAG_SEXPR, Size); F->V.Expr = Expr; } @@ -665,7 +128,7 @@ void EmitData (const unsigned char* Data, unsigned Size) } /* Create a new fragment */ - F = NewFragment (FRAG_LITERAL, Len); + F = GenFragment (FRAG_LITERAL, Len); /* Copy the data */ memcpy (F->V.Data, Data, Len); @@ -692,7 +155,7 @@ void EmitByte (ExprNode* Expr) Emit0 (Val & 0xFF); } else { /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 1); + Fragment* F = GenFragment (FRAG_EXPR, 1); /* Set the data */ F->V.Expr = Expr; @@ -715,7 +178,7 @@ void EmitWord (ExprNode* Expr) Emit0 ((Val >> 8) & 0xFF); } else { /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 2); + Fragment* F = GenFragment (FRAG_EXPR, 2); /* Set the data */ F->V.Expr = Expr; @@ -739,7 +202,7 @@ void EmitFarAddr (ExprNode* Expr) Emit0 ((Val >> 16) & 0xFF); } else { /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 3); + Fragment* F = GenFragment (FRAG_EXPR, 3); /* Set the data */ F->V.Expr = Expr; @@ -761,7 +224,7 @@ void EmitDWord (ExprNode* Expr) Emit0 ((Val >> 24) & 0xFF); } else { /* Create a new fragment */ - Fragment* F = NewFragment (FRAG_EXPR, 4); + Fragment* F = GenFragment (FRAG_EXPR, 4); /* Set the data */ F->V.Expr = Expr; @@ -779,7 +242,7 @@ void EmitFill (unsigned long Count) Count -= Chunk; /* Emit one chunk */ - NewFragment (FRAG_FILL, Chunk); + GenFragment (FRAG_FILL, Chunk); } } diff --git a/src/ca65/objcode.h b/src/ca65/objcode.h index ddfbc4154..d3f88ea5c 100644 --- a/src/ca65/objcode.h +++ b/src/ca65/objcode.h @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 1998-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -38,80 +38,11 @@ -/* common */ -#include "segdefs.h" - /* ca65 */ #include "expr.h" -/*****************************************************************************/ -/* Data */ -/*****************************************************************************/ - - - -/* Are we in absolute mode or in relocatable mode? */ -extern int RelocMode; - -/* Definitions for predefined segments */ -extern SegDef NullSegDef; -extern SegDef ZeropageSegDef; -extern SegDef DataSegDef; -extern SegDef BssSegDef; -extern SegDef RODataSegDef; -extern SegDef CodeSegDef; - - - -/*****************************************************************************/ -/* Segment management */ -/*****************************************************************************/ - - - -void UseSeg (const SegDef* D); -/* Use the given segment */ - -const SegDef* GetCurrentSeg (void); -/* Get a pointer to the segment defininition of the current segment */ - -unsigned GetSegNum (void); -/* Get the number of the current segment */ - -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. - */ - -int IsZPSeg (void); -/* Return true if the current segment is a zeropage segment */ - -int IsFarSeg (void); -/* Return true if the current segment is a far segment */ - -unsigned GetSegType (unsigned SegNum); -/* Return the type of the segment with the given number */ - -unsigned long GetPC (void); -/* Get the program counter of the current segment */ - -void SetAbsPC (unsigned long AbsPC); -/* Set the program counter in absolute mode */ - -void SegCheck (void); -/* Check the segments for range and other errors */ - -void SegDump (void); -/* Dump the contents of all segments */ - -void WriteSegments (void); -/* Write the segment data to the object file */ - - - /*****************************************************************************/ /* Code */ /*****************************************************************************/ diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 20dfe2e0c..e1b284757 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -66,6 +66,7 @@ #include "options.h" #include "pseudo.h" #include "repeat.h" +#include "segment.h" #include "spool.h" #include "symtab.h" diff --git a/src/ca65/segment.c b/src/ca65/segment.c new file mode 100644 index 000000000..3e50d96ac --- /dev/null +++ b/src/ca65/segment.c @@ -0,0 +1,559 @@ +/*****************************************************************************/ +/* */ +/* segment.c */ +/* */ +/* Segments for the ca65 macroassembler */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#include +#include + +/* common */ +#include "segnames.h" +#include "xmalloc.h" + +/* cc65 */ +#include "error.h" +#include "fragment.h" +#include "global.h" +#include "lineinfo.h" +#include "listing.h" +#include "objcode.h" +#include "objfile.h" +#include "segment.h" +#include "spool.h" +#include "symtab.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 long FragCount; /* Number of fragments */ + unsigned Num; /* Segment number */ + unsigned Align; /* Segment alignment */ + unsigned long PC; + SegDef* Def; /* Segment definition (name and type) */ +}; + + +#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); + +/* Predefined segments */ +static Segment NullSeg = SEG (&NullSegDef, 5, NULL); +static Segment ZeropageSeg = SEG (&ZeropageSegDef, 4, &NullSeg); +static Segment DataSeg = SEG (&DataSegDef, 3, &ZeropageSeg); +static Segment BssSeg = SEG (&BssSegDef, 2, &DataSeg); +static Segment RODataSeg = SEG (&RODataSegDef, 1, &BssSeg); +static Segment CodeSeg = SEG (&CodeSegDef, 0, &RODataSeg); + +/* 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; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +static Segment* NewSegment (const char* Name, unsigned SegType) +/* 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); + } + + /* Check the segment name for invalid names */ + if (!ValidSegName (Name)) { + Error (ERR_ILLEGAL_SEGMENT, Name); + } + + /* Create a new segment */ + S = xmalloc (sizeof (*S)); + + /* Initialize it */ + S->List = 0; + S->Root = 0; + S->Last = 0; + S->FragCount = 0; + S->Num = SegmentCount++; + S->Align = 0; + S->PC = 0; + S->Def = NewSegDef (Name, SegType); + + /* Insert it into the segment list */ + SegmentLast->List = S; + SegmentLast = S; + + /* And return it... */ + return S; +} + + + +Fragment* GenFragment (unsigned char Type, unsigned short Len) +/* Generate a new fragment, add it to the current segment and return it. */ +{ + /* Create the new fragment */ + Fragment* F = NewFragment (Type, Len); + + /* Insert the fragment into the current segment */ + if (ActiveSeg->Root) { + ActiveSeg->Last->Next = F; + ActiveSeg->Last = F; + } else { + ActiveSeg->Root = ActiveSeg->Last = F; + } + ++ActiveSeg->FragCount; + + /* 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 */ + ActiveSeg->PC += F->Len; + if (!RelocMode) { + AbsPC += F->Len; + } + + /* Return the fragment */ + return F; +} + + + +void UseSeg (const SegDef* D) +/* Use the segment with the given name */ +{ + Segment* Seg = SegmentList; + 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); + /* Use the new attribute to avoid errors */ + Seg->Def->Type = D->Type; + } + ActiveSeg = Seg; + return; + } + /* Check next segment */ + Seg = Seg->List; + } + + /* Segment is not in list, create a new one */ + if (D->Type == SEGTYPE_DEFAULT) { + Seg = NewSegment (D->Name, SEGTYPE_ABS); + } else { + Seg = NewSegment (D->Name, D->Type); + } + 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; +} + + + +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 + * 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->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 */ +{ + /* 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->Def->Type; +} + + + +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->Def->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; + unsigned LineInfoIndex; + unsigned long DataSize; + unsigned long EndPos; + + /* Remember the file position, then write a dummy for the size of the + * following data + */ + unsigned long SizePos = ObjGetFilePos (); + ObjWrite32 (0); + + /* Write the segment data */ + 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 */ + ObjWriteVar (Seg->FragCount); /* Number of fragments */ + + /* 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: + ObjWrite8 (FRAG_LITERAL); + ObjWriteVar (Frag->Len); + ObjWriteData (Frag->V.Data, Frag->Len); + 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); + + /* 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); + + /* Next fragment */ + Frag = Frag->Next; + } + + /* Calculate the size of the data, seek back and write it */ + EndPos = ObjGetFilePos (); /* Remember where we are */ + DataSize = EndPos - SizePos - 4; /* Don't count size itself */ + ObjSetFilePos (SizePos); /* Seek back to the size */ + ObjWrite32 (DataSize); /* Write the size */ + ObjSetFilePos (EndPos); /* Seek back to the end */ +} + + + +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 (); +} + + + diff --git a/src/ca65/segment.h b/src/ca65/segment.h new file mode 100644 index 000000000..1d6ce796e --- /dev/null +++ b/src/ca65/segment.h @@ -0,0 +1,124 @@ +/*****************************************************************************/ +/* */ +/* segment.h */ +/* */ +/* Segments for the ca65 macroassembler */ +/* */ +/* */ +/* */ +/* (C) 1998-2003 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ +/* EMail: uz@cc65.org */ +/* */ +/* */ +/* This software is provided 'as-is', without any expressed or implied */ +/* warranty. In no event will the authors be held liable for any damages */ +/* arising from the use of this software. */ +/* */ +/* Permission is granted to anyone to use this software for any purpose, */ +/* including commercial applications, and to alter it and redistribute it */ +/* freely, subject to the following restrictions: */ +/* */ +/* 1. The origin of this software must not be misrepresented; you must not */ +/* claim that you wrote the original software. If you use this software */ +/* in a product, an acknowledgment in the product documentation would be */ +/* appreciated but is not required. */ +/* 2. Altered source versions must be plainly marked as such, and must not */ +/* be misrepresented as being the original software. */ +/* 3. This notice may not be removed or altered from any source */ +/* distribution. */ +/* */ +/*****************************************************************************/ + + + +#ifndef SEGMENT_H +#define SEGMENT_H + + + +/* common */ +#include "fragdefs.h" +#include "segdefs.h" + +/* ca65 */ +#include "fragment.h" + + + +/*****************************************************************************/ +/* Data */ +/*****************************************************************************/ + + + +/* Are we in absolute mode or in relocatable mode? */ +extern int RelocMode; + +/* Definitions for predefined segments */ +extern SegDef NullSegDef; +extern SegDef ZeropageSegDef; +extern SegDef DataSegDef; +extern SegDef BssSegDef; +extern SegDef RODataSegDef; +extern SegDef CodeSegDef; + + + +/*****************************************************************************/ +/* Code */ +/*****************************************************************************/ + + + +Fragment* GenFragment (unsigned char Type, unsigned short Len); +/* Generate a new fragment, add it to the current segment and return it. */ + +void UseSeg (const SegDef* D); +/* Use the given segment */ + +const SegDef* GetCurrentSeg (void); +/* Get a pointer to the segment defininition of the current segment */ + +unsigned GetSegNum (void); +/* Get the number of the current segment */ + +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. + */ + +int IsZPSeg (void); +/* Return true if the current segment is a zeropage segment */ + +int IsFarSeg (void); +/* Return true if the current segment is a far segment */ + +unsigned GetSegType (unsigned SegNum); +/* Return the type of the segment with the given number */ + +unsigned long GetPC (void); +/* Get the program counter of the current segment */ + +void SetAbsPC (unsigned long AbsPC); +/* Set the program counter in absolute mode */ + +void SegCheck (void); +/* Check the segments for range and other errors */ + +void SegDump (void); +/* Dump the contents of all segments */ + +void WriteSegments (void); +/* Write the segment data to the object file */ + + + +/* End of segment.h */ + +#endif + + + diff --git a/src/ca65/symtab.c b/src/ca65/symtab.c index 09837720c..fa3d4847b 100644 --- a/src/ca65/symtab.c +++ b/src/ca65/symtab.c @@ -70,6 +70,7 @@ #define SF_ABS 0x0040 /* Declared as absolute symbol */ #define SF_LABEL 0x0080 /* Used as a label */ #define SF_FORCED 0x0100 /* Forced import, SF_IMPORT also set */ +#define SF_FINALIZED 0x0200 /* Symbol is finalized */ #define SF_INDEXED 0x0800 /* Index is valid */ #define SF_CONST 0x1000 /* The symbol has a constant value */ #define SF_MULTDEF 0x2000 /* Multiply defined symbol */ @@ -369,8 +370,7 @@ void SymEnterLevel (void) RootTab = SymTab = NewSymTable (MAIN_HASHTAB_SIZE); } else { /* Create a local symbol table */ - SymTable* LocalSyms; - LocalSyms = NewSymTable (SUB_HASHTAB_SIZE); + SymTable* LocalSyms = NewSymTable (SUB_HASHTAB_SIZE); LocalSyms->BackLink = SymTab; SymTab = LocalSyms; } @@ -820,12 +820,13 @@ void SymFinalize (SymEntry* S) { /* Resolve trampoline entries */ if (S->Flags & SF_TRAMPOLINE) { - S = S->V.Sym; + S = S->V.Sym; } /* Check if we have an expression */ - if (SymHasExpr (S)) { + if ((S->Flags & SF_FINALIZED) == 0 && SymHasExpr (S)) { S->V.Expr = FinalizeExpr (S->V.Expr); + S->Flags |= SF_FINALIZED; } } -- 2.39.5