/* */
/* */
/* */
-/* (C) 1998-2000 Ullrich von Bassewitz */
+/* (C) 1998-2002 Ullrich von Bassewitz */
/* Wacholderweg 14 */
/* D-70597 Stuttgart */
/* EMail: uz@musoftware.de */
/* common */
#include "check.h"
#include "bitops.h"
+#include "print.h"
#include "xmalloc.h"
/* ld65 */
static BinDesc* BinFmtDesc = 0;
static O65Desc* O65FmtDesc = 0;
-/* Attributes for the o65 format */
-static unsigned O65Attr = 0;
-#define OA_OS 0x0001
-#define OA_TYPE 0x0002
-#define OA_VERSION 0x0004
-#define OA_OSVERSION 0x0008
-#define OA_TEXT 0x0010
-#define OA_DATA 0x0020
-#define OA_BSS 0x0040
-#define OA_ZP 0x0080
-
/*****************************************************************************/
{
static const IdentTok Attributes [] = {
{ "LOAD", CFGTOK_LOAD },
- { "RUN", CFGTOK_RUN },
+ { "RUN", CFGTOK_RUN },
{ "TYPE", CFGTOK_TYPE },
{ "ALIGN", CFGTOK_ALIGN },
{ "DEFINE", CFGTOK_DEFINE },
- { "OFFSET", CFGTOK_OFFSET },
- { "START", CFGTOK_START },
+ { "OFFSET", CFGTOK_OFFSET },
+ { "START", CFGTOK_START },
};
static const IdentTok Types [] = {
- { "RO", CFGTOK_RO },
- { "RW", CFGTOK_RW },
- { "BSS", CFGTOK_BSS },
- { "ZP", CFGTOK_ZP },
- { "WP", CFGTOK_WPROT },
- { "WPROT", CFGTOK_WPROT },
+ { "RO", CFGTOK_RO },
+ { "RW", CFGTOK_RW },
+ { "BSS", CFGTOK_BSS },
+ { "ZP", CFGTOK_ZP },
+ { "WP", CFGTOK_WPROT },
+ { "WPROT", CFGTOK_WPROT },
};
unsigned Count;
/* Parse the o65 format section */
{
static const IdentTok Attributes [] = {
- { "EXPORT", CFGTOK_EXPORT },
- { "IMPORT", CFGTOK_IMPORT },
- { "TYPE", CFGTOK_TYPE },
- { "OS", CFGTOK_OS },
+ { "EXPORT", CFGTOK_EXPORT },
+ { "IMPORT", CFGTOK_IMPORT },
+ { "TYPE", CFGTOK_TYPE },
+ { "OS", CFGTOK_OS },
+ { "ID", CFGTOK_ID },
+ { "VERSION", CFGTOK_VERSION },
};
static const IdentTok Types [] = {
- { "SMALL", CFGTOK_SMALL },
- { "LARGE", CFGTOK_LARGE },
+ { "SMALL", CFGTOK_SMALL },
+ { "LARGE", CFGTOK_LARGE },
};
static const IdentTok OperatingSystems [] = {
- { "LUNIX", CFGTOK_LUNIX },
- { "OSA65", CFGTOK_OSA65 },
+ { "LUNIX", CFGTOK_LUNIX },
+ { "OSA65", CFGTOK_OSA65 },
+ { "CC65", CFGTOK_CC65 },
};
+ /* Bitmask to remember the attributes we got already */
+ enum {
+ atNone = 0x0000,
+ atOS = 0x0001,
+ atOSVersion = 0x0002,
+ atType = 0x0004,
+ atImport = 0x0008,
+ atExport = 0x0010,
+ atID = 0x0020,
+ atVersion = 0x0040
+ };
+ unsigned AttrFlags = atNone;
+
+ /* Remember the attributes read */
+ unsigned OS = 0; /* Initialize to keep gcc happy */
+ unsigned Version = 0;
+
+ /* Read the attributes */
while (CfgTok == CFGTOK_IDENT) {
/* Map the identifier to a token */
switch (AttrTok) {
case CFGTOK_EXPORT:
+ /* Remember we had this token (maybe more than once) */
+ AttrFlags |= atExport;
/* We expect an identifier */
CfgAssureIdent ();
+ /* Check if the export symbol is also defined as an import. */
+ if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+ CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
+ }
/* Check if we have this symbol defined already. The entry
* routine will check this also, but we get a more verbose
* error message when checking it here.
*/
if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
+ CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
}
/* Insert the symbol into the table */
- O65SetExport (O65FmtDesc, CfgSVal);
+ O65SetExport (O65FmtDesc, CfgSVal);
break;
case CFGTOK_IMPORT:
+ /* Remember we had this token (maybe more than once) */
+ AttrFlags |= atImport;
/* We expect an identifier */
CfgAssureIdent ();
- /* Check if we have this symbol defined already. The entry
- * routine will check this also, but we get a more verbose
- * error message when checking it here.
- */
- if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
- CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
- }
- /* Insert the symbol into the table */
- O65SetImport (O65FmtDesc, CfgSVal);
+ /* Check if the imported symbol is also defined as an export. */
+ if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
+ CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
+ }
+ /* Check if we have this symbol defined already. The entry
+ * routine will check this also, but we get a more verbose
+ * error message when checking it here.
+ */
+ if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
+ CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
+ }
+ /* Insert the symbol into the table */
+ O65SetImport (O65FmtDesc, CfgSVal);
break;
case CFGTOK_TYPE:
/* Cannot have this attribute twice */
- FlagAttr (&O65Attr, OA_TYPE, "TYPE");
+ FlagAttr (&AttrFlags, atType, "TYPE");
/* Get the type of the executable */
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) {
case CFGTOK_SMALL:
- /* Default, nothing to do */
+ O65SetSmallModel (O65FmtDesc);
break;
case CFGTOK_LARGE:
- O65SetLargeModel (O65FmtDesc);
+ O65SetLargeModel (O65FmtDesc);
break;
default:
case CFGTOK_OS:
/* Cannot use this attribute twice */
- FlagAttr (&O65Attr, OA_OS, "OS");
+ FlagAttr (&AttrFlags, atOS, "OS");
/* Get the operating system */
CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
switch (CfgTok) {
-
- case CFGTOK_LUNIX:
- O65SetOS (O65FmtDesc, O65OS_LUNIX);
- break;
-
- case CFGTOK_OSA65:
- O65SetOS (O65FmtDesc, O65OS_OSA65);
- break;
-
- default:
- CfgError ("Unexpected OS token");
+ case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
+ case CFGTOK_OSA65: OS = O65OS_OSA65; break;
+ case CFGTOK_CC65: OS = O65OS_CC65; break;
+ default: CfgError ("Unexpected OS token");
}
break;
+ case CFGTOK_ID:
+ /* Cannot have this attribute twice */
+ FlagAttr (&AttrFlags, atID, "ID");
+ /* We're expecting a number in the 0..$FFFF range*/
+ CfgAssureInt ();
+ CfgRangeCheck (0, 0xFFFF);
+ ModuleId = (unsigned) CfgIVal;
+ break;
+
+ case CFGTOK_VERSION:
+ /* Cannot have this attribute twice */
+ FlagAttr (&AttrFlags, atVersion, "VERSION");
+ /* We're expecting a number in byte range */
+ CfgAssureInt ();
+ CfgRangeCheck (0, 0xFF);
+ Version = (unsigned) CfgIVal;
+ break;
+
default:
FAIL ("Unexpected attribute token");
CfgNextTok ();
CfgOptionalComma ();
}
+
+ /* Check if we have all mandatory attributes */
+ AttrCheck (AttrFlags, atOS, "OS");
+
+ /* Check for attributes that may not be combined */
+ if (OS == O65OS_CC65) {
+ if ((AttrFlags & (atImport | atExport)) != 0) {
+ CfgError ("OS type CC65 may not have imports or exports");
+ }
+ } else {
+ if (AttrFlags & atID) {
+ CfgError ("Operating system does not support the ID attribute");
+ }
+ }
+
+ /* Set the O65 operating system to use */
+ O65SetOS (O65FmtDesc, OS, Version, ModuleId);
}
/* Parse the CONDES feature */
{
static const IdentTok Attributes [] = {
- { "SEGMENT", CFGTOK_SEGMENT },
- { "LABEL", CFGTOK_LABEL },
- { "TYPE", CFGTOK_TYPE },
+ { "SEGMENT", CFGTOK_SEGMENT },
+ { "LABEL", CFGTOK_LABEL },
+ { "COUNT", CFGTOK_COUNT },
+ { "TYPE", CFGTOK_TYPE },
+ { "ORDER", CFGTOK_ORDER },
};
static const IdentTok Types [] = {
{ "DESTRUCTOR", CFGTOK_DESTRUCTOR },
};
+ static const IdentTok Orders [] = {
+ { "DECREASING", CFGTOK_DECREASING },
+ { "INCREASING", CFGTOK_INCREASING },
+ };
+
/* Attribute values. */
char SegName[sizeof (CfgSVal)];
char Label[sizeof (CfgSVal)];
- int Type = -1; /* Initialize to avoid gcc warnings */
+ char Count[sizeof (CfgSVal)];
+ /* Initialize to avoid gcc warnings: */
+ int Type = -1;
+ ConDesOrder Order = cdIncreasing;
/* Bitmask to remember the attributes we got already */
enum {
atNone = 0x0000,
atSegName = 0x0001,
atLabel = 0x0002,
- atType = 0x0004
+ atCount = 0x0004,
+ atType = 0x0008,
+ atOrder = 0x0010
};
unsigned AttrFlags = atNone;
strcpy (Label, CfgSVal);
break;
+ case CFGTOK_COUNT:
+ /* Don't allow this twice */
+ FlagAttr (&AttrFlags, atCount, "COUNT");
+ /* We expect an identifier */
+ CfgAssureIdent ();
+ /* Remember the value for later */
+ strcpy (Count, CfgSVal);
+ break;
case CFGTOK_TYPE:
/* Don't allow this twice */
}
break;
+ case CFGTOK_ORDER:
+ /* Don't allow this twice */
+ FlagAttr (&AttrFlags, atOrder, "ORDER");
+ CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
+ switch (CfgTok) {
+ case CFGTOK_DECREASING: Order = cdDecreasing; break;
+ case CFGTOK_INCREASING: Order = cdIncreasing; break;
+ default: FAIL ("Unexpected order token");
+ }
+ break;
+
default:
FAIL ("Unexpected attribute token");
/* Define the attributes */
ConDesSetSegName (Type, SegName);
ConDesSetLabel (Type, Label);
+ if (AttrFlags & atCount) {
+ ConDesSetCountSym (Type, Count);
+ }
+ if (AttrFlags & atOrder) {
+ ConDesSetOrder (Type, Order);
+ }
}
+static void ParseSymbols (void)
+/* Parse a symbols section */
+{
+ while (CfgTok == CFGTOK_IDENT) {
+
+ long Val;
+
+ /* Remember the name */
+ char Name [sizeof (CfgSVal)];
+ strcpy (Name, CfgSVal);
+ CfgNextTok ();
+
+ /* Allow an optional assignment */
+ CfgOptionalAssign ();
+
+ /* Make sure the next token is an integer, read and skip it */
+ CfgAssureInt ();
+ Val = CfgIVal;
+ CfgNextTok ();
+
+ /* Generate an export with the given value */
+ CreateConstExport (Name, Val);
+
+ /* Skip the semicolon */
+ CfgConsumeSemi ();
+ }
+}
+
+
+
static void ParseConfig (void)
/* Parse the config file */
{
{ "SEGMENTS", CFGTOK_SEGMENTS },
{ "FORMATS", CFGTOK_FORMATS },
{ "FEATURES", CFGTOK_FEATURES },
+ { "SYMBOLS", CFGTOK_SYMBOLS },
};
cfgtok_t BlockTok;
ParseFeatures ();
break;
+ case CFGTOK_SYMBOLS:
+ ParseSymbols ();
+ break;
+
default:
FAIL ("Unexpected block token");
/* Walk through the files list */
File* F = FileList;
while (F) {
- /* We don't need to look at files with no memory areas */
- if (F->MemList) {
+ /* We don't need to look at files with no memory areas */
+ if (F->MemList) {
- /* Is there an output file? */
- if (strlen (F->Name) > 0) {
+ /* Is there an output file? */
+ if (strlen (F->Name) > 0) {
- /* Assign a proper binary format */
- if (F->Format == BINFMT_DEFAULT) {
- F->Format = DefaultBinFmt;
+ /* Assign a proper binary format */
+ if (F->Format == BINFMT_DEFAULT) {
+ F->Format = DefaultBinFmt;
}
/* Call the apropriate routine for the binary format */
- switch (F->Format) {
+ switch (F->Format) {
- case BINFMT_BINARY:
- BinWriteTarget (BinFmtDesc, F);
- break;
+ case BINFMT_BINARY:
+ BinWriteTarget (BinFmtDesc, F);
+ break;
- case BINFMT_O65:
- O65WriteTarget (O65FmtDesc, F);
- break;
+ case BINFMT_O65:
+ O65WriteTarget (O65FmtDesc, F);
+ break;
- default:
- Internal ("Invalid binary format: %u", F->Format);
+ default:
+ Internal ("Invalid binary format: %u", F->Format);
- }
+ }
+
+ } else {
+
+ /* No output file. Walk through the list and mark all segments
+ * loading into these memory areas in this file as dumped.
+ */
+ M = F->MemList;
+ while (M) {
+
+ MemListNode* N;
+
+ /* Debugging */
+ Print (stdout, 2, "Skipping `%s'...\n", M->Name);
+
+ /* Walk throught the segments */
+ N = M->SegList;
+ while (N) {
+ if (N->Seg->Load == M) {
+ /* Load area - mark the segment as dumped */
+ N->Seg->Seg->Dumped = 1;
+ }
- } else {
-
- /* No output file. Walk through the list and mark all segments
- * assigned to the memory areas in this file as dumped.
- */
- M = F->MemList;
- while (M) {
- /* Walk throught the segments */
- MemListNode* N = M->SegList;
- while (N) {
- /* Mark the segment as dumped */
- N->Seg->Seg->Dumped = 1;
-
- /* Next segment node */
- N = N->Next;
+ /* Next segment node */
+ N = N->Next;
}
/* Next memory area */
M = M->FNext;