From e58c84acf7958c7e21879fea9daceef423da2e6e Mon Sep 17 00:00:00 2001 From: acqn Date: Tue, 21 Jan 2020 10:39:19 +0800 Subject: [PATCH] Support for optionally specifying address size for segments with: #pragma ***-name([push,] "name"[, "addrsize"]) where "addrsize" is any addressing size supported in ca65. --- src/cc65/codegen.c | 12 +++++- src/cc65/main.c | 6 +++ src/cc65/pragma.c | 30 ++++++++++++++- src/cc65/segments.c | 90 +++++++++++++++++++++++++++++++++++++++++++++ src/cc65/segments.h | 13 +++++++ 5 files changed, 148 insertions(+), 3 deletions(-) diff --git a/src/cc65/codegen.c b/src/cc65/codegen.c index bc85ba1de..539309283 100644 --- a/src/cc65/codegen.c +++ b/src/cc65/codegen.c @@ -39,6 +39,7 @@ #include /* common */ +#include "addrsize.h" #include "check.h" #include "cpu.h" #include "inttypes.h" @@ -260,6 +261,9 @@ void g_usebss (void) void g_segname (segment_t Seg) /* Emit the name of a segment if necessary */ { + unsigned char AddrSize; + const char* Name; + /* Emit a segment directive for the data style segments */ DataSeg* S; switch (Seg) { @@ -269,7 +273,13 @@ void g_segname (segment_t Seg) default: S = 0; break; } if (S) { - DS_AddLine (S, ".segment\t\"%s\"", GetSegName (Seg)); + Name = GetSegName (Seg); + AddrSize = GetSegAddrSize (Name); + if (AddrSize != ADDR_SIZE_INVALID) { + DS_AddLine (S, ".segment\t\"%s\": %s", Name, AddrSizeToStr (AddrSize)); + } else { + DS_AddLine (S, ".segment\t\"%s\"", Name); + } } } diff --git a/src/cc65/main.c b/src/cc65/main.c index 26dd721be..fabd71ef7 100644 --- a/src/cc65/main.c +++ b/src/cc65/main.c @@ -897,6 +897,9 @@ int main (int argc, char* argv[]) /* Initialize the default segment names */ InitSegNames (); + /* Initialize the segment address sizes table */ + InitSegAddrSizes (); + /* Initialize the include search paths */ InitIncludePaths (); @@ -1089,6 +1092,9 @@ int main (int argc, char* argv[]) /* Done with tracked string buffer allocation */ DoneDiagnosticStrBufs (); + /* Free up the segment address sizes table */ + DoneSegAddrSizes (); + /* Return an apropriate exit code */ return (ErrorCount > 0)? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/src/cc65/pragma.c b/src/cc65/pragma.c index c614bbfdd..cf463a832 100644 --- a/src/cc65/pragma.c +++ b/src/cc65/pragma.c @@ -37,6 +37,7 @@ #include /* common */ +#include "addrsize.h" #include "chartype.h" #include "segnames.h" #include "tgttrans.h" @@ -389,7 +390,9 @@ static void SegNamePragma (StrBuf* B, segment_t Seg) /* Handle a pragma that expects a segment name parameter */ { const char* Name; + unsigned char AddrSize = ADDR_SIZE_INVALID; StrBuf S = AUTO_STRBUF_INITIALIZER; + StrBuf A = AUTO_STRBUF_INITIALIZER; int Push = 0; /* Check for the "push" or "pop" keywords */ @@ -430,13 +433,35 @@ static void SegNamePragma (StrBuf* B, segment_t Seg) goto ExitPoint; } - /* Get the string */ + /* Get the name string of the segment */ Name = SB_GetConstBuf (&S); /* Check if the name is valid */ if (ValidSegName (Name)) { - /* Set the new name */ + /* Skip the following comma */ + SB_SkipWhite (B); + if (SB_Peek (B) == ',') { + SB_Skip (B); + SB_SkipWhite (B); + + /* A string argument must follow */ + if (!GetString (B, &A)) { + goto ExitPoint; + } + + /* Get the address size for the segment */ + AddrSize = AddrSizeFromStr (SB_GetConstBuf (&A)); + + /* Set the address size for the segment if valid */ + if (AddrSize != ADDR_SIZE_INVALID) { + SetSegAddrSize (Name, AddrSize); + } else { + Warning ("Invalid address size for segment!"); + } + } + + /* Set the new name and optionally address size */ if (Push) { PushSegName (Seg, Name); } else { @@ -460,6 +485,7 @@ static void SegNamePragma (StrBuf* B, segment_t Seg) ExitPoint: /* Call the string buf destructor */ SB_Done (&S); + SB_Done (&A); } diff --git a/src/cc65/segments.c b/src/cc65/segments.c index 7a9e32eb8..8283b9da5 100644 --- a/src/cc65/segments.c +++ b/src/cc65/segments.c @@ -37,6 +37,7 @@ #include /* common */ +#include "addrsize.h" #include "chartype.h" #include "check.h" #include "coll.h" @@ -61,6 +62,13 @@ +/* Table struct for address sizes of segments */ +typedef struct { + StrBuf Name; + unsigned char AddrSize; +} SegAddrSize_t; + + /* Pointer to the current segment list. Output goes here. */ Segments* CS = 0; @@ -70,6 +78,9 @@ Segments* GS = 0; /* Actual names for the segments */ static StrStack SegmentNames[SEG_COUNT]; +/* Address size for the segments */ +static Collection SegmentAddrSizes; + /* We're using a collection for the stack instead of a linked list. Since ** functions may not be nested (at least in the current implementation), the ** maximum stack depth is 2, so there is not really a need for a better @@ -85,6 +96,85 @@ static Collection SegmentStack = STATIC_COLLECTION_INITIALIZER; +void InitSegAddrSizes (void) +/* Initialize the segment address sizes */ +{ + InitCollection (&SegmentAddrSizes); +} + + + +void DoneSegAddrSizes (void) +/* Free the segment address sizes */ +{ + SegAddrSize_t* A; + int I; + for (I = 0; I < (int)CollCount (&SegmentAddrSizes); ++I) { + A = CollAtUnchecked (&SegmentAddrSizes, I); + SB_Done (&A->Name); + xfree (A); + } + DoneCollection (&SegmentAddrSizes); +} + + + +static SegAddrSize_t* FindSegAddrSize (const char* Name) +/* Find already specified address size for a segment by name. +** Return the found struct or 0 if not found. +*/ +{ + SegAddrSize_t* A; + int I; + for (I = 0; I < (int)CollCount (&SegmentAddrSizes); ++I) { + A = CollAtUnchecked (&SegmentAddrSizes, I); + if (A && strcmp (SB_GetConstBuf (&A->Name), Name) == 0) { + return A; + } + } + return 0; +} + + + +void SetSegAddrSize (const char* Name, unsigned char AddrSize) +/* Set the address size for a segment */ +{ + SegAddrSize_t* A = FindSegAddrSize (Name); + if (!A) { + /* New one */ + A = xmalloc (sizeof (SegAddrSize_t)); + SB_Init (&A->Name); + SB_CopyStr (&A->Name, Name); + SB_Terminate (&A->Name); + CollAppend (&SegmentAddrSizes, A); + } else { + /* Check for mismatching address sizes */ + if (A->AddrSize != AddrSize) { + Warning ("Segment address size changed from last time!"); + } + } + + /* Set the address size anyway */ + A->AddrSize = AddrSize; +} + + + +unsigned char GetSegAddrSize (const char* Name) +/* Get the address size of the given segment. +** Return ADDR_SIZE_INVALID if not found. +*/ +{ + SegAddrSize_t* A = FindSegAddrSize (Name); + if (A) { + return A->AddrSize; + } + return ADDR_SIZE_INVALID; +} + + + void InitSegNames (void) /* Initialize the segment names */ { diff --git a/src/cc65/segments.h b/src/cc65/segments.h index 777073559..91d702df6 100644 --- a/src/cc65/segments.h +++ b/src/cc65/segments.h @@ -103,6 +103,19 @@ extern Segments* GS; /*****************************************************************************/ +void InitSegAddrSizes (void); +/* Initialize the segment address sizes */ + +void DoneSegAddrSizes (void); +/* Free the segment address sizes */ + +void SetSegAddrSize (const char* Name, unsigned char AddrSize); +/* Set the address size for a segment */ + +unsigned char GetSegAddrSize (const char* Name); +/* Get the address size of the given segment. +** Return ADDR_SIZE_INVALID if not found. +*/ void InitSegNames (void); /* Initialize the segment names */