mirror of
https://github.com/cc65/cc65.git
synced 2024-12-25 17:29:50 +00:00
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
This commit is contained in:
parent
be14b8e5e4
commit
badfe85991
@ -64,6 +64,7 @@ unsigned char AutoImport = 0; /* Mark unresolveds as import */
|
|||||||
unsigned char SmartMode = 0; /* Smart mode */
|
unsigned char SmartMode = 0; /* Smart mode */
|
||||||
unsigned char DbgSyms = 0; /* Add debug symbols */
|
unsigned char DbgSyms = 0; /* Add debug symbols */
|
||||||
unsigned char LineCont = 0; /* Allow line continuation */
|
unsigned char LineCont = 0; /* Allow line continuation */
|
||||||
|
unsigned char LargeAlignment = 0; /* Don't warn about large alignments */
|
||||||
|
|
||||||
/* Emulation features */
|
/* Emulation features */
|
||||||
unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */
|
unsigned char DollarIsPC = 0; /* Allow the $ symbol as current PC */
|
||||||
|
@ -66,6 +66,7 @@ extern unsigned char AutoImport; /* Mark unresolveds as import */
|
|||||||
extern unsigned char SmartMode; /* Smart mode */
|
extern unsigned char SmartMode; /* Smart mode */
|
||||||
extern unsigned char DbgSyms; /* Add debug symbols */
|
extern unsigned char DbgSyms; /* Add debug symbols */
|
||||||
extern unsigned char LineCont; /* Allow line continuation */
|
extern unsigned char LineCont; /* Allow line continuation */
|
||||||
|
extern unsigned char LargeAlignment; /* Don't warn about large alignments */
|
||||||
|
|
||||||
/* Emulation features */
|
/* Emulation features */
|
||||||
extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */
|
extern unsigned char DollarIsPC; /* Allow the $ symbol as current PC */
|
||||||
|
@ -119,6 +119,7 @@ static void Usage (void)
|
|||||||
" --help\t\t\tHelp (this text)\n"
|
" --help\t\t\tHelp (this text)\n"
|
||||||
" --ignore-case\t\t\tIgnore case of symbols\n"
|
" --ignore-case\t\t\tIgnore case of symbols\n"
|
||||||
" --include-dir dir\t\tSet an include directory search path\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"
|
" --listing name\t\tCreate a listing file if assembly was ok\n"
|
||||||
" --list-bytes n\t\tMaximum number of bytes per listing line\n"
|
" --list-bytes n\t\tMaximum number of bytes per listing line\n"
|
||||||
" --macpack-dir dir\t\tSet a macro package directory\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)
|
static void OptListBytes (const char* Opt, const char* Arg)
|
||||||
/* Set the maximum number of bytes per listing line */
|
/* Set the maximum number of bytes per listing line */
|
||||||
{
|
{
|
||||||
@ -849,6 +859,7 @@ int main (int argc, char* argv [])
|
|||||||
{ "--help", 0, OptHelp },
|
{ "--help", 0, OptHelp },
|
||||||
{ "--ignore-case", 0, OptIgnoreCase },
|
{ "--ignore-case", 0, OptIgnoreCase },
|
||||||
{ "--include-dir", 1, OptIncludeDir },
|
{ "--include-dir", 1, OptIncludeDir },
|
||||||
|
{ "--large-alignment", 0, OptLargeAlignment },
|
||||||
{ "--list-bytes", 1, OptListBytes },
|
{ "--list-bytes", 1, OptListBytes },
|
||||||
{ "--listing", 1, OptListing },
|
{ "--listing", 1, OptListing },
|
||||||
{ "--macpack-dir", 1, OptMacPackDir },
|
{ "--macpack-dir", 1, OptMacPackDir },
|
||||||
|
@ -42,6 +42,7 @@
|
|||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
|
#include "alignment.h"
|
||||||
#include "assertion.h"
|
#include "assertion.h"
|
||||||
#include "bitops.h"
|
#include "bitops.h"
|
||||||
#include "cddefs.h"
|
#include "cddefs.h"
|
||||||
@ -395,13 +396,12 @@ static void DoAddr (void)
|
|||||||
static void DoAlign (void)
|
static void DoAlign (void)
|
||||||
/* Align the PC to some boundary */
|
/* Align the PC to some boundary */
|
||||||
{
|
{
|
||||||
long Val;
|
long FillVal;
|
||||||
long Align;
|
long Alignment;
|
||||||
unsigned Bit;
|
|
||||||
|
|
||||||
/* Read the alignment value */
|
/* Read the alignment value */
|
||||||
Align = ConstExpression ();
|
Alignment = ConstExpression ();
|
||||||
if (Align <= 0 || Align > 0x10000) {
|
if (Alignment <= 0 || (unsigned long) Alignment > MAX_ALIGNMENT) {
|
||||||
ErrorSkip ("Range error");
|
ErrorSkip ("Range error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -409,23 +409,18 @@ static void DoAlign (void)
|
|||||||
/* Optional value follows */
|
/* Optional value follows */
|
||||||
if (CurTok.Tok == TOK_COMMA) {
|
if (CurTok.Tok == TOK_COMMA) {
|
||||||
NextTok ();
|
NextTok ();
|
||||||
Val = ConstExpression ();
|
FillVal = ConstExpression ();
|
||||||
/* We need a byte value here */
|
/* We need a byte value here */
|
||||||
if (!IsByteRange (Val)) {
|
if (!IsByteRange (FillVal)) {
|
||||||
ErrorSkip ("Range error");
|
ErrorSkip ("Range error");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Val = -1;
|
FillVal = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if the alignment is a power of two */
|
/* Generate the alignment */
|
||||||
Bit = BitFind (Align);
|
SegAlign (Alignment, (int) FillVal);
|
||||||
if (Align != (0x01L << Bit)) {
|
|
||||||
Error ("Alignment value must be a power of 2");
|
|
||||||
} else {
|
|
||||||
SegAlign (Bit, (int) Val);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -38,6 +38,7 @@
|
|||||||
|
|
||||||
/* common */
|
/* common */
|
||||||
#include "addrsize.h"
|
#include "addrsize.h"
|
||||||
|
#include "alignment.h"
|
||||||
#include "coll.h"
|
#include "coll.h"
|
||||||
#include "mmodel.h"
|
#include "mmodel.h"
|
||||||
#include "segnames.h"
|
#include "segnames.h"
|
||||||
@ -106,7 +107,7 @@ static Segment* NewSegFromDef (SegDef* Def)
|
|||||||
S->Last = 0;
|
S->Last = 0;
|
||||||
S->FragCount = 0;
|
S->FragCount = 0;
|
||||||
S->Num = CollCount (&SegmentList);
|
S->Num = CollCount (&SegmentList);
|
||||||
S->Align = 0;
|
S->Align = 1;
|
||||||
S->RelocMode = 1;
|
S->RelocMode = 1;
|
||||||
S->PC = 0;
|
S->PC = 0;
|
||||||
S->AbsPC = 0;
|
S->AbsPC = 0;
|
||||||
@ -276,20 +277,41 @@ void EnterRelocMode (void)
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
void SegAlign (unsigned Power, int Val)
|
void SegAlign (unsigned long Alignment, int FillVal)
|
||||||
/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
|
/* Align the PC segment to Alignment. If FillVal is -1, emit fill fragments
|
||||||
* actual fill value will be determined by the linker), otherwise use the
|
* (the actual fill value will be determined by the linker), otherwise use
|
||||||
* given value.
|
* the given value.
|
||||||
*/
|
*/
|
||||||
{
|
{
|
||||||
unsigned char Data [4];
|
unsigned char Data [4];
|
||||||
unsigned long Align = (1UL << Power) - 1;
|
unsigned long CombinedAlignment;
|
||||||
unsigned long NewPC = (ActiveSeg->PC + Align) & ~Align;
|
unsigned long Count;
|
||||||
unsigned long Count = NewPC - ActiveSeg->PC;
|
|
||||||
|
|
||||||
if (Val != -1) {
|
/* 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 {
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* 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 */
|
/* User defined fill value */
|
||||||
memset (Data, Val, sizeof (Data));
|
memset (Data, FillVal, sizeof (Data));
|
||||||
while (Count) {
|
while (Count) {
|
||||||
if (Count > sizeof (Data)) {
|
if (Count > sizeof (Data)) {
|
||||||
EmitData (Data, sizeof (Data));
|
EmitData (Data, sizeof (Data));
|
||||||
@ -303,11 +325,6 @@ void SegAlign (unsigned Power, int Val)
|
|||||||
/* Linker defined fill value */
|
/* Linker defined fill value */
|
||||||
EmitFill (Count);
|
EmitFill (Count);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Remember the alignment in the header */
|
|
||||||
if (ActiveSeg->Align < Power) {
|
|
||||||
ActiveSeg->Align = Power;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -514,7 +531,7 @@ static void WriteOneSeg (Segment* Seg)
|
|||||||
/* Write the segment data */
|
/* Write the segment data */
|
||||||
ObjWriteVar (GetStringId (Seg->Def->Name)); /* Name of the segment */
|
ObjWriteVar (GetStringId (Seg->Def->Name)); /* Name of the segment */
|
||||||
ObjWriteVar (Seg->PC); /* Size */
|
ObjWriteVar (Seg->PC); /* Size */
|
||||||
ObjWrite8 (Seg->Align); /* Segment alignment */
|
ObjWriteVar (Seg->Align); /* Segment alignment */
|
||||||
ObjWrite8 (Seg->Def->AddrSize); /* Address size of the segment */
|
ObjWrite8 (Seg->Def->AddrSize); /* Address size of the segment */
|
||||||
ObjWriteVar (Seg->FragCount); /* Number of fragments */
|
ObjWriteVar (Seg->FragCount); /* Number of fragments */
|
||||||
|
|
||||||
|
@ -62,7 +62,7 @@ struct Segment {
|
|||||||
Fragment* Last; /* Pointer to last fragment */
|
Fragment* Last; /* Pointer to last fragment */
|
||||||
unsigned long FragCount; /* Number of fragments */
|
unsigned long FragCount; /* Number of fragments */
|
||||||
unsigned Num; /* Segment number */
|
unsigned Num; /* Segment number */
|
||||||
unsigned Align; /* Segment alignment */
|
unsigned long Align; /* Segment alignment */
|
||||||
int RelocMode; /* Relocatable mode if OrgPerSeg */
|
int RelocMode; /* Relocatable mode if OrgPerSeg */
|
||||||
unsigned long PC; /* PC if in relocatable mode */
|
unsigned long PC; /* PC if in relocatable mode */
|
||||||
unsigned long AbsPC; /* PC if in local absolute mode */
|
unsigned long AbsPC; /* PC if in local absolute mode */
|
||||||
@ -128,10 +128,10 @@ INLINE unsigned char GetCurrentSegAddrSize (void)
|
|||||||
# define GetCurrentSegAddrSize() (ActiveSeg->Def->AddrSize)
|
# define GetCurrentSegAddrSize() (ActiveSeg->Def->AddrSize)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
void SegAlign (unsigned Power, int Val);
|
void SegAlign (unsigned long Alignment, int FillVal);
|
||||||
/* Align the PC segment to 2^Power. If Val is -1, emit fill fragments (the
|
/* Align the PC segment to Alignment. If FillVal is -1, emit fill fragments
|
||||||
* actual fill value will be determined by the linker), otherwise use the
|
* (the actual fill value will be determined by the linker), otherwise use
|
||||||
* given value.
|
* the given value.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
unsigned char GetSegAddrSize (unsigned SegNum);
|
unsigned char GetSegAddrSize (unsigned SegNum);
|
||||||
|
Loading…
Reference in New Issue
Block a user