From: cuz Date: Sat, 8 Jan 2005 13:44:11 +0000 (+0000) Subject: New segment attribute ALIGN_LOAD. Some cleanup. X-Git-Tag: V2.12.0~483 X-Git-Url: https://git.sur5r.net/?a=commitdiff_plain;h=7774e57eae856acf4c76d9c6868c46a4706110ae;p=cc65 New segment attribute ALIGN_LOAD. Some cleanup. git-svn-id: svn://svn.cc65.org/cc65/trunk@3353 b7a2c559-68d2-44c3-8de9-860c34a00d81 --- diff --git a/src/ld65/bin.c b/src/ld65/bin.c index d1f8acd9a..9ba09f673 100644 --- a/src/ld65/bin.c +++ b/src/ld65/bin.c @@ -6,9 +6,9 @@ /* */ /* */ /* */ -/* (C) 1999-2001 Ullrich von Bassewitz */ -/* Wacholderweg 14 */ -/* D-70597 Stuttgart */ +/* (C) 1999-2005 Ullrich von Bassewitz */ +/* Römerstrasse 52 */ +/* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ /* */ /* */ @@ -141,8 +141,8 @@ static void BinWriteMem (BinDesc* D, Memory* M) /* Writes do only occur in the load area and not for BSS segments */ DoWrite = (S->Flags & SF_BSS) == 0 && /* No BSS segment */ - S->Load == M && /* LOAD segment */ - S->Seg->Dumped == 0; /* Not already written */ + S->Load == M && /* LOAD segment */ + S->Seg->Dumped == 0; /* Not already written */ /* Output the DoWrite flag for debugging */ if (Verbosity > 1) { @@ -158,38 +158,59 @@ static void BinWriteMem (BinDesc* D, Memory* M) * in the linker. */ Warning ("Segment `%s' in module `%s' requires larger alignment", - GetString (S->Name), GetObjFileName (S->Seg->AlignObj)); + GetString (S->Name), GetObjFileName (S->Seg->AlignObj)); } - /* Handle ALIGN and OFFSET/START */ - if (S->Flags & SF_ALIGN) { - /* Align the address */ - unsigned long Val, NewAddr; - Val = (0x01UL << S->Align) - 1; - NewAddr = (Addr + Val) & ~Val; - if (DoWrite) { - WriteMult (D->F, M->FillVal, NewAddr-Addr); - } - Addr = NewAddr; - /* Remember the fill value for the segment */ - S->Seg->FillVal = M->FillVal; - } else if (S->Flags & (SF_OFFSET | SF_START)) { - unsigned long NewAddr = S->Addr; - if (S->Flags & SF_OFFSET) { - /* It's an offset, not a fixed address, make an address */ - NewAddr += M->Start; - } - if (DoWrite) { - WriteMult (D->F, M->FillVal, NewAddr-Addr); - } - Addr = NewAddr; - } + /* If this is the run memory area, we must apply run alignment. If + * this is not the run memory area but the load memory area (which + * means that both are different), we must apply load alignment. + * Beware: DoWrite may be true even if this is the run memory area, + * because it may be also the load memory area. + */ + if (S->Run == M) { + + /* Handle ALIGN and OFFSET/START */ + if (S->Flags & SF_ALIGN) { + /* Align the address */ + unsigned long Val = (0x01UL << S->Align) - 1; + unsigned long NewAddr = (Addr + Val) & ~Val; + if (DoWrite) { + WriteMult (D->F, M->FillVal, NewAddr-Addr); + } + Addr = NewAddr; + } else if (S->Flags & (SF_OFFSET | SF_START)) { + unsigned long NewAddr = S->Addr; + if (S->Flags & SF_OFFSET) { + /* It's an offset, not a fixed address, make an address */ + NewAddr += M->Start; + } + if (DoWrite) { + WriteMult (D->F, M->FillVal, NewAddr-Addr); + } + Addr = NewAddr; + } + + } else if (S->Load == M) { + + /* Handle ALIGN_LOAD */ + if (S->Flags & SF_ALIGN_LOAD) { + /* Align the address */ + unsigned long Val = (0x01UL << S->AlignLoad) - 1; + unsigned long NewAddr = (Addr + Val) & ~Val; + if (DoWrite) { + WriteMult (D->F, M->FillVal, NewAddr-Addr); + } + Addr = NewAddr; + } + + } /* Now write the segment to disk if it is not a BSS type segment and * if the memory area is the load area. */ if (DoWrite) { RelocLineInfo (S->Seg); + S->Seg->FillVal = M->FillVal; SegWrite (D->F, S->Seg, BinWriteExpr, D); } else if (M->Flags & MF_FILL) { WriteMult (D->F, M->FillVal, S->Seg->Size); @@ -208,11 +229,9 @@ static void BinWriteMem (BinDesc* D, Memory* M) } /* If a fill was requested, fill the remaining space */ - if (M->Flags & MF_FILL) { - while (M->FillLevel < M->Size) { - Write8 (D->F, M->FillVal); - ++M->FillLevel; - } + if ((M->Flags & MF_FILL) != 0 && M->FillLevel < M->Size) { + WriteMult (D->F, M->FillVal, M->Size - M->FillLevel); + M->FillLevel = M->Size; } } @@ -229,7 +248,7 @@ static int BinUnresolved (unsigned Name attribute ((unused)), void* D) return 0; } - + void BinWriteTarget (BinDesc* D, struct File* F) /* Write a binary output file */ diff --git a/src/ld65/config.c b/src/ld65/config.c index 608cc8949..7bcc33f67 100644 --- a/src/ld65/config.c +++ b/src/ld65/config.c @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2004 Ullrich von Bassewitz */ +/* (C) 1998-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -96,10 +96,11 @@ unsigned SegDescCount; /* Number of entries in list */ #define SA_LOAD 0x0002 #define SA_RUN 0x0004 #define SA_ALIGN 0x0008 -#define SA_DEFINE 0x0010 -#define SA_OFFSET 0x0020 -#define SA_START 0x0040 -#define SA_OPTIONAL 0x0080 +#define SA_ALIGN_LOAD 0x0010 +#define SA_DEFINE 0x0020 +#define SA_OFFSET 0x0040 +#define SA_START 0x0080 +#define SA_OPTIONAL 0x0100 @@ -598,21 +599,21 @@ static void ParseSegments (void) /* Parse a SEGMENTS section */ { static const IdentTok Attributes [] = { - { "ALIGN", CFGTOK_ALIGN }, - { "DEFINE", CFGTOK_DEFINE }, - { "LOAD", CFGTOK_LOAD }, - { "OFFSET", CFGTOK_OFFSET }, - { "OPTIONAL", CFGTOK_OPTIONAL }, - { "RUN", CFGTOK_RUN }, - { "START", CFGTOK_START }, - { "TYPE", CFGTOK_TYPE }, + { "ALIGN", CFGTOK_ALIGN }, + { "ALIGN_LOAD", CFGTOK_ALIGN_LOAD }, + { "DEFINE", CFGTOK_DEFINE }, + { "LOAD", CFGTOK_LOAD }, + { "OFFSET", CFGTOK_OFFSET }, + { "OPTIONAL", CFGTOK_OPTIONAL }, + { "RUN", CFGTOK_RUN }, + { "START", CFGTOK_START }, + { "TYPE", CFGTOK_TYPE }, }; static const IdentTok Types [] = { - { "RO", CFGTOK_RO }, - { "RW", CFGTOK_RW }, - { "BSS", CFGTOK_BSS }, - { "ZP", CFGTOK_ZP }, - { "WPROT", CFGTOK_RO }, /* ### OBSOLETE */ + { "RO", CFGTOK_RO }, + { "RW", CFGTOK_RW }, + { "BSS", CFGTOK_BSS }, + { "ZP", CFGTOK_ZP }, }; unsigned Count; @@ -654,6 +655,17 @@ static void ParseSegments (void) S->Flags |= SF_ALIGN; break; + case CFGTOK_ALIGN_LOAD: + CfgAssureInt (); + FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD"); + CfgRangeCheck (1, 0x10000); + S->AlignLoad = BitFind (CfgIVal); + if ((0x01UL << S->AlignLoad) != CfgIVal) { + CfgError ("Alignment must be a power of 2"); + } + S->Flags |= SF_ALIGN_LOAD; + break; + case CFGTOK_DEFINE: FlagAttr (&S->Attr, SA_DEFINE, "DEFINE"); /* Map the token to a boolean */ @@ -705,7 +717,7 @@ static void ParseSegments (void) case CFGTOK_RW: /* Default */ break; case CFGTOK_BSS: S->Flags |= SF_BSS; break; case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break; - default: Internal ("Unexpected token: %d", CfgTok); + default: Internal ("Unexpected token: %d", CfgTok); } break; @@ -726,14 +738,7 @@ static void ParseSegments (void) if ((S->Attr & SA_RUN) == 0) { S->Attr |= SA_RUN; S->Run = S->Load; - } else { - /* Both attributes given */ - S->Flags |= SF_LOAD_AND_RUN; - } - if ((S->Attr & SA_ALIGN) == 0) { - S->Attr |= SA_ALIGN; - S->Align = 0; - } + } /* If the segment is marked as BSS style, and if the segment exists * in any of the object file, check that there's no initialized data @@ -744,10 +749,21 @@ static void ParseSegments (void) CfgGetName (), CfgErrorLine); } + /* An attribute of ALIGN_LOAD doesn't make sense if there are no + * separate run and load memory areas. + */ + if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) { + Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate " + "LOAD and RUN memory areas assigned", + CfgGetName (), CfgErrorLine); + /* Remove the flag */ + S->Flags &= ~SF_ALIGN_LOAD; + } + /* If the segment is marked as BSS style, it may not have separate * load and run memory areas, because it's is never written to disk. */ - if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) { + if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) { Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN " "memory areas assigned", CfgGetName (), CfgErrorLine); } @@ -778,8 +794,8 @@ static void ParseSegments (void) SegDescInsert (S); /* Insert the segment into the memory area list */ MemoryInsert (S->Run, S); - if ((S->Flags & SF_LOAD_AND_RUN) != 0) { - /* We have a separate RUN area given */ + if (S->Load != S->Run) { + /* We have separate RUN and LOAD areas */ MemoryInsert (S->Load, S); } } else { @@ -1448,40 +1464,58 @@ void CfgAssignSegments (void) /* Get the segment from the node */ SegDesc* S = N->Seg; - /* Handle ALIGN and OFFSET/START */ - if (S->Flags & SF_ALIGN) { - /* Align the address */ - unsigned long Val = (0x01UL << S->Align) - 1; - Addr = (Addr + Val) & ~Val; - } else if (S->Flags & (SF_OFFSET | SF_START)) { - /* Give the segment a fixed starting address */ - unsigned long NewAddr = S->Addr; - if (S->Flags & SF_OFFSET) { - /* An offset was given, no address, make an address */ - NewAddr += M->Start; - } - if (Addr > NewAddr) { - /* Offset already too large */ - if (S->Flags & SF_OFFSET) { - Error ("Offset too small in `%s', segment `%s'", - GetString (M->Name), GetString (S->Name)); - } else { - Error ("Start address too low in `%s', segment `%s'", - GetString (M->Name), GetString (S->Name)); - } - } - Addr = NewAddr; - } - - /* If this is the run area, set the start address of this segment, - * set the readonly flag in the segment and and remember if the - * segment is in a relocatable file or not. + /* Some actions depend on wether this is the load or run memory + * area. */ - if (S->Run == M) { - S->Seg->PC = Addr; + if (S->Run == M) { + + /* This is the run (and maybe load) memory area. Handle + * alignment and explict start address and offset. + */ + if (S->Flags & SF_ALIGN) { + /* Align the address */ + unsigned long Val = (0x01UL << S->Align) - 1; + Addr = (Addr + Val) & ~Val; + } else if (S->Flags & (SF_OFFSET | SF_START)) { + /* Give the segment a fixed starting address */ + unsigned long NewAddr = S->Addr; + if (S->Flags & SF_OFFSET) { + /* An offset was given, no address, make an address */ + NewAddr += M->Start; + } + if (Addr > NewAddr) { + /* Offset already too large */ + if (S->Flags & SF_OFFSET) { + Error ("Offset too small in `%s', segment `%s'", + GetString (M->Name), GetString (S->Name)); + } else { + Error ("Start address too low in `%s', segment `%s'", + GetString (M->Name), GetString (S->Name)); + } + } + Addr = NewAddr; + } + + /* Set the start address of this segment, set the readonly flag + * in the segment and and remember if the segment is in a + * relocatable file or not. + */ + S->Seg->PC = Addr; S->Seg->ReadOnly = (S->Flags & SF_RO) != 0; S->Seg->Relocatable = M->Relocatable; - } + + } else if (S->Load == M) { + + /* This is the load memory area, *and* run and load are + * different (because of the "else" above). Handle alignment. + */ + if (S->Flags & SF_ALIGN_LOAD) { + /* Align the address */ + unsigned long Val = (0x01UL << S->AlignLoad) - 1; + Addr = (Addr + Val) & ~Val; + } + + } /* Increment the fill level of the memory area and check for an * overflow. @@ -1497,33 +1531,12 @@ void CfgAssignSegments (void) * segment. */ if (S->Flags & SF_DEFINE) { - if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) { - /* RUN and LOAD given and in one memory area. - * Be careful: We will encounter this code twice, the - * first time when walking the RUN list, second time when - * walking the LOAD list. Be sure to define only the - * relevant symbols on each walk. - */ - if (S->Load == M) { - if ((S->Flags & SF_LOAD_DEF) == 0) { - CreateLoadDefines (S, Addr); - } else { - CHECK ((S->Flags & SF_RUN_DEF) == 0); - CreateRunDefines (S, Addr); - } - } - } else { - /* RUN and LOAD in different memory areas, or RUN not - * given, so RUN defaults to LOAD. In the latter case, we - * have only one copy of the segment in the area. - */ - if (S->Run == M) { - CreateRunDefines (S, Addr); - } - if (S->Load == M) { - CreateLoadDefines (S, Addr); - } - } + if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) { + CreateRunDefines (S, Addr); + } + if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) { + CreateLoadDefines (S, Addr); + } } /* Calculate the new address */ diff --git a/src/ld65/config.h b/src/ld65/config.h index 38282689f..88d939eea 100644 --- a/src/ld65/config.h +++ b/src/ld65/config.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2003 Ullrich von Bassewitz */ +/* (C) 1998-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -96,7 +96,8 @@ struct SegDesc { Memory* Load; /* Load memory section */ Memory* Run; /* Run memory section */ unsigned long Addr; /* Start address or offset into segment */ - unsigned char Align; /* Alignment if given */ + unsigned char Align; /* Run area alignment if given */ + unsigned char AlignLoad; /* Load area alignment if given */ }; /* Segment list */ @@ -113,13 +114,13 @@ extern unsigned SegDescCount; /* Number of entries in list */ #define SF_BSS 0x0002 /* Segment is BSS style segment */ #define SF_ZP 0x0004 /* Zeropage segment (o65 only) */ #define SF_DEFINE 0x0008 /* Define start and size */ -#define SF_ALIGN 0x0010 /* Align the segment */ -#define SF_OFFSET 0x0020 /* Segment has offset in memory */ -#define SF_START 0x0040 /* Segment has fixed start address */ -#define SF_OPTIONAL 0x0080 /* Segment is optional (must not exist) */ -#define SF_LOAD_AND_RUN 0x1000 /* LOAD and RUN given */ -#define SF_RUN_DEF 0x2000 /* RUN symbols already defined */ -#define SF_LOAD_DEF 0x4000 /* LOAD symbols already defined */ +#define SF_ALIGN 0x0010 /* Align segment in run area */ +#define SF_ALIGN_LOAD 0x0020 /* Align segment in load area */ +#define SF_OFFSET 0x0040 /* Segment has offset in memory */ +#define SF_START 0x0080 /* Segment has fixed start address */ +#define SF_OPTIONAL 0x0100 /* Segment is optional (must not exist) */ +#define SF_RUN_DEF 0x0200 /* RUN symbols already defined */ +#define SF_LOAD_DEF 0x0400 /* LOAD symbols already defined */ diff --git a/src/ld65/scanner.h b/src/ld65/scanner.h index aa4758627..5604f59ed 100644 --- a/src/ld65/scanner.h +++ b/src/ld65/scanner.h @@ -6,7 +6,7 @@ /* */ /* */ /* */ -/* (C) 1998-2004 Ullrich von Bassewitz */ +/* (C) 1998-2005 Ullrich von Bassewitz */ /* Römerstrasse 52 */ /* D-70794 Filderstadt */ /* EMail: uz@cc65.org */ @@ -84,6 +84,7 @@ typedef enum { CFGTOK_LOAD, CFGTOK_RUN, CFGTOK_ALIGN, + CFGTOK_ALIGN_LOAD, CFGTOK_OFFSET, CFGTOK_OPTIONAL,