From badfe85991618dd8e44fb3486f122cd8b390d1e5 Mon Sep 17 00:00:00 2001 From: uz Date: Tue, 27 Dec 2011 22:54:52 +0000 Subject: [PATCH] Allow arbitrary alignments, not just powers of two. Beware: This needs support in the linker which is currently missing. git-svn-id: svn://svn.cc65.org/cc65/trunk@5334 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- src/ca65/global.c | 1 + src/ca65/global.h | 1 + src/ca65/main.c | 11 +++++++ src/ca65/pseudo.c | 39 +++++++++++-------------- src/ca65/segment.c | 73 ++++++++++++++++++++++++++++------------------ src/ca65/segment.h | 10 +++---- 6 files changed, 80 insertions(+), 55 deletions(-) diff --git a/src/ca65/global.c b/src/ca65/global.c index e934652ec..ced950d6b 100644 --- a/src/ca65/global.c +++ b/src/ca65/global.c @@ -64,6 +64,7 @@ unsigned char AutoImport = 0; /* Mark unresolveds as import */ unsigned char SmartMode = 0; /* Smart mode */ unsigned char DbgSyms = 0; /* Add debug symbols */ unsigned char LineCont = 0; /* Allow line continuation */ +unsigned char LargeAlignment = 0; /* Don't warn about large alignments */ /* Emulation features */ unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */ diff --git a/src/ca65/global.h b/src/ca65/global.h index 9cdd18e68..51b31725b 100644 --- a/src/ca65/global.h +++ b/src/ca65/global.h @@ -66,6 +66,7 @@ extern unsigned char AutoImport; /* Mark unresolveds as import */ extern unsigned char SmartMode; /* Smart mode */ extern unsigned char DbgSyms; /* Add debug symbols */ extern unsigned char LineCont; /* Allow line continuation */ +extern unsigned char LargeAlignment; /* Don't warn about large alignments */ /* Emulation features */ extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */ diff --git a/src/ca65/main.c b/src/ca65/main.c index 43da5ffd7..6b16dd98b 100644 --- a/src/ca65/main.c +++ b/src/ca65/main.c @@ -119,6 +119,7 @@ static void Usage (void) " --help\t\t\tHelp (this text)\n" " --ignore-case\t\t\tIgnore case of symbols\n" " --include-dir dir\t\tSet an include directory search path\n" + " --large-alignment\t\tDon't warn about large alignments\n" " --listing name\t\tCreate a listing file if assembly was ok\n" " --list-bytes n\t\tMaximum number of bytes per listing line\n" " --macpack-dir dir\t\tSet a macro package directory\n" @@ -458,6 +459,15 @@ static void OptIncludeDir (const char* Opt attribute ((unused)), const char* Arg +static void OptLargeAlignment (const char* Opt attribute ((unused)), + const char* Arg attribute ((unused))) +/* Don't warn about large alignments */ +{ + LargeAlignment = 1; +} + + + static void OptListBytes (const char* Opt, const char* Arg) /* Set the maximum number of bytes per listing line */ { @@ -849,6 +859,7 @@ int main (int argc, char* argv []) { "--help", 0, OptHelp }, { "--ignore-case", 0, OptIgnoreCase }, { "--include-dir", 1, OptIncludeDir }, + { "--large-alignment", 0, OptLargeAlignment }, { "--list-bytes", 1, OptListBytes }, { "--listing", 1, OptListing }, { "--macpack-dir", 1, OptMacPackDir }, diff --git a/src/ca65/pseudo.c b/src/ca65/pseudo.c index 477a6a698..365fd5b79 100644 --- a/src/ca65/pseudo.c +++ b/src/ca65/pseudo.c @@ -42,6 +42,7 @@ #include /* common */ +#include "alignment.h" #include "assertion.h" #include "bitops.h" #include "cddefs.h" @@ -395,37 +396,31 @@ static void DoAddr (void) static void DoAlign (void) /* Align the PC to some boundary */ { - long Val; - long Align; - unsigned Bit; + long FillVal; + long Alignment; /* Read the alignment value */ - Align = ConstExpression (); - if (Align <= 0 || Align > 0x10000) { - ErrorSkip ("Range error"); - return; + Alignment = ConstExpression (); + if (Alignment <= 0 || (unsigned long) Alignment > MAX_ALIGNMENT) { + ErrorSkip ("Range error"); + return; } /* Optional value follows */ if (CurTok.Tok == TOK_COMMA) { - NextTok (); - Val = ConstExpression (); - /* We need a byte value here */ - if (!IsByteRange (Val)) { - ErrorSkip ("Range error"); - return; - } + NextTok (); + FillVal = ConstExpression (); + /* We need a byte value here */ + if (!IsByteRange (FillVal)) { + ErrorSkip ("Range error"); + return; + } } else { - Val = -1; + FillVal = -1; } - /* Check if the alignment is a power of two */ - Bit = BitFind (Align); - if (Align != (0x01L << Bit)) { - Error ("Alignment value must be a power of 2"); - } else { - SegAlign (Bit, (int) Val); - } + /* Generate the alignment */ + SegAlign (Alignment, (int) FillVal); } diff --git a/src/ca65/segment.c b/src/ca65/segment.c index 9a1532b26..a1c2aed27 100644 --- a/src/ca65/segment.c +++ b/src/ca65/segment.c @@ -38,6 +38,7 @@ /* common */ #include "addrsize.h" +#include "alignment.h" #include "coll.h" #include "mmodel.h" #include "segnames.h" @@ -106,7 +107,7 @@ static Segment* NewSegFromDef (SegDef* Def) S->Last = 0; S->FragCount = 0; S->Num = CollCount (&SegmentList); - S->Align = 0; + S->Align = 1; S->RelocMode = 1; S->PC = 0; S->AbsPC = 0; @@ -276,37 +277,53 @@ void EnterRelocMode (void) -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. +void SegAlign (unsigned long Alignment, int FillVal) +/* Align the PC segment to Alignment. If FillVal 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; - } - } + unsigned long CombinedAlignment; + unsigned long Count; + + /* The segment must have the combined alignment of all separate alignments + * in the source. Calculate this alignment and check it for sanity. + */ + CombinedAlignment = LeastCommonMultiple (ActiveSeg->Align, Alignment); + if (CombinedAlignment > MAX_ALIGNMENT) { + Error ("Combined alignment for active segment exceeds 0x10000"); } else { - /* Linker defined fill value */ - EmitFill (Count); + ActiveSeg->Align = CombinedAlignment; + + /* Output a warning for larger alignments if not suppressed */ + if (CombinedAlignment > LARGE_ALIGNMENT && !LargeAlignment) { + Warning (0, "Combined alignment is suspiciously large (%lu)", + CombinedAlignment); + } } - /* Remember the alignment in the header */ - if (ActiveSeg->Align < Power) { - ActiveSeg->Align = Power; + + + /* Calculate the number of fill bytes */ + Count = AlignCount (ActiveSeg->PC, Alignment) - ActiveSeg->PC; + + /* Emit the data or a fill fragment */ + if (FillVal != -1) { + /* User defined fill value */ + memset (Data, FillVal, 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); } } @@ -513,8 +530,8 @@ static void WriteOneSeg (Segment* Seg) /* Write the segment data */ ObjWriteVar (GetStringId (Seg->Def->Name)); /* Name of the segment */ - ObjWriteVar (Seg->PC); /* Size */ - ObjWrite8 (Seg->Align); /* Segment alignment */ + ObjWriteVar (Seg->PC); /* Size */ + ObjWriteVar (Seg->Align); /* Segment alignment */ ObjWrite8 (Seg->Def->AddrSize); /* Address size of the segment */ ObjWriteVar (Seg->FragCount); /* Number of fragments */ diff --git a/src/ca65/segment.h b/src/ca65/segment.h index c28c86be1..0575bc774 100644 --- a/src/ca65/segment.h +++ b/src/ca65/segment.h @@ -62,7 +62,7 @@ struct Segment { Fragment* Last; /* Pointer to last fragment */ unsigned long FragCount; /* Number of fragments */ unsigned Num; /* Segment number */ - unsigned Align; /* Segment alignment */ + unsigned long Align; /* Segment alignment */ int RelocMode; /* Relocatable mode if OrgPerSeg */ unsigned long PC; /* PC if in relocatable mode */ unsigned long AbsPC; /* PC if in local absolute mode */ @@ -128,10 +128,10 @@ INLINE unsigned char GetCurrentSegAddrSize (void) # define GetCurrentSegAddrSize() (ActiveSeg->Def->AddrSize) #endif -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. +void SegAlign (unsigned long Alignment, int FillVal); +/* Align the PC segment to Alignment. If FillVal is -1, emit fill fragments + * (the actual fill value will be determined by the linker), otherwise use + * the given value. */ unsigned char GetSegAddrSize (unsigned SegNum); -- 2.39.5