#include "objdata.h"
#include "scanner.h"
#include "spool.h"
+#include "xex.h"
/* Descriptor holding information about the binary formats */
static BinDesc* BinFmtDesc = 0;
static O65Desc* O65FmtDesc = 0;
+static XexDesc* XexFmtDesc = 0;
{
MemoryArea* M = CfgFindMemory (Name);
if (M == 0) {
- CfgError (&CfgErrorPos, "Invalid memory area `%s'", GetString (Name));
+ CfgError (&CfgErrorPos, "Invalid memory area '%s'", GetString (Name));
}
return M;
}
MemoryArea* M = CfgFindMemory (Name);
if (M) {
CfgError (&CfgErrorPos,
- "Memory area `%s' defined twice",
+ "Memory area '%s' defined twice",
GetString (Name));
}
/* Check for duplicate names */
SegDesc* S = CfgFindSegDesc (Name);
if (S) {
- CfgError (&CfgErrorPos, "Segment `%s' defined twice", GetString (Name));
+ CfgError (&CfgErrorPos, "Segment '%s' defined twice", GetString (Name));
}
/* Allocate memory */
{ "FORMAT", CFGTOK_FORMAT },
};
static const IdentTok Formats [] = {
+ { "ATARI", CFGTOK_ATARIEXE },
{ "O65", CFGTOK_O65 },
{ "BIN", CFGTOK_BIN },
{ "BINARY", CFGTOK_BIN },
F = FindFile (GetStrBufId (&CfgSVal));
if (F == 0) {
CfgError (&CfgErrorPos,
- "File `%s' not found in MEMORY section",
+ "File '%s' not found in MEMORY section",
SB_GetConstBuf (&CfgSVal));
}
F->Format = BINFMT_O65;
break;
+ case CFGTOK_ATARIEXE:
+ F->Format = BINFMT_ATARIEXE;
+ break;
+
default:
Error ("Unexpected format token");
}
{ "RW", CFGTOK_RW },
{ "BSS", CFGTOK_BSS },
{ "ZP", CFGTOK_ZP },
+ { "OVERWRITE", CFGTOK_OVERWRITE },
};
unsigned Count;
FlagAttr (&S->Attr, SA_TYPE, "TYPE");
CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
switch (CfgTok) {
- case CFGTOK_RO: S->Flags |= SF_RO; break;
- 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);
+ case CFGTOK_RO: S->Flags |= SF_RO; break;
+ case CFGTOK_RW: /* Default */ break;
+ case CFGTOK_BSS: S->Flags |= SF_BSS; break;
+ case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
+ case CFGTOK_OVERWRITE: S->Flags |= (SF_OVERWRITE | SF_RO); break;
+ default: Internal ("Unexpected token: %d", CfgTok);
}
CfgNextTok ();
break;
*/
if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
CfgWarning (&CfgErrorPos,
- "Segment with type `bss' has both LOAD and RUN "
+ "Segment with type 'bss' has both LOAD and RUN "
"memory areas assigned");
}
if ((S->Flags & SF_RO) == 0) {
if (S->Run->Flags & MF_RO) {
CfgError (&CfgErrorPos,
- "Cannot put r/w segment `%s' in r/o memory area `%s'",
+ "Cannot put r/w segment '%s' in r/o memory area '%s'",
GetString (S->Name), GetString (S->Run->Name));
}
}
+static void ParseXex (void)
+/* Parse the o65 format section */
+{
+ static const IdentTok Attributes [] = {
+ { "RUNAD", CFGTOK_RUNAD },
+ { "INITAD", CFGTOK_INITAD },
+ };
+
+ /* Remember the attributes read */
+ /* Bitmask to remember the attributes we got already */
+ enum {
+ atNone = 0x0000,
+ atRunAd = 0x0001,
+ };
+ unsigned AttrFlags = atNone;
+ Import *RunAd = 0;
+ Import *InitAd;
+ MemoryArea *InitMem;
+
+ /* Read the attributes */
+ while (CfgTok == CFGTOK_IDENT) {
+
+ /* Map the identifier to a token */
+ cfgtok_t AttrTok;
+ CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
+ AttrTok = CfgTok;
+
+ /* An optional assignment follows */
+ CfgNextTok ();
+ CfgOptionalAssign ();
+
+ /* Check which attribute was given */
+ switch (AttrTok) {
+
+ case CFGTOK_RUNAD:
+ /* Cannot have this attribute twice */
+ FlagAttr (&AttrFlags, atRunAd, "RUNAD");
+ /* We expect an identifier */
+ CfgAssureIdent ();
+ /* Generate an import for the symbol */
+ RunAd = InsertImport (GenImport (GetStrBufId (&CfgSVal), ADDR_SIZE_ABS));
+ /* Remember the file position */
+ CollAppend (&RunAd->RefLines, GenLineInfo (&CfgErrorPos));
+ /* Eat the identifier token */
+ CfgNextTok ();
+ break;
+
+ case CFGTOK_INITAD:
+ /* We expect a memory area followed by a colon and an identifier */
+ CfgAssureIdent ();
+ InitMem = CfgGetMemory (GetStrBufId (&CfgSVal));
+ CfgNextTok ();
+ CfgConsumeColon ();
+ CfgAssureIdent ();
+ /* Generate an import for the symbol */
+ InitAd = InsertImport (GenImport (GetStrBufId (&CfgSVal), ADDR_SIZE_ABS));
+ /* Remember the file position */
+ CollAppend (&InitAd->RefLines, GenLineInfo (&CfgErrorPos));
+ /* Eat the identifier token */
+ CfgNextTok ();
+ /* Add to XEX */
+ if (XexAddInitAd (XexFmtDesc, InitMem, InitAd))
+ CfgError (&CfgErrorPos, "INITAD already given for memory area");
+ break;
+
+ default:
+ FAIL ("Unexpected attribute token");
+
+ }
+
+ /* Skip an optional comma */
+ CfgOptionalComma ();
+ }
+
+ /* Set the RUNAD import if we have one */
+ if ( RunAd )
+ XexSetRunAd (XexFmtDesc, RunAd);
+}
+
+
+
static void ParseFormats (void)
/* Parse a target format section */
{
{ "O65", CFGTOK_O65 },
{ "BIN", CFGTOK_BIN },
{ "BINARY", CFGTOK_BIN },
+ { "ATARI", CFGTOK_ATARIEXE },
};
while (CfgTok == CFGTOK_IDENT) {
ParseO65 ();
break;
+ case CFGTOK_ATARIEXE:
+ ParseXex ();
+ break;
+
case CFGTOK_BIN:
/* No attribibutes available */
break;
CfgNextTok ();
/* Expected a curly brace */
- CfgConsume (CFGTOK_LCURLY, "`{' expected");
+ CfgConsume (CFGTOK_LCURLY, "'{' expected");
/* Read the block */
switch (BlockTok) {
}
/* Skip closing brace */
- CfgConsume (CFGTOK_RCURLY, "`}' expected");
+ CfgConsume (CFGTOK_RCURLY, "'}' expected");
} while (CfgTok != CFGTOK_EOF);
}
/* Create the descriptors for the binary formats */
BinFmtDesc = NewBinDesc ();
O65FmtDesc = NewO65Desc ();
+ XexFmtDesc = NewXexDesc ();
/* If we have a config name given, open the file, otherwise we will read
** from a buffer.
*/
if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
CfgWarning (GetSourcePos (S->LI),
- "Segment `%s' with type `bss' contains initialized data",
+ "Segment '%s' with type 'bss' contains initialized data",
GetString (S->Name));
}
/* Print a warning if the segment is not optional */
if ((S->Flags & SF_OPTIONAL) == 0) {
CfgWarning (&CfgErrorPos,
- "Segment `%s' does not exist",
+ "Segment '%s' does not exist",
GetString (S->Name));
}
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
GetSourcePos (Sym->LI),
- "Exported o65 symbol `%s' cannot also be an o65 import",
+ "Exported o65 symbol '%s' cannot also be an o65 import",
GetString (Sym->Name)
);
}
if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
GetSourcePos (Sym->LI),
- "Duplicate exported o65 symbol: `%s'",
+ "Duplicate exported o65 symbol: '%s'",
GetString (Sym->Name)
);
}
if (O65GetExport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
GetSourcePos (Sym->LI),
- "Imported o65 symbol `%s' cannot also be an o65 export",
+ "Imported o65 symbol '%s' cannot also be an o65 export",
GetString (Sym->Name)
);
}
if (O65GetImport (O65FmtDesc, Sym->Name) != 0) {
CfgError (
GetSourcePos (Sym->LI),
- "Duplicate imported o65 symbol: `%s'",
+ "Duplicate imported o65 symbol: '%s'",
GetString (Sym->Name)
);
}
for (I = 0; I < CollCount (&MemoryAreas); ++I) {
unsigned J;
unsigned long Addr;
+ unsigned Overwrites = 0;
/* Get the next memory area */
MemoryArea* M = CollAtUnchecked (&MemoryAreas, I);
*/
if (!IsConstExpr (M->StartExpr)) {
CfgError (GetSourcePos (M->LI),
- "Start address of memory area `%s' is not constant",
+ "Start address of memory area '%s' is not constant",
GetString (M->Name));
}
Addr = M->Start = GetExprVal (M->StartExpr);
/* Resolve the size expression */
if (!IsConstExpr (M->SizeExpr)) {
CfgError (GetSourcePos (M->LI),
- "Size of memory area `%s' is not constant",
+ "Size of memory area '%s' is not constant",
GetString (M->Name));
}
M->Size = GetExprVal (M->SizeExpr);
/* Remember the start address before handling this segment */
unsigned long StartAddr = Addr;
+ /* Take note of "overwrite" segments and make sure there are no
+ ** other segment types following them in current memory region.
+ */
+ if (S->Flags & SF_OVERWRITE) {
+ if (S->Flags & (SF_OFFSET | SF_START)) {
+ ++Overwrites;
+ } else {
+ CfgError (GetSourcePos (M->LI),
+ "Segment '%s' of type 'overwrite' requires either"
+ " 'Start' or 'Offset' attribute to be specified",
+ GetString (S->Name));
+ }
+ } else {
+ if (Overwrites > 0) {
+ CfgError (GetSourcePos (M->LI),
+ "Segment '%s' is preceded by at least one segment"
+ " of type 'overwrite'",
+ GetString (S->Name));
+ }
+ }
+
/* Some actions depend on whether this is the load or run memory
** area.
*/
*/
/* Check if the alignment for the segment from the linker
- ** config. is a multiple for that of the segment.
+ ** config is a multiple for that of the segment.
+ ** If START or OFFSET is provided instead of ALIGN, check
+ ** if its address fits alignment requirements.
*/
- if ((S->RunAlignment % S->Seg->Alignment) != 0) {
+ unsigned long AlignedBy = (S->Flags & SF_START) ? S->Addr
+ : (S->Flags & SF_OFFSET) ? (S->Addr + M->Start)
+ : S->RunAlignment;
+ if ((AlignedBy % S->Seg->Alignment) != 0) {
/* Segment requires another alignment than configured
** in the linker.
*/
CfgWarning (GetSourcePos (S->LI),
- "Segment `%s' isn't aligned properly; the"
+ "Segment '%s' isn't aligned properly; the"
" resulting executable might not be functional.",
GetString (S->Name));
}
*/
if (M->FillLevel == 0 && NewAddr > Addr) {
CfgWarning (GetSourcePos (S->LI),
- "The first segment in memory area `%s' "
+ "The first segment in memory area '%s' "
"needs fill bytes for alignment.",
GetString (M->Name));
}
/* An offset was given, no address, make an address */
NewAddr += M->Start;
}
- if (NewAddr < Addr) {
- /* Offset already too large */
- ++Overflows;
- if (S->Flags & SF_OFFSET) {
- CfgWarning (GetSourcePos (S->LI),
- "Segment `%s' offset is too small in `%s' by %lu byte%c",
- GetString (S->Name), GetString (M->Name),
- Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+
+ if (S->Flags & SF_OVERWRITE) {
+ if (NewAddr < M->Start) {
+ CfgError (GetSourcePos (S->LI),
+ "Segment '%s' begins before memory area '%s'",
+ GetString (S->Name), GetString (M->Name));
} else {
- CfgWarning (GetSourcePos (S->LI),
- "Segment `%s' start address is too low in `%s' by %lu byte%c",
- GetString (S->Name), GetString (M->Name),
- Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+ Addr = NewAddr;
}
} else {
- Addr = NewAddr;
+ if (NewAddr < Addr) {
+ /* Offset already too large */
+ ++Overflows;
+ if (S->Flags & SF_OFFSET) {
+ CfgWarning (GetSourcePos (S->LI),
+ "Segment '%s' offset is too small in '%s' by %lu byte%c",
+ GetString (S->Name), GetString (M->Name),
+ Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+ } else {
+ CfgWarning (GetSourcePos (S->LI),
+ "Segment '%s' start address is too low in '%s' by %lu byte%c",
+ GetString (S->Name), GetString (M->Name),
+ Addr - NewAddr, (Addr - NewAddr == 1) ? ' ' : 's');
+ }
+ } else {
+ Addr = NewAddr;
+ }
}
}
++Overflows;
M->Flags |= MF_OVERFLOW;
CfgWarning (GetSourcePos (M->LI),
- "Segment `%s' overflows memory area `%s' by %lu byte%c",
+ "Segment '%s' overflows memory area '%s' by %lu byte%c",
GetString (S->Name), GetString (M->Name),
M->FillLevel - M->Size, (M->FillLevel - M->Size == 1) ? ' ' : 's');
}
O65WriteTarget (O65FmtDesc, F);
break;
+ case BINFMT_ATARIEXE:
+ XexWriteTarget (XexFmtDesc, F);
+ break;
+
default:
Internal ("Invalid binary format: %u", F->Format);
MemoryArea* M = CollAtUnchecked (&F->MemoryAreas, J);
/* Debugging */
- Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
+ Print (stdout, 2, "Skipping '%s'...\n", GetString (M->Name));
/* Walk throught the segments */
for (K = 0; K < CollCount (&M->SegList); ++K) {