/* */
/* */
/* */
-/* (C) 2000-2005 Ullrich von Bassewitz */
-/* Römerstrasse 52 */
+/* (C) 2000-2007 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
/* D-70794 Filderstadt */
/* EMail: uz@cc65.org */
/* */
#include "labels.h"
#include "opctable.h"
#include "scanner.h"
+#include "segment.h"
+static void AsmIncSection (void)
+/* Parse a asminc section */
+{
+ static const IdentTok LabelDefs[] = {
+ { "COMMENTSTART", INFOTOK_COMMENTSTART },
+ { "FILE", INFOTOK_FILE },
+ { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN },
+ };
+
+ /* Locals - initialize to avoid gcc warnings */
+ char* Name = 0;
+ int CommentStart = EOF;
+ int IgnoreUnknown = -1;
+
+ /* Skip the token */
+ InfoNextTok ();
+
+ /* Expect the opening curly brace */
+ InfoConsumeLCurly ();
+
+ /* Look for section tokens */
+ while (InfoTok != INFOTOK_RCURLY) {
+
+ /* Convert to special token */
+ InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
+
+ /* Look at the token */
+ switch (InfoTok) {
+
+ case INFOTOK_COMMENTSTART:
+ InfoNextTok ();
+ if (CommentStart != EOF) {
+ InfoError ("Commentstart already given");
+ }
+ InfoAssureChar ();
+ CommentStart = (char) InfoIVal;
+ InfoNextTok ();
+ break;
+
+ case INFOTOK_FILE:
+ InfoNextTok ();
+ if (Name) {
+ InfoError ("File name already given");
+ }
+ InfoAssureStr ();
+ if (InfoSVal[0] == '\0') {
+ InfoError ("File name may not be empty");
+ }
+ Name = xstrdup (InfoSVal);
+ InfoNextTok ();
+ break;
+
+ case INFOTOK_IGNOREUNKNOWN:
+ InfoNextTok ();
+ if (IgnoreUnknown != -1) {
+ InfoError ("Ignoreunknown already specified");
+ }
+ InfoBoolToken ();
+ IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
+ InfoNextTok ();
+ break;
+
+ default:
+ Internal ("Unexpected token: %u", InfoTok);
+ }
+
+ /* Directive is followed by a semicolon */
+ InfoConsumeSemi ();
+ }
+
+ /* Check for the necessary data and assume defaults */
+ if (Name == 0) {
+ InfoError ("File name is missing");
+ }
+ if (CommentStart == EOF) {
+ CommentStart = ';';
+ }
+ if (IgnoreUnknown == -1) {
+ IgnoreUnknown = 0;
+ }
+
+ /* Open the file and read the symbol definitions */
+ AsmInc (Name, CommentStart, IgnoreUnknown);
+
+ /* Delete the dynamically allocated memory for Name */
+ xfree (Name);
+
+ /* Consume the closing brace */
+ InfoConsumeRCurly ();
+}
+
+
+
static void GlobalSection (void)
/* Parse a global section */
{
+static void LabelSection (void)
+/* Parse a label section */
+{
+ static const IdentTok LabelDefs[] = {
+ { "COMMENT", INFOTOK_COMMENT },
+ { "ADDR", INFOTOK_ADDR },
+ { "NAME", INFOTOK_NAME },
+ { "SIZE", INFOTOK_SIZE },
+ };
+
+ /* Locals - initialize to avoid gcc warnings */
+ char* Name = 0;
+ char* Comment = 0;
+ long Value = -1;
+ long Size = -1;
+
+ /* Skip the token */
+ InfoNextTok ();
+
+ /* Expect the opening curly brace */
+ InfoConsumeLCurly ();
+
+ /* Look for section tokens */
+ while (InfoTok != INFOTOK_RCURLY) {
+
+ /* Convert to special token */
+ InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label attribute");
+
+ /* Look at the token */
+ switch (InfoTok) {
+
+ case INFOTOK_ADDR:
+ InfoNextTok ();
+ if (Value >= 0) {
+ InfoError ("Value already given");
+ }
+ InfoAssureInt ();
+ InfoRangeCheck (0, 0xFFFF);
+ Value = InfoIVal;
+ InfoNextTok ();
+ break;
+
+ case INFOTOK_COMMENT:
+ InfoNextTok ();
+ if (Comment) {
+ InfoError ("Comment already given");
+ }
+ InfoAssureStr ();
+ if (InfoSVal[0] == '\0') {
+ InfoError ("Comment may not be empty");
+ }
+ Comment = xstrdup (InfoSVal);
+ InfoNextTok ();
+ break;
+
+ case INFOTOK_NAME:
+ InfoNextTok ();
+ if (Name) {
+ InfoError ("Name already given");
+ }
+ InfoAssureStr ();
+ Name = xstrdup (InfoSVal);
+ InfoNextTok ();
+ break;
+
+ case INFOTOK_SIZE:
+ InfoNextTok ();
+ if (Size >= 0) {
+ InfoError ("Size already given");
+ }
+ InfoAssureInt ();
+ InfoRangeCheck (1, 0x10000);
+ Size = InfoIVal;
+ InfoNextTok ();
+ break;
+
+ default:
+ Internal ("Unexpected token: %u", InfoTok);
+ }
+
+ /* Directive is followed by a semicolon */
+ InfoConsumeSemi ();
+ }
+
+ /* Did we get the necessary data */
+ if (Name == 0) {
+ InfoError ("Label name is missing");
+ }
+ if (Name[0] == '\0' && Size > 1) {
+ InfoError ("Unnamed labels must not have a size > 1");
+ }
+ if (Value < 0) {
+ InfoError ("Label value is missing");
+ }
+ if (Size < 0) {
+ /* Use default */
+ Size = 1;
+ }
+ if (Value + Size > 0x10000) {
+ InfoError ("Invalid size (address out of range)");
+ }
+ if (HaveLabel ((unsigned) Value)) {
+ InfoError ("Label for address $%04lX already defined", Value);
+ }
+
+ /* Define the label(s) */
+ if (Name[0] == '\0') {
+ /* Size has already beed checked */
+ AddUnnamedLabel (Value);
+ } else {
+ AddExtLabelRange ((unsigned) Value, Name, Size);
+ }
+
+ /* Define the comment */
+ if (Comment) {
+ SetComment (Value, Comment);
+ }
+
+ /* Delete the dynamically allocated memory for Name and Comment */
+ xfree (Name);
+ xfree (Comment);
+
+ /* Consume the closing brace */
+ InfoConsumeRCurly ();
+}
+
+
+
static void RangeSection (void)
/* Parse a range section */
{
while (InfoTok != INFOTOK_RCURLY) {
/* Convert to special token */
- InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range directive");
+ InfoSpecialToken (RangeDefs, ENTRY_COUNT (RangeDefs), "Range attribute");
/* Look at the token */
switch (InfoTok) {
-static void LabelSection (void)
-/* Parse a label section */
+static void SegmentSection (void)
+/* Parse a segment section */
{
static const IdentTok LabelDefs[] = {
- { "COMMENT", INFOTOK_COMMENT },
- { "ADDR", INFOTOK_ADDR },
+ { "END", INFOTOK_END },
{ "NAME", INFOTOK_NAME },
- { "SIZE", INFOTOK_SIZE },
+ { "START", INFOTOK_START },
};
/* Locals - initialize to avoid gcc warnings */
- char* Name = 0;
- char* Comment = 0;
- long Value = -1;
- long Size = -1;
+ long End = -1;
+ long Start = -1;
+ char* Name = 0;
/* Skip the token */
InfoNextTok ();
/* Look for section tokens */
while (InfoTok != INFOTOK_RCURLY) {
- /* Convert to special token */
- InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Label directive");
+ /* Convert to special token */
+ InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Segment attribute");
- /* Look at the token */
- switch (InfoTok) {
+ /* Look at the token */
+ switch (InfoTok) {
- case INFOTOK_ADDR:
- InfoNextTok ();
- if (Value >= 0) {
- InfoError ("Value already given");
- }
+ case INFOTOK_END:
+ InfoNextTok ();
+ if (End >= 0) {
+ InfoError ("Value already given");
+ }
InfoAssureInt ();
- InfoRangeCheck (0, 0xFFFF);
- Value = InfoIVal;
- InfoNextTok ();
- break;
-
- case INFOTOK_COMMENT:
- InfoNextTok ();
- if (Comment) {
- InfoError ("Comment already given");
- }
- InfoAssureStr ();
- if (InfoSVal[0] == '\0') {
- InfoError ("Comment may not be empty");
- }
- Comment = xstrdup (InfoSVal);
- InfoNextTok ();
+ InfoRangeCheck (0, 0xFFFF);
+ End = InfoIVal;
+ InfoNextTok ();
break;
case INFOTOK_NAME:
InfoNextTok ();
break;
- case INFOTOK_SIZE:
- InfoNextTok ();
- if (Size >= 0) {
- InfoError ("Size already given");
- }
- InfoAssureInt ();
- InfoRangeCheck (1, 0x10000);
- Size = InfoIVal;
- InfoNextTok ();
- break;
+ case INFOTOK_START:
+ InfoNextTok ();
+ if (Start >= 0) {
+ InfoError ("Value already given");
+ }
+ InfoAssureInt ();
+ InfoRangeCheck (0, 0xFFFF);
+ Start = InfoIVal;
+ InfoNextTok ();
+ break;
default:
Internal ("Unexpected token: %u", InfoTok);
InfoConsumeSemi ();
}
- /* Did we get the necessary data */
- if (Name == 0) {
- InfoError ("Label name is missing");
- }
- if (Name[0] == '\0' && Size > 1) {
- InfoError ("Unnamed labels must not have a size > 1");
- }
- if (Value < 0) {
- InfoError ("Label value is missing");
- }
- if (Size < 0) {
- /* Use default */
- Size = 1;
+ /* Did we get the necessary data, and is it correct? */
+ if (Name == 0 || Name[0] == '\0') {
+ InfoError ("Segment name is missing");
}
- if (Value + Size > 0x10000) {
- InfoError ("Invalid size (address out of range)");
+ if (End < 0) {
+ InfoError ("End address is missing");
}
- if (HaveLabel ((unsigned) Value)) {
- InfoError ("Label for address $%04lX already defined", Value);
+ if (Start < 0) {
+ InfoError ("Start address is missing");
}
-
- /* Define the label(s) */
- if (Name[0] == '\0') {
- /* Size has already beed checked */
- AddUnnamedLabel (Value);
- } else {
- AddExtLabelRange ((unsigned) Value, Name, Size);
+ if (Start == End) {
+ InfoError ("Segment is empty");
}
-
- /* Define the comment */
- if (Comment) {
- SetComment (Value, Comment);
- }
-
- /* Delete the dynamically allocated memory for Name and Comment */
- xfree (Name);
- xfree (Comment);
-
- /* Consume the closing brace */
- InfoConsumeRCurly ();
-}
-
-
-
-static void AsmIncSection (void)
-/* Parse a asminc section */
-{
- static const IdentTok LabelDefs[] = {
- { "COMMENTSTART", INFOTOK_COMMENTSTART },
- { "FILE", INFOTOK_FILE },
- { "IGNOREUNKNOWN", INFOTOK_IGNOREUNKNOWN },
- };
-
- /* Locals - initialize to avoid gcc warnings */
- char* Name = 0;
- int CommentStart = EOF;
- int IgnoreUnknown = -1;
-
- /* Skip the token */
- InfoNextTok ();
-
- /* Expect the opening curly brace */
- InfoConsumeLCurly ();
-
- /* Look for section tokens */
- while (InfoTok != INFOTOK_RCURLY) {
-
- /* Convert to special token */
- InfoSpecialToken (LabelDefs, ENTRY_COUNT (LabelDefs), "Asminc directive");
-
- /* Look at the token */
- switch (InfoTok) {
-
- case INFOTOK_COMMENTSTART:
- InfoNextTok ();
- if (CommentStart != EOF) {
- InfoError ("Commentstart already given");
- }
- InfoAssureChar ();
- CommentStart = (char) InfoIVal;
- InfoNextTok ();
- break;
-
- case INFOTOK_FILE:
- InfoNextTok ();
- if (Name) {
- InfoError ("File name already given");
- }
- InfoAssureStr ();
- if (InfoSVal[0] == '\0') {
- InfoError ("File name may not be empty");
- }
- Name = xstrdup (InfoSVal);
- InfoNextTok ();
- break;
-
- case INFOTOK_IGNOREUNKNOWN:
- InfoNextTok ();
- if (IgnoreUnknown != -1) {
- InfoError ("Ignoreunknown already specified");
- }
- InfoBoolToken ();
- IgnoreUnknown = (InfoTok != INFOTOK_FALSE);
- InfoNextTok ();
- break;
-
- default:
- Internal ("Unexpected token: %u", InfoTok);
- }
-
- /* Directive is followed by a semicolon */
- InfoConsumeSemi ();
+ if (Start > End) {
+ InfoError ("Start address of segment is greater than end address");
}
- /* Check for the necessary data and assume defaults */
- if (Name == 0) {
- InfoError ("File name is missing");
- }
- if (CommentStart == EOF) {
- CommentStart = ';';
- }
- if (IgnoreUnknown == -1) {
- IgnoreUnknown = 0;
+ /* Check that segments do not overlap */
+ if (SegmentDefined ((unsigned) Start, (unsigned) End)) {
+ InfoError ("Segments cannot overlap");
}
- /* Open the file and read the symbol definitions */
- AsmInc (Name, CommentStart, IgnoreUnknown);
+ /* Remember the segment data */
+ AddAbsSegment ((unsigned) Start, (unsigned) End, Name);
/* Delete the dynamically allocated memory for Name */
xfree (Name);
/* Parse the config file */
{
static const IdentTok Globals[] = {
+ { "ASMINC", INFOTOK_ASMINC },
{ "GLOBAL", INFOTOK_GLOBAL },
- { "RANGE", INFOTOK_RANGE },
{ "LABEL", INFOTOK_LABEL },
- { "ASMINC", INFOTOK_ASMINC },
+ { "RANGE", INFOTOK_RANGE },
+ { "SEGMENT", INFOTOK_SEGMENT },
};
while (InfoTok != INFOTOK_EOF) {
/* Check the token */
switch (InfoTok) {
+ case INFOTOK_ASMINC:
+ AsmIncSection ();
+ break;
+
case INFOTOK_GLOBAL:
GlobalSection ();
break;
- case INFOTOK_RANGE:
- RangeSection ();
- break;
-
case INFOTOK_LABEL:
LabelSection ();
break;
- case INFOTOK_ASMINC:
- AsmIncSection ();
+ case INFOTOK_RANGE:
+ RangeSection ();
+ break;
+
+ case INFOTOK_SEGMENT:
+ SegmentSection ();
break;
default:
--- /dev/null
+/*****************************************************************************/
+/* */
+/* segment.c */
+/* */
+/* Segment handling for da65 */
+/* */
+/* */
+/* */
+/* (C) 2007 Ullrich von Bassewitz */
+/* Roemerstrasse 52 */
+/* D-70794 Filderstadt */
+/* EMail: uz@cc65.org */
+/* */
+/* */
+/* This software is provided 'as-is', without any expressed or implied */
+/* warranty. In no event will the authors be held liable for any damages */
+/* arising from the use of this software. */
+/* */
+/* Permission is granted to anyone to use this software for any purpose, */
+/* including commercial applications, and to alter it and redistribute it */
+/* freely, subject to the following restrictions: */
+/* */
+/* 1. The origin of this software must not be misrepresented; you must not */
+/* claim that you wrote the original software. If you use this software */
+/* in a product, an acknowledgment in the product documentation would be */
+/* appreciated but is not required. */
+/* 2. Altered source versions must be plainly marked as such, and must not */
+/* be misrepresented as being the original software. */
+/* 3. This notice may not be removed or altered from any source */
+/* distribution. */
+/* */
+/*****************************************************************************/
+
+
+
+#include <string.h>
+
+/* common */
+#include "addrsize.h"
+#include "xmalloc.h"
+
+/* da65 */
+#include "attrtab.h"
+#include "segment.h"
+
+
+
+/*****************************************************************************/
+/* Data */
+/*****************************************************************************/
+
+
+
+/* Hash definitions */
+#define HASH_SIZE 64 /* Must be power of two */
+#define HASH_MASK (HASH_SIZE-1)
+
+/* Segment definition */
+typedef struct Segment Segment;
+struct Segment {
+ Segment* NextStart; /* Pointer to next segment */
+ Segment* NextEnd; /* Pointer to next segment */
+ unsigned long Start;
+ unsigned long End;
+ unsigned AddrSize;
+ char Name[1]; /* Name, dynamically allocated */
+};
+
+/* Tables containing the segments. A segment is inserted using it's hash
+ * value. Collision is done by single linked lists.
+ */
+static Segment* StartTab[HASH_SIZE]; /* Table containing segment starts */
+static Segment* EndTab[HASH_SIZE]; /* Table containing segment ends */
+
+
+
+/*****************************************************************************/
+/* Code */
+/*****************************************************************************/
+
+
+
+void AddAbsSegment (unsigned Start, unsigned End, const char* Name)
+/* Add an absolute segment to the segment table */
+{
+ /* Get the length of the name */
+ unsigned Len = strlen (Name);
+
+ /* Create a new segment */
+ Segment* S = xmalloc (sizeof (Segment) + Len);
+
+ /* Fill in the data */
+ S->Start = Start;
+ S->End = End;
+ S->AddrSize = ADDR_SIZE_ABS;
+ memcpy (S->Name, Name, Len + 1);
+
+ /* Insert the segment into the hash tables */
+ S->NextStart = StartTab[Start & HASH_MASK];
+ StartTab[Start & HASH_MASK] = S;
+ S->NextEnd = EndTab[End & HASH_MASK];
+ EndTab[End & HASH_MASK] = S;
+
+ /* Mark the addresses within the segment */
+ MarkRange (Start, End, atSegment);
+}
+
+
+