1 /*****************************************************************************/
5 /* Target configuration file for the ld65 linker */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
15 /* This software is provided 'as-is', without any expressed or implied */
16 /* warranty. In no event will the authors be held liable for any damages */
17 /* arising from the use of this software. */
19 /* Permission is granted to anyone to use this software for any purpose, */
20 /* including commercial applications, and to alter it and redistribute it */
21 /* freely, subject to the following restrictions: */
23 /* 1. The origin of this software must not be misrepresented; you must not */
24 /* claim that you wrote the original software. If you use this software */
25 /* in a product, an acknowledgment in the product documentation would be */
26 /* appreciated but is not required. */
27 /* 2. Altered source versions must be plainly marked as such, and must not */
28 /* be misrepresented as being the original software. */
29 /* 3. This notice may not be removed or altered from any source */
32 /*****************************************************************************/
62 /*****************************************************************************/
64 /*****************************************************************************/
69 static File* FileList; /* Single linked list */
70 static unsigned FileCount; /* Number of entries in the list */
75 static Memory* MemoryList; /* Single linked list */
76 static Memory* MemoryLast; /* Last element in list */
77 static unsigned MemoryCount; /* Number of entries in the list */
79 /* Memory attributes */
80 #define MA_START 0x0001
81 #define MA_SIZE 0x0002
82 #define MA_TYPE 0x0004
83 #define MA_FILE 0x0008
84 #define MA_DEFINE 0x0010
85 #define MA_FILL 0x0020
86 #define MA_FILLVAL 0x0040
91 SegDesc* SegDescList; /* Single linked list */
92 unsigned SegDescCount; /* Number of entries in list */
94 /* Segment attributes */
95 #define SA_TYPE 0x0001
96 #define SA_LOAD 0x0002
98 #define SA_ALIGN 0x0008
99 #define SA_DEFINE 0x0010
100 #define SA_OFFSET 0x0020
101 #define SA_START 0x0040
102 #define SA_OPTIONAL 0x0080
106 /* Descriptor holding information about the binary formats */
107 static BinDesc* BinFmtDesc = 0;
108 static O65Desc* O65FmtDesc = 0;
112 /*****************************************************************************/
114 /*****************************************************************************/
118 static File* NewFile (unsigned Name);
119 /* Create a new file descriptor and insert it into the list */
123 /*****************************************************************************/
124 /* List management */
125 /*****************************************************************************/
129 static File* FindFile (unsigned Name)
130 /* Find a file with a given name. */
134 if (F->Name == Name) {
144 static File* GetFile (unsigned Name)
145 /* Get a file entry with the given name. Create a new one if needed. */
147 File* F = FindFile (Name);
149 /* Create a new one */
157 static void FileInsert (File* F, Memory* M)
158 /* Insert the memory area into the files list */
161 if (F->MemList == 0) {
165 F->MemLast->FNext = M;
172 static Memory* CfgFindMemory (unsigned Name)
173 /* Find the memory are with the given name. Return NULL if not found */
175 Memory* M = MemoryList;
177 if (M->Name == Name) {
187 static Memory* CfgGetMemory (unsigned Name)
188 /* Find the memory are with the given name. Print an error on an invalid name */
190 Memory* M = CfgFindMemory (Name);
192 CfgError ("Invalid memory area `%s'", GetString (Name));
199 static SegDesc* CfgFindSegDesc (unsigned Name)
200 /* Find the segment descriptor with the given name, return NULL if not found. */
202 SegDesc* S = SegDescList;
204 if (S->Name == Name) {
217 static void SegDescInsert (SegDesc* S)
218 /* Insert a segment descriptor into the list of segment descriptors */
220 /* Insert the struct into the list */
221 S->Next = SegDescList;
228 static void MemoryInsert (Memory* M, SegDesc* S)
229 /* Insert the segment descriptor into the memory area list */
231 /* Create a new node for the entry */
232 MemListNode* N = xmalloc (sizeof (MemListNode));
236 if (M->SegLast == 0) {
240 M->SegLast->Next = N;
247 /*****************************************************************************/
248 /* Constructors/Destructors */
249 /*****************************************************************************/
253 static File* NewFile (unsigned Name)
254 /* Create a new file descriptor and insert it into the list */
256 /* Allocate memory */
257 File* F = xmalloc (sizeof (File));
259 /* Initialize the fields */
262 F->Format = BINFMT_DEFAULT;
266 /* Insert the struct into the list */
271 /* ...and return it */
277 static Memory* NewMemory (unsigned Name)
278 /* Create a new memory section and insert it into the list */
280 /* Check for duplicate names */
281 Memory* M = CfgFindMemory (Name);
283 CfgError ("Memory area `%s' defined twice", GetString (Name));
286 /* Allocate memory */
287 M = xmalloc (sizeof (Memory));
289 /* Initialize the fields */
303 /* Insert the struct into the list */
304 if (MemoryLast == 0) {
308 MemoryLast->Next = M;
313 /* ...and return it */
319 static SegDesc* NewSegDesc (unsigned Name)
320 /* Create a segment descriptor */
324 /* Check for duplicate names */
325 SegDesc* S = CfgFindSegDesc (Name);
327 CfgError ("Segment `%s' defined twice", GetString (Name));
330 /* Search for the actual segment in the input files. The function may
331 * return NULL (no such segment), this is checked later.
333 Seg = SegFind (Name);
335 /* Allocate memory */
336 S = xmalloc (sizeof (SegDesc));
338 /* Initialize the fields */
346 /* ...and return it */
352 static void FreeSegDesc (SegDesc* S)
353 /* Free a segment descriptor */
360 /*****************************************************************************/
362 /*****************************************************************************/
366 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
367 /* Check if the item is already defined. Print an error if so. If not, set
368 * the marker that we have a definition now.
372 CfgError ("%s is already defined", Name);
379 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
380 /* Check that a mandatory attribute was given */
382 if ((Attr & Mask) == 0) {
383 CfgError ("%s attribute is missing", Name);
389 static void ParseMemory (void)
390 /* Parse a MEMORY section */
392 static const IdentTok Attributes [] = {
393 { "START", CFGTOK_START },
394 { "SIZE", CFGTOK_SIZE },
395 { "TYPE", CFGTOK_TYPE },
396 { "FILE", CFGTOK_FILE },
397 { "DEFINE", CFGTOK_DEFINE },
398 { "FILL", CFGTOK_FILL },
399 { "FILLVAL", CFGTOK_FILLVAL },
401 static const IdentTok Types [] = {
406 while (CfgTok == CFGTOK_IDENT) {
408 /* Create a new entry on the heap */
409 Memory* M = NewMemory (GetStringId (CfgSVal));
411 /* Skip the name and the following colon */
415 /* Read the attributes */
416 while (CfgTok == CFGTOK_IDENT) {
418 /* Map the identifier to a token */
420 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
423 /* An optional assignment follows */
425 CfgOptionalAssign ();
427 /* Check which attribute was given */
431 FlagAttr (&M->Attr, MA_START, "START");
437 FlagAttr (&M->Attr, MA_SIZE, "SIZE");
443 FlagAttr (&M->Attr, MA_TYPE, "TYPE");
444 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
445 if (CfgTok == CFGTOK_RO) {
451 FlagAttr (&M->Attr, MA_FILE, "FILE");
453 /* Get the file entry and insert the memory area */
454 FileInsert (GetFile (GetStringId (CfgSVal)), M);
458 FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
459 /* Map the token to a boolean */
461 if (CfgTok == CFGTOK_TRUE) {
462 M->Flags |= MF_DEFINE;
467 FlagAttr (&M->Attr, MA_FILL, "FILL");
468 /* Map the token to a boolean */
470 if (CfgTok == CFGTOK_TRUE) {
476 FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
478 CfgRangeCheck (0, 0xFF);
479 M->FillVal = (unsigned char) CfgIVal;
483 FAIL ("Unexpected attribute token");
487 /* Skip the attribute value and an optional comma */
492 /* Skip the semicolon */
495 /* Check for mandatory parameters */
496 AttrCheck (M->Attr, MA_START, "START");
497 AttrCheck (M->Attr, MA_SIZE, "SIZE");
499 /* If we don't have a file name for output given, use the default
502 if ((M->Attr & MA_FILE) == 0) {
503 FileInsert (GetFile (GetStringId (OutputName)), M);
510 static void ParseFiles (void)
511 /* Parse a FILES section */
513 static const IdentTok Attributes [] = {
514 { "FORMAT", CFGTOK_FORMAT },
516 static const IdentTok Formats [] = {
517 { "O65", CFGTOK_O65 },
518 { "BIN", CFGTOK_BIN },
519 { "BINARY", CFGTOK_BIN },
523 /* Parse all files */
524 while (CfgTok != CFGTOK_RCURLY) {
528 /* We expect a string value here */
531 /* Search for the file, it must exist */
532 F = FindFile (GetStringId (CfgSVal));
534 CfgError ("No such file: `%s'", CfgSVal);
537 /* Skip the token and the following colon */
541 /* Read the attributes */
542 while (CfgTok == CFGTOK_IDENT) {
544 /* Map the identifier to a token */
546 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
549 /* An optional assignment follows */
551 CfgOptionalAssign ();
553 /* Check which attribute was given */
557 if (F->Format != BINFMT_DEFAULT) {
558 /* We've set the format already! */
559 Error ("Cannot set a file format twice");
561 /* Read the format token */
562 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
566 F->Format = BINFMT_BINARY;
570 F->Format = BINFMT_O65;
574 Error ("Unexpected format token");
579 FAIL ("Unexpected attribute token");
583 /* Skip the attribute value and an optional comma */
588 /* Skip the semicolon */
596 static void ParseSegments (void)
597 /* Parse a SEGMENTS section */
599 static const IdentTok Attributes [] = {
600 { "ALIGN", CFGTOK_ALIGN },
601 { "DEFINE", CFGTOK_DEFINE },
602 { "LOAD", CFGTOK_LOAD },
603 { "OFFSET", CFGTOK_OFFSET },
604 { "OPTIONAL", CFGTOK_OPTIONAL },
605 { "RUN", CFGTOK_RUN },
606 { "START", CFGTOK_START },
607 { "TYPE", CFGTOK_TYPE },
609 static const IdentTok Types [] = {
612 { "BSS", CFGTOK_BSS },
614 { "WP", CFGTOK_WPROT },
615 { "WPROT", CFGTOK_WPROT },
620 while (CfgTok == CFGTOK_IDENT) {
624 /* Create a new entry on the heap */
625 S = NewSegDesc (GetStringId (CfgSVal));
627 /* Skip the name and the following colon */
631 /* Read the attributes */
632 while (CfgTok == CFGTOK_IDENT) {
634 /* Map the identifier to a token */
636 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
639 /* An optional assignment follows */
641 CfgOptionalAssign ();
643 /* Check which attribute was given */
648 FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
649 CfgRangeCheck (1, 0x10000);
650 S->Align = BitFind (CfgIVal);
651 if ((0x01UL << S->Align) != CfgIVal) {
652 CfgError ("Alignment must be a power of 2");
654 S->Flags |= SF_ALIGN;
658 FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
659 /* Map the token to a boolean */
661 if (CfgTok == CFGTOK_TRUE) {
662 S->Flags |= SF_DEFINE;
667 FlagAttr (&S->Attr, SA_LOAD, "LOAD");
668 S->Load = CfgGetMemory (GetStringId (CfgSVal));
673 FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
674 CfgRangeCheck (1, 0x1000000);
676 S->Flags |= SF_OFFSET;
679 case CFGTOK_OPTIONAL:
680 FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
682 if (CfgTok == CFGTOK_TRUE) {
683 S->Flags |= SF_OPTIONAL;
688 FlagAttr (&S->Attr, SA_RUN, "RUN");
689 S->Run = CfgGetMemory (GetStringId (CfgSVal));
694 FlagAttr (&S->Attr, SA_START, "START");
695 CfgRangeCheck (1, 0x1000000);
697 S->Flags |= SF_START;
701 FlagAttr (&S->Attr, SA_TYPE, "TYPE");
702 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
704 case CFGTOK_RO: S->Flags |= SF_RO; break;
705 case CFGTOK_RW: /* Default */ break;
706 case CFGTOK_BSS: S->Flags |= SF_BSS; break;
707 case CFGTOK_ZP: S->Flags |= (SF_BSS | SF_ZP); break;
708 case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT); break;
709 default: Internal ("Unexpected token: %d", CfgTok);
714 FAIL ("Unexpected attribute token");
718 /* Skip the attribute value and an optional comma */
723 /* Check for mandatory parameters */
724 AttrCheck (S->Attr, SA_LOAD, "LOAD");
726 /* Set defaults for stuff not given */
727 if ((S->Attr & SA_RUN) == 0) {
731 /* Both attributes given */
732 S->Flags |= SF_LOAD_AND_RUN;
734 if ((S->Attr & SA_ALIGN) == 0) {
739 /* If the segment is marked as BSS style, and if the segment exists
740 * in any of the object file, check that there's no initialized data
743 if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
744 Warning ("%s(%u): Segment with type `bss' contains initialized data",
745 CfgGetName (), CfgErrorLine);
748 /* If the segment is marked as BSS style, it may not have separate
749 * load and run memory areas, because it's is never written to disk.
751 if ((S->Flags & SF_BSS) != 0 && (S->Flags & SF_LOAD_AND_RUN) != 0) {
752 Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
753 "memory areas assigned", CfgGetName (), CfgErrorLine);
756 /* Don't allow read/write data to be put into a readonly area */
757 if ((S->Flags & SF_RO) == 0) {
758 if (S->Run->Flags & MF_RO) {
759 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
760 GetString (S->Name), GetString (S->Run->Name));
764 /* Only one of ALIGN, START and OFFSET may be used */
765 Count = ((S->Flags & SF_ALIGN) != 0) +
766 ((S->Flags & SF_OFFSET) != 0) +
767 ((S->Flags & SF_START) != 0);
769 CfgError ("Only one of ALIGN, START, OFFSET may be used");
772 /* If this segment does exist in any of the object files, insert the
773 * descriptor into the list of segment descriptors. Otherwise print a
774 * warning and discard it, because the segment pointer in the
775 * descriptor is invalid.
778 /* Insert the descriptor into the list of all descriptors */
780 /* Insert the segment into the memory area list */
781 MemoryInsert (S->Run, S);
782 if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
783 /* We have a separate RUN area given */
784 MemoryInsert (S->Load, S);
787 /* Print a warning if the segment is not optional */
788 if ((S->Flags & SF_OPTIONAL) == 0) {
789 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
791 /* Discard the descriptor */
795 /* Skip the semicolon */
802 static void ParseO65 (void)
803 /* Parse the o65 format section */
805 static const IdentTok Attributes [] = {
806 { "EXPORT", CFGTOK_EXPORT },
807 { "IMPORT", CFGTOK_IMPORT },
808 { "TYPE", CFGTOK_TYPE },
811 { "VERSION", CFGTOK_VERSION },
813 static const IdentTok Types [] = {
814 { "SMALL", CFGTOK_SMALL },
815 { "LARGE", CFGTOK_LARGE },
817 static const IdentTok OperatingSystems [] = {
818 { "LUNIX", CFGTOK_LUNIX },
819 { "OSA65", CFGTOK_OSA65 },
820 { "CC65", CFGTOK_CC65 },
823 /* Bitmask to remember the attributes we got already */
827 atOSVersion = 0x0002,
834 unsigned AttrFlags = atNone;
836 /* Remember the attributes read */
838 unsigned OS = 0; /* Initialize to keep gcc happy */
839 unsigned Version = 0;
841 /* Read the attributes */
842 while (CfgTok == CFGTOK_IDENT) {
844 /* Map the identifier to a token */
846 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
849 /* An optional assignment follows */
851 CfgOptionalAssign ();
853 /* Check which attribute was given */
857 /* Remember we had this token (maybe more than once) */
858 AttrFlags |= atExport;
859 /* We expect an identifier */
861 /* Convert the string into a string index */
862 CfgSValId = GetStringId (CfgSVal);
863 /* Check if the export symbol is also defined as an import. */
864 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
865 CfgError ("Exported symbol `%s' cannot be an import", CfgSVal);
867 /* Check if we have this symbol defined already. The entry
868 * routine will check this also, but we get a more verbose
869 * error message when checking it here.
871 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
872 CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
874 /* Insert the symbol into the table */
875 O65SetExport (O65FmtDesc, CfgSValId);
879 /* Remember we had this token (maybe more than once) */
880 AttrFlags |= atImport;
881 /* We expect an identifier */
883 /* Convert the string into a string index */
884 CfgSValId = GetStringId (CfgSVal);
885 /* Check if the imported symbol is also defined as an export. */
886 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
887 CfgError ("Imported symbol `%s' cannot be an export", CfgSVal);
889 /* Check if we have this symbol defined already. The entry
890 * routine will check this also, but we get a more verbose
891 * error message when checking it here.
893 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
894 CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
896 /* Insert the symbol into the table */
897 O65SetImport (O65FmtDesc, CfgSValId);
901 /* Cannot have this attribute twice */
902 FlagAttr (&AttrFlags, atType, "TYPE");
903 /* Get the type of the executable */
904 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
908 O65SetSmallModel (O65FmtDesc);
912 O65SetLargeModel (O65FmtDesc);
916 CfgError ("Unexpected type token");
921 /* Cannot use this attribute twice */
922 FlagAttr (&AttrFlags, atOS, "OS");
923 /* Get the operating system */
924 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
926 case CFGTOK_LUNIX: OS = O65OS_LUNIX; break;
927 case CFGTOK_OSA65: OS = O65OS_OSA65; break;
928 case CFGTOK_CC65: OS = O65OS_CC65; break;
929 default: CfgError ("Unexpected OS token");
934 /* Cannot have this attribute twice */
935 FlagAttr (&AttrFlags, atID, "ID");
936 /* We're expecting a number in the 0..$FFFF range*/
938 CfgRangeCheck (0, 0xFFFF);
939 ModuleId = (unsigned) CfgIVal;
943 /* Cannot have this attribute twice */
944 FlagAttr (&AttrFlags, atVersion, "VERSION");
945 /* We're expecting a number in byte range */
947 CfgRangeCheck (0, 0xFF);
948 Version = (unsigned) CfgIVal;
952 FAIL ("Unexpected attribute token");
956 /* Skip the attribute value and an optional comma */
961 /* Check if we have all mandatory attributes */
962 AttrCheck (AttrFlags, atOS, "OS");
964 /* Check for attributes that may not be combined */
965 if (OS == O65OS_CC65) {
966 if ((AttrFlags & (atImport | atExport)) != 0) {
967 CfgError ("OS type CC65 may not have imports or exports");
970 if (AttrFlags & atID) {
971 CfgError ("Operating system does not support the ID attribute");
975 /* Set the O65 operating system to use */
976 O65SetOS (O65FmtDesc, OS, Version, ModuleId);
981 static void ParseFormats (void)
982 /* Parse a target format section */
984 static const IdentTok Formats [] = {
985 { "O65", CFGTOK_O65 },
986 { "BIN", CFGTOK_BIN },
987 { "BINARY", CFGTOK_BIN },
990 while (CfgTok == CFGTOK_IDENT) {
992 /* Map the identifier to a token */
994 CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
997 /* Skip the name and the following colon */
1001 /* Parse the format options */
1002 switch (FormatTok) {
1009 /* No attribibutes available */
1013 Error ("Unexpected format token");
1016 /* Skip the semicolon */
1023 static void ParseConDes (void)
1024 /* Parse the CONDES feature */
1026 static const IdentTok Attributes [] = {
1027 { "SEGMENT", CFGTOK_SEGMENT },
1028 { "LABEL", CFGTOK_LABEL },
1029 { "COUNT", CFGTOK_COUNT },
1030 { "TYPE", CFGTOK_TYPE },
1031 { "ORDER", CFGTOK_ORDER },
1034 static const IdentTok Types [] = {
1035 { "CONSTRUCTOR", CFGTOK_CONSTRUCTOR },
1036 { "DESTRUCTOR", CFGTOK_DESTRUCTOR },
1039 static const IdentTok Orders [] = {
1040 { "DECREASING", CFGTOK_DECREASING },
1041 { "INCREASING", CFGTOK_INCREASING },
1044 /* Attribute values. */
1045 unsigned SegName = INVALID_STRING_ID;
1046 unsigned Label = INVALID_STRING_ID;
1047 unsigned Count = INVALID_STRING_ID;
1048 /* Initialize to avoid gcc warnings: */
1050 ConDesOrder Order = cdIncreasing;
1052 /* Bitmask to remember the attributes we got already */
1061 unsigned AttrFlags = atNone;
1063 /* Parse the attributes */
1066 /* Map the identifier to a token */
1068 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1071 /* An optional assignment follows */
1073 CfgOptionalAssign ();
1075 /* Check which attribute was given */
1078 case CFGTOK_SEGMENT:
1079 /* Don't allow this twice */
1080 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1081 /* We expect an identifier */
1083 /* Remember the value for later */
1084 SegName = GetStringId (CfgSVal);
1088 /* Don't allow this twice */
1089 FlagAttr (&AttrFlags, atLabel, "LABEL");
1090 /* We expect an identifier */
1092 /* Remember the value for later */
1093 Label = GetStringId (CfgSVal);
1097 /* Don't allow this twice */
1098 FlagAttr (&AttrFlags, atCount, "COUNT");
1099 /* We expect an identifier */
1101 /* Remember the value for later */
1102 Count = GetStringId (CfgSVal);
1106 /* Don't allow this twice */
1107 FlagAttr (&AttrFlags, atType, "TYPE");
1108 /* The type may be given as id or numerical */
1109 if (CfgTok == CFGTOK_INTCON) {
1110 CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1111 Type = (int) CfgIVal;
1113 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1115 case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON; break;
1116 case CFGTOK_DESTRUCTOR: Type = CD_TYPE_DES; break;
1117 default: FAIL ("Unexpected type token");
1123 /* Don't allow this twice */
1124 FlagAttr (&AttrFlags, atOrder, "ORDER");
1125 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1127 case CFGTOK_DECREASING: Order = cdDecreasing; break;
1128 case CFGTOK_INCREASING: Order = cdIncreasing; break;
1129 default: FAIL ("Unexpected order token");
1134 FAIL ("Unexpected attribute token");
1138 /* Skip the attribute value */
1141 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1142 if (CfgTok == CFGTOK_SEMI) {
1144 } else if (CfgTok == CFGTOK_COMMA) {
1149 /* Check if we have all mandatory attributes */
1150 AttrCheck (AttrFlags, atSegName, "SEGMENT");
1151 AttrCheck (AttrFlags, atLabel, "LABEL");
1152 AttrCheck (AttrFlags, atType, "TYPE");
1154 /* Check if the condes has already attributes defined */
1155 if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1156 CfgError ("CONDES attributes for type %d are already defined", Type);
1159 /* Define the attributes */
1160 ConDesSetSegName (Type, SegName);
1161 ConDesSetLabel (Type, Label);
1162 if (AttrFlags & atCount) {
1163 ConDesSetCountSym (Type, Count);
1165 if (AttrFlags & atOrder) {
1166 ConDesSetOrder (Type, Order);
1172 static void ParseStartAddress (void)
1173 /* Parse the STARTADDRESS feature */
1175 static const IdentTok Attributes [] = {
1176 { "DEFAULT", CFGTOK_DEFAULT },
1180 /* Attribute values. */
1181 unsigned long DefStartAddr = 0;
1183 /* Bitmask to remember the attributes we got already */
1188 unsigned AttrFlags = atNone;
1190 /* Parse the attributes */
1193 /* Map the identifier to a token */
1195 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1198 /* An optional assignment follows */
1200 CfgOptionalAssign ();
1202 /* Check which attribute was given */
1205 case CFGTOK_DEFAULT:
1206 /* Don't allow this twice */
1207 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1208 /* We expect a number */
1210 CfgRangeCheck (0, 0xFFFFFF);
1211 /* Remember the value for later */
1212 DefStartAddr = CfgIVal;
1216 FAIL ("Unexpected attribute token");
1220 /* Skip the attribute value */
1223 /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1224 if (CfgTok == CFGTOK_SEMI) {
1226 } else if (CfgTok == CFGTOK_COMMA) {
1231 /* Check if we have all mandatory attributes */
1232 AttrCheck (AttrFlags, atDefault, "DEFAULT");
1234 /* If no start address was given on the command line, use the one given
1237 if (!HaveStartAddr) {
1238 StartAddr = DefStartAddr;
1244 static void ParseFeatures (void)
1245 /* Parse a features section */
1247 static const IdentTok Features [] = {
1248 { "CONDES", CFGTOK_CONDES },
1249 { "STARTADDRESS", CFGTOK_STARTADDRESS },
1252 while (CfgTok == CFGTOK_IDENT) {
1254 /* Map the identifier to a token */
1255 cfgtok_t FeatureTok;
1256 CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1257 FeatureTok = CfgTok;
1259 /* Skip the name and the following colon */
1263 /* Parse the format options */
1264 switch (FeatureTok) {
1270 case CFGTOK_STARTADDRESS:
1271 ParseStartAddress ();
1276 Error ("Unexpected feature token");
1279 /* Skip the semicolon */
1286 static void ParseSymbols (void)
1287 /* Parse a symbols section */
1289 while (CfgTok == CFGTOK_IDENT) {
1293 /* Remember the name */
1294 unsigned Name = GetStringId (CfgSVal);
1297 /* Allow an optional assignment */
1298 CfgOptionalAssign ();
1300 /* Make sure the next token is an integer, read and skip it */
1305 /* Generate an export with the given value */
1306 CreateConstExport (Name, Val);
1308 /* Skip the semicolon */
1315 static void ParseConfig (void)
1316 /* Parse the config file */
1318 static const IdentTok BlockNames [] = {
1319 { "MEMORY", CFGTOK_MEMORY },
1320 { "FILES", CFGTOK_FILES },
1321 { "SEGMENTS", CFGTOK_SEGMENTS },
1322 { "FORMATS", CFGTOK_FORMATS },
1323 { "FEATURES", CFGTOK_FEATURES },
1324 { "SYMBOLS", CFGTOK_SYMBOLS },
1330 /* Read the block ident */
1331 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1335 /* Expected a curly brace */
1336 CfgConsume (CFGTOK_LCURLY, "`{' expected");
1338 /* Read the block */
1349 case CFGTOK_SEGMENTS:
1353 case CFGTOK_FORMATS:
1357 case CFGTOK_FEATURES:
1361 case CFGTOK_SYMBOLS:
1366 FAIL ("Unexpected block token");
1370 /* Skip closing brace */
1371 CfgConsume (CFGTOK_RCURLY, "`}' expected");
1373 } while (CfgTok != CFGTOK_EOF);
1379 /* Read the configuration */
1381 /* Create the descriptors for the binary formats */
1382 BinFmtDesc = NewBinDesc ();
1383 O65FmtDesc = NewO65Desc ();
1385 /* If we have a config name given, open the file, otherwise we will read
1390 /* Parse the file */
1393 /* Close the input file */
1399 static void CreateRunDefines (SegDesc* S)
1400 /* Create the defines for a RUN segment */
1404 xsprintf (Buf, sizeof (Buf), "__%s_RUN__", GetString (S->Name));
1405 CreateSegmentExport (GetStringId (Buf), S->Seg, 0);
1406 xsprintf (Buf, sizeof (Buf), "__%s_SIZE__", GetString (S->Name));
1407 CreateConstExport (GetStringId (Buf), S->Seg->Size);
1408 S->Flags |= SF_RUN_DEF;
1413 static void CreateLoadDefines (Memory* M, SegDesc* S)
1414 /* Create the defines for a LOAD segment */
1418 xsprintf (Buf, sizeof (Buf), "__%s_LOAD__", GetString (S->Name));
1419 CreateMemoryExport (GetStringId (Buf), M, S->Seg->PC - M->Start);
1420 S->Flags |= SF_LOAD_DEF;
1425 void CfgAssignSegments (void)
1426 /* Assign segments, define linker symbols where requested */
1428 /* Walk through each of the memory sections. Add up the sizes and check
1429 * for an overflow of the section. Assign the start addresses of the
1430 * segments while doing this.
1432 Memory* M = MemoryList;
1435 /* Get the start address of this memory area */
1436 unsigned long Addr = M->Start;
1438 /* Walk through the segments in this memory area */
1439 MemListNode* N = M->SegList;
1442 /* Get the segment from the node */
1443 SegDesc* S = N->Seg;
1445 /* Handle ALIGN and OFFSET/START */
1446 if (S->Flags & SF_ALIGN) {
1447 /* Align the address */
1448 unsigned long Val = (0x01UL << S->Align) - 1;
1449 Addr = (Addr + Val) & ~Val;
1450 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1451 /* Give the segment a fixed starting address */
1452 unsigned long NewAddr = S->Addr;
1453 if (S->Flags & SF_OFFSET) {
1454 /* An offset was given, no address, make an address */
1455 NewAddr += M->Start;
1457 if (Addr > NewAddr) {
1458 /* Offset already too large */
1459 if (S->Flags & SF_OFFSET) {
1460 Error ("Offset too small in `%s', segment `%s'",
1461 GetString (M->Name), GetString (S->Name));
1463 Error ("Start address too low in `%s', segment `%s'",
1464 GetString (M->Name), GetString (S->Name));
1470 /* If this is the run area, set the start address of this segment */
1475 /* Increment the fill level of the memory area and check for an
1478 M->FillLevel = Addr + S->Seg->Size - M->Start;
1479 if (M->FillLevel > M->Size) {
1480 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1481 GetString (M->Name), GetString (S->Name),
1482 M->FillLevel - M->Size);
1485 /* If requested, define symbols for the start and size of the
1488 if (S->Flags & SF_DEFINE) {
1489 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1490 /* RUN and LOAD given and in one memory area.
1491 * Be careful: We will encounter this code twice, the
1492 * first time when walking the RUN list, second time when
1493 * walking the LOAD list. Be sure to define only the
1494 * relevant symbols on each walk.
1497 if ((S->Flags & SF_LOAD_DEF) == 0) {
1498 CreateLoadDefines (M, S);
1500 CHECK ((S->Flags & SF_RUN_DEF) == 0);
1501 CreateRunDefines (S);
1505 /* RUN and LOAD in different memory areas, or RUN not
1506 * given, so RUN defaults to LOAD. In the latter case, we
1507 * have only one copy of the segment in the area.
1510 CreateRunDefines (S);
1513 CreateLoadDefines (M, S);
1518 /* Calculate the new address */
1519 Addr += S->Seg->Size;
1525 /* If requested, define symbols for start and size of the memory area */
1526 if (M->Flags & MF_DEFINE) {
1528 sprintf (Buf, "__%s_START__", GetString (M->Name));
1529 CreateMemoryExport (GetStringId (Buf), M, 0);
1530 sprintf (Buf, "__%s_SIZE__", GetString (M->Name));
1531 CreateConstExport (GetStringId (Buf), M->Size);
1532 sprintf (Buf, "__%s_LAST__", GetString (M->Name));
1533 CreateConstExport (GetStringId (Buf), M->FillLevel);
1536 /* Next memory area */
1543 void CfgWriteTarget (void)
1544 /* Write the target file(s) */
1548 /* Walk through the files list */
1551 /* We don't need to look at files with no memory areas */
1554 /* Is there an output file? */
1555 if (strlen (GetString (F->Name)) > 0) {
1557 /* Assign a proper binary format */
1558 if (F->Format == BINFMT_DEFAULT) {
1559 F->Format = DefaultBinFmt;
1562 /* Call the apropriate routine for the binary format */
1563 switch (F->Format) {
1566 BinWriteTarget (BinFmtDesc, F);
1570 O65WriteTarget (O65FmtDesc, F);
1574 Internal ("Invalid binary format: %u", F->Format);
1580 /* No output file. Walk through the list and mark all segments
1581 * loading into these memory areas in this file as dumped.
1589 Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1591 /* Walk throught the segments */
1594 if (N->Seg->Load == M) {
1595 /* Load area - mark the segment as dumped */
1596 N->Seg->Seg->Dumped = 1;
1599 /* Next segment node */
1602 /* Next memory area */