]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Replace more linked lists by collections.
[cc65] / src / ld65 / config.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 config.c                                  */
4 /*                                                                           */
5 /*               Target configuration file for the ld65 linker               */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2010, Ullrich von Bassewitz                                      */
10 /*                Roemerstrasse 52                                           */
11 /*                D-70794 Filderstadt                                        */
12 /* EMail:         uz@cc65.org                                                */
13 /*                                                                           */
14 /*                                                                           */
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.                                    */
18 /*                                                                           */
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:                            */
22 /*                                                                           */
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              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "bitops.h"
43 #include "check.h"
44 #include "print.h"
45 #include "xmalloc.h"
46 #include "xsprintf.h"
47
48 /* ld65 */
49 #include "bin.h"
50 #include "binfmt.h"
51 #include "cfgexpr.h"
52 #include "condes.h"
53 #include "config.h"
54 #include "error.h"
55 #include "exports.h"
56 #include "global.h"
57 #include "o65.h"
58 #include "objdata.h"
59 #include "scanner.h"
60 #include "spool.h"
61
62
63
64 /*****************************************************************************/
65 /*                                   Data                                    */
66 /*****************************************************************************/
67
68
69
70 /* Remember which sections we had encountered */
71 static enum {
72     SE_NONE     = 0x0000,
73     SE_MEMORY   = 0x0001,
74     SE_SEGMENTS = 0x0002,
75     SE_FEATURES = 0x0004,
76     SE_FILES    = 0x0008,
77     SE_FORMATS  = 0x0010,
78     SE_SYMBOLS  = 0x0020
79 } SectionsEncountered = SE_NONE;
80
81
82
83 /* File list */
84 static Collection       FileList = STATIC_COLLECTION_INITIALIZER;
85
86 /* Memory list */
87 static Collection       MemoryList = STATIC_COLLECTION_INITIALIZER;
88
89 /* Memory attributes */
90 #define MA_START        0x0001
91 #define MA_SIZE         0x0002
92 #define MA_TYPE         0x0004
93 #define MA_FILE         0x0008
94 #define MA_DEFINE       0x0010
95 #define MA_FILL         0x0020
96 #define MA_FILLVAL      0x0040
97
98
99
100 /* Segment list */
101 SegDesc*                SegDescList;    /* Single linked list */
102 unsigned                SegDescCount;   /* Number of entries in list */
103
104 /* Segment attributes */
105 #define SA_TYPE         0x0001
106 #define SA_LOAD         0x0002
107 #define SA_RUN          0x0004
108 #define SA_ALIGN        0x0008
109 #define SA_ALIGN_LOAD   0x0010
110 #define SA_DEFINE       0x0020
111 #define SA_OFFSET       0x0040
112 #define SA_START        0x0080
113 #define SA_OPTIONAL     0x0100
114
115
116
117 /* Descriptor holding information about the binary formats */
118 static BinDesc* BinFmtDesc      = 0;
119 static O65Desc* O65FmtDesc      = 0;
120
121
122
123 /*****************************************************************************/
124 /*                                 Forwards                                  */
125 /*****************************************************************************/
126
127
128
129 static File* NewFile (unsigned Name);
130 /* Create a new file descriptor and insert it into the list */
131
132
133
134 /*****************************************************************************/
135 /*                              List management                              */
136 /*****************************************************************************/
137
138
139
140 static File* FindFile (unsigned Name)
141 /* Find a file with a given name. */
142 {
143     unsigned I;
144     for (I = 0; I < CollCount (&FileList); ++I) {
145         File* F = CollAtUnchecked (&FileList, I);
146         if (F->Name == Name) {
147             return F;
148         }
149     }
150     return 0;
151 }
152
153
154
155 static File* GetFile (unsigned Name)
156 /* Get a file entry with the given name. Create a new one if needed. */
157 {
158     File* F = FindFile (Name);
159     if (F == 0) {
160         /* Create a new one */
161         F = NewFile (Name);
162     }
163     return F;
164 }
165
166
167
168 static void FileInsert (File* F, Memory* M)
169 /* Insert the memory area into the files list */
170 {
171     M->F = F;
172     CollAppend (&F->MemList, M);
173 }
174
175
176
177 static Memory* CfgFindMemory (unsigned Name)
178 /* Find the memory are with the given name. Return NULL if not found */
179 {
180     unsigned I;
181     for (I = 0; I < CollCount (&MemoryList); ++I) {
182         Memory* M = CollAt (&MemoryList, I);
183         if (M->Name == Name) {
184             return M;
185         }
186     }
187     return 0;
188 }
189
190
191
192 static Memory* CfgGetMemory (unsigned Name)
193 /* Find the memory are with the given name. Print an error on an invalid name */
194 {
195     Memory* M = CfgFindMemory (Name);
196     if (M == 0) {
197         CfgError ("Invalid memory area `%s'", GetString (Name));
198     }
199     return M;
200 }
201
202
203
204 static SegDesc* CfgFindSegDesc (unsigned Name)
205 /* Find the segment descriptor with the given name, return NULL if not found. */
206 {
207     SegDesc* S = SegDescList;
208     while (S) {
209         if (S->Name == Name) {
210             /* Found */
211             return S;
212         }
213         S = S->Next;
214     }
215
216     /* Not found */
217     return 0;
218 }
219
220
221
222 static void SegDescInsert (SegDesc* S)
223 /* Insert a segment descriptor into the list of segment descriptors */
224 {
225     /* Insert the struct into the list */
226     S->Next = SegDescList;
227     SegDescList = S;
228     ++SegDescCount;
229 }
230
231
232
233 static void MemoryInsert (Memory* M, SegDesc* S)
234 /* Insert the segment descriptor into the memory area list */
235 {
236     /* Create a new node for the entry */
237     MemListNode* N = xmalloc (sizeof (MemListNode));
238     N->Seg  = S;
239     N->Next = 0;
240
241     if (M->SegLast == 0) {
242         /* First entry */
243         M->SegList = N;
244     } else {
245         M->SegLast->Next = N;
246     }
247     M->SegLast = N;
248 }
249
250
251
252 /*****************************************************************************/
253 /*                         Constructors/Destructors                          */
254 /*****************************************************************************/
255
256
257
258 static File* NewFile (unsigned Name)
259 /* Create a new file descriptor and insert it into the list */
260 {
261     /* Allocate memory */
262     File* F = xmalloc (sizeof (File));
263
264     /* Initialize the fields */
265     F->Name    = Name;
266     F->Flags   = 0;
267     F->Format  = BINFMT_DEFAULT;
268     InitCollection (&F->MemList);
269
270     /* Insert the struct into the list */
271     CollAppend (&FileList, F);
272
273     /* ...and return it */
274     return F;
275 }
276
277
278
279 static Memory* NewMemory (unsigned Name)
280 /* Create a new memory section and insert it into the list */
281 {
282     /* Check for duplicate names */
283     Memory* M = CfgFindMemory (Name);
284     if (M) {
285         CfgError ("Memory area `%s' defined twice", GetString (Name));
286     }
287
288     /* Allocate memory */
289     M = xmalloc (sizeof (Memory));
290
291     /* Initialize the fields */
292     M->Name        = Name;
293     M->Attr        = 0;
294     M->Flags       = 0;
295     M->Start       = 0;
296     M->Size        = 0;
297     M->FillLevel   = 0;
298     M->FillVal     = 0;
299     M->Relocatable = 0;
300     M->SegList     = 0;
301     M->SegLast     = 0;
302     M->F           = 0;
303
304     /* Insert the struct into the list */
305     CollAppend (&MemoryList, M);
306
307     /* ...and return it */
308     return M;
309 }
310
311
312
313 static SegDesc* NewSegDesc (unsigned Name)
314 /* Create a segment descriptor */
315 {
316     Segment* Seg;
317
318     /* Check for duplicate names */
319     SegDesc* S = CfgFindSegDesc (Name);
320     if (S) {
321         CfgError ("Segment `%s' defined twice", GetString (Name));
322     }
323
324     /* Search for the actual segment in the input files. The function may
325      * return NULL (no such segment), this is checked later.
326      */
327     Seg = SegFind (Name);
328
329     /* Allocate memory */
330     S = xmalloc (sizeof (SegDesc));
331
332     /* Initialize the fields */
333     S->Name    = Name;
334     S->Next    = 0;
335     S->Seg     = Seg;
336     S->Attr    = 0;
337     S->Flags   = 0;
338     S->Align   = 0;
339
340     /* ...and return it */
341     return S;
342 }
343
344
345
346 static void FreeSegDesc (SegDesc* S)
347 /* Free a segment descriptor */
348 {
349     xfree (S);
350 }
351
352
353
354 /*****************************************************************************/
355 /*                                   Code                                    */
356 /*****************************************************************************/
357
358
359
360 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
361 /* Check if the item is already defined. Print an error if so. If not, set
362  * the marker that we have a definition now.
363  */
364 {
365     if (*Flags & Mask) {
366         CfgError ("%s is already defined", Name);
367     }
368     *Flags |= Mask;
369 }
370
371
372
373 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
374 /* Check that a mandatory attribute was given */
375 {
376     if ((Attr & Mask) == 0) {
377         CfgError ("%s attribute is missing", Name);
378     }
379 }
380
381
382
383 static void ParseMemory (void)
384 /* Parse a MEMORY section */
385 {
386     static const IdentTok Attributes [] = {
387         {   "START",    CFGTOK_START    },
388         {   "SIZE",     CFGTOK_SIZE     },
389         {   "TYPE",     CFGTOK_TYPE     },
390         {   "FILE",     CFGTOK_FILE     },
391         {   "DEFINE",   CFGTOK_DEFINE   },
392         {   "FILL",     CFGTOK_FILL     },
393         {   "FILLVAL",  CFGTOK_FILLVAL  },
394     };
395     static const IdentTok Types [] = {
396         {   "RO",       CFGTOK_RO       },
397         {   "RW",       CFGTOK_RW       },
398     };
399
400     while (CfgTok == CFGTOK_IDENT) {
401
402         /* Create a new entry on the heap */
403         Memory* M = NewMemory (GetStrBufId (&CfgSVal));
404
405         /* Skip the name and the following colon */
406         CfgNextTok ();
407         CfgConsumeColon ();
408
409         /* Read the attributes */
410         while (CfgTok == CFGTOK_IDENT) {
411
412             /* Map the identifier to a token */
413             cfgtok_t AttrTok;
414             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
415             AttrTok = CfgTok;
416
417             /* An optional assignment follows */
418             CfgNextTok ();
419             CfgOptionalAssign ();
420
421             /* Check which attribute was given */
422             switch (AttrTok) {
423
424                 case CFGTOK_START:
425                     FlagAttr (&M->Attr, MA_START, "START");
426                     M->Start = CfgIntExpr ();
427                     break;
428
429                 case CFGTOK_SIZE:
430                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
431                     M->Size = CfgIntExpr ();
432                     break;
433
434                 case CFGTOK_TYPE:
435                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
436                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
437                     if (CfgTok == CFGTOK_RO) {
438                         M->Flags |= MF_RO;
439                     }
440                     CfgNextTok ();
441                     break;
442
443                 case CFGTOK_FILE:
444                     FlagAttr (&M->Attr, MA_FILE, "FILE");
445                     CfgAssureStr ();
446                     /* Get the file entry and insert the memory area */
447                     FileInsert (GetFile (GetStrBufId (&CfgSVal)), M);
448                     CfgNextTok ();
449                     break;
450
451                 case CFGTOK_DEFINE:
452                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
453                     /* Map the token to a boolean */
454                     CfgBoolToken ();
455                     if (CfgTok == CFGTOK_TRUE) {
456                         M->Flags |= MF_DEFINE;
457                     }
458                     CfgNextTok ();
459                     break;
460
461                 case CFGTOK_FILL:
462                     FlagAttr (&M->Attr, MA_FILL, "FILL");
463                     /* Map the token to a boolean */
464                     CfgBoolToken ();
465                     if (CfgTok == CFGTOK_TRUE) {
466                         M->Flags |= MF_FILL;
467                     }
468                     CfgNextTok ();
469                     break;
470
471                 case CFGTOK_FILLVAL:
472                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
473                     M->FillVal = (unsigned char) CfgCheckedIntExpr (0, 0xFF);
474                     break;
475
476                 default:
477                     FAIL ("Unexpected attribute token");
478
479             }
480
481             /* Skip an optional comma */
482             CfgOptionalComma ();
483         }
484
485         /* Skip the semicolon */
486         CfgConsumeSemi ();
487
488         /* Check for mandatory parameters */
489         AttrCheck (M->Attr, MA_START, "START");
490         AttrCheck (M->Attr, MA_SIZE, "SIZE");
491
492         /* If we don't have a file name for output given, use the default
493          * file name.
494          */
495         if ((M->Attr & MA_FILE) == 0) {
496             FileInsert (GetFile (GetStringId (OutputName)), M);
497         }
498     }
499
500     /* Remember we had this section */
501     SectionsEncountered |= SE_MEMORY;
502 }
503
504
505
506 static void ParseFiles (void)
507 /* Parse a FILES section */
508 {
509     static const IdentTok Attributes [] = {
510         {   "FORMAT",   CFGTOK_FORMAT   },
511     };
512     static const IdentTok Formats [] = {
513         {   "O65",      CFGTOK_O65           },
514         {   "BIN",      CFGTOK_BIN      },
515         {   "BINARY",   CFGTOK_BIN      },
516     };
517
518
519     /* The MEMORY section must preceed the FILES section */
520     if ((SectionsEncountered & SE_MEMORY) == 0) {
521         CfgError ("MEMORY must precede FILES");
522     }
523
524     /* Parse all files */
525     while (CfgTok != CFGTOK_RCURLY) {
526
527         File* F;
528
529         /* We expect a string value here */
530         CfgAssureStr ();
531
532         /* Search for the file, it must exist */
533         F = FindFile (GetStrBufId (&CfgSVal));
534         if (F == 0) {
535             CfgError ("File `%s' not found in MEMORY section",
536                       SB_GetConstBuf (&CfgSVal));
537         }
538
539         /* Skip the token and the following colon */
540         CfgNextTok ();
541         CfgConsumeColon ();
542
543         /* Read the attributes */
544         while (CfgTok == CFGTOK_IDENT) {
545
546             /* Map the identifier to a token */
547             cfgtok_t AttrTok;
548             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
549             AttrTok = CfgTok;
550
551             /* An optional assignment follows */
552             CfgNextTok ();
553             CfgOptionalAssign ();
554
555             /* Check which attribute was given */
556             switch (AttrTok) {
557
558                 case CFGTOK_FORMAT:
559                     if (F->Format != BINFMT_DEFAULT) {
560                         /* We've set the format already! */
561                         Error ("Cannot set a file format twice");
562                     }
563                     /* Read the format token */
564                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
565                     switch (CfgTok) {
566
567                         case CFGTOK_BIN:
568                             F->Format = BINFMT_BINARY;
569                             break;
570
571                         case CFGTOK_O65:
572                             F->Format = BINFMT_O65;
573                             break;
574
575                         default:
576                             Error ("Unexpected format token");
577                     }
578                     break;
579
580                 default:
581                     FAIL ("Unexpected attribute token");
582
583             }
584
585             /* Skip the attribute value and an optional comma */
586             CfgNextTok ();
587             CfgOptionalComma ();
588         }
589
590         /* Skip the semicolon */
591         CfgConsumeSemi ();
592
593     }
594
595     /* Remember we had this section */
596     SectionsEncountered |= SE_FILES;
597 }
598
599
600
601 static void ParseSegments (void)
602 /* Parse a SEGMENTS section */
603 {
604     static const IdentTok Attributes [] = {
605         {   "ALIGN",            CFGTOK_ALIGN            },
606         {   "ALIGN_LOAD",       CFGTOK_ALIGN_LOAD       },
607         {   "DEFINE",           CFGTOK_DEFINE           },
608         {   "LOAD",             CFGTOK_LOAD             },
609         {   "OFFSET",           CFGTOK_OFFSET           },
610         {   "OPTIONAL",         CFGTOK_OPTIONAL         },
611         {   "RUN",              CFGTOK_RUN              },
612         {   "START",            CFGTOK_START            },
613         {   "TYPE",             CFGTOK_TYPE             },
614     };
615     static const IdentTok Types [] = {
616         {   "RO",               CFGTOK_RO               },
617         {   "RW",               CFGTOK_RW               },
618         {   "BSS",              CFGTOK_BSS              },
619         {   "ZP",               CFGTOK_ZP               },
620     };
621
622     unsigned Count;
623     long     Val;
624
625     /* The MEMORY section must preceed the SEGMENTS section */
626     if ((SectionsEncountered & SE_MEMORY) == 0) {
627         CfgError ("MEMORY must precede SEGMENTS");
628     }
629
630     while (CfgTok == CFGTOK_IDENT) {
631
632         SegDesc* S;
633
634         /* Create a new entry on the heap */
635         S = NewSegDesc (GetStrBufId (&CfgSVal));
636
637         /* Skip the name and the following colon */
638         CfgNextTok ();
639         CfgConsumeColon ();
640
641         /* Read the attributes */
642         while (CfgTok == CFGTOK_IDENT) {
643
644             /* Map the identifier to a token */
645             cfgtok_t AttrTok;
646             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
647             AttrTok = CfgTok;
648
649             /* An optional assignment follows */
650             CfgNextTok ();
651             CfgOptionalAssign ();
652
653             /* Check which attribute was given */
654             switch (AttrTok) {
655
656                 case CFGTOK_ALIGN:
657                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
658                     Val = CfgCheckedIntExpr (1, 0x10000);
659                     S->Align = BitFind (Val);
660                     if ((0x01L << S->Align) != Val) {
661                         CfgError ("Alignment must be a power of 2");
662                     }
663                     S->Flags |= SF_ALIGN;
664                     break;
665
666                 case CFGTOK_ALIGN_LOAD:
667                     FlagAttr (&S->Attr, SA_ALIGN_LOAD, "ALIGN_LOAD");
668                     Val = CfgCheckedIntExpr (1, 0x10000);
669                     S->AlignLoad = BitFind (Val);
670                     if ((0x01L << S->AlignLoad) != Val) {
671                         CfgError ("Alignment must be a power of 2");
672                     }
673                     S->Flags |= SF_ALIGN_LOAD;
674                     break;
675
676                 case CFGTOK_DEFINE:
677                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
678                     /* Map the token to a boolean */
679                     CfgBoolToken ();
680                     if (CfgTok == CFGTOK_TRUE) {
681                         S->Flags |= SF_DEFINE;
682                     }
683                     CfgNextTok ();
684                     break;
685
686                 case CFGTOK_LOAD:
687                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
688                     S->Load = CfgGetMemory (GetStrBufId (&CfgSVal));
689                     CfgNextTok ();
690                     break;
691
692                 case CFGTOK_OFFSET:
693                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
694                     S->Addr   = CfgCheckedIntExpr (1, 0x1000000);
695                     S->Flags |= SF_OFFSET;
696                     break;
697
698                 case CFGTOK_OPTIONAL:
699                     FlagAttr (&S->Attr, SA_OPTIONAL, "OPTIONAL");
700                     CfgBoolToken ();
701                     if (CfgTok == CFGTOK_TRUE) {
702                         S->Flags |= SF_OPTIONAL;
703                     }
704                     CfgNextTok ();
705                     break;
706
707                 case CFGTOK_RUN:
708                     FlagAttr (&S->Attr, SA_RUN, "RUN");
709                     S->Run = CfgGetMemory (GetStrBufId (&CfgSVal));
710                     CfgNextTok ();
711                     break;
712
713                 case CFGTOK_START:
714                     FlagAttr (&S->Attr, SA_START, "START");
715                     S->Addr   = CfgCheckedIntExpr (1, 0x1000000);
716                     S->Flags |= SF_START;
717                     break;
718
719                 case CFGTOK_TYPE:
720                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
721                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
722                     switch (CfgTok) {
723                         case CFGTOK_RO:    S->Flags |= SF_RO;               break;
724                         case CFGTOK_RW:    /* Default */                    break;
725                         case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
726                         case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
727                         default:           Internal ("Unexpected token: %d", CfgTok);
728                     }
729                     CfgNextTok ();
730                     break;
731
732                 default:
733                     FAIL ("Unexpected attribute token");
734
735             }
736
737             /* Skip an optional comma */
738             CfgOptionalComma ();
739         }
740
741         /* Check for mandatory parameters */
742         AttrCheck (S->Attr, SA_LOAD, "LOAD");
743
744         /* Set defaults for stuff not given */
745         if ((S->Attr & SA_RUN) == 0) {
746             S->Attr |= SA_RUN;
747             S->Run = S->Load;
748         }
749
750         /* If the segment is marked as BSS style, and if the segment exists
751          * in any of the object file, check that there's no initialized data
752          * in the segment.
753          */
754         if ((S->Flags & SF_BSS) != 0 && S->Seg != 0 && !IsBSSType (S->Seg)) {
755             Warning ("%s(%u): Segment with type `bss' contains initialized data",
756                      CfgGetName (), CfgErrorLine);
757         }
758
759         /* An attribute of ALIGN_LOAD doesn't make sense if there are no
760          * separate run and load memory areas.
761          */
762         if ((S->Flags & SF_ALIGN_LOAD) != 0 && (S->Load == S->Run)) {
763             Warning ("%s(%u): ALIGN_LOAD attribute specified, but no separate "
764                      "LOAD and RUN memory areas assigned",
765                      CfgGetName (), CfgErrorLine);
766             /* Remove the flag */
767             S->Flags &= ~SF_ALIGN_LOAD;
768         }
769
770         /* If the segment is marked as BSS style, it may not have separate
771          * load and run memory areas, because it's is never written to disk.
772          */
773         if ((S->Flags & SF_BSS) != 0 && (S->Load != S->Run)) {
774             Warning ("%s(%u): Segment with type `bss' has both LOAD and RUN "
775                      "memory areas assigned", CfgGetName (), CfgErrorLine);
776         }
777
778         /* Don't allow read/write data to be put into a readonly area */
779         if ((S->Flags & SF_RO) == 0) {
780             if (S->Run->Flags & MF_RO) {
781                 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
782                           GetString (S->Name), GetString (S->Run->Name));
783             }
784         }
785
786         /* Only one of ALIGN, START and OFFSET may be used */
787         Count = ((S->Flags & SF_ALIGN)  != 0) +
788                 ((S->Flags & SF_OFFSET) != 0) +
789                 ((S->Flags & SF_START)  != 0);
790         if (Count > 1) {
791             CfgError ("Only one of ALIGN, START, OFFSET may be used");
792         }
793
794         /* If this segment does exist in any of the object files, insert the
795          * descriptor into the list of segment descriptors. Otherwise print a
796          * warning and discard it, because the segment pointer in the
797          * descriptor is invalid.
798          */
799         if (S->Seg != 0) {
800             /* Insert the descriptor into the list of all descriptors */
801             SegDescInsert (S);
802             /* Insert the segment into the memory area list */
803             MemoryInsert (S->Run, S);
804             if (S->Load != S->Run) {
805                 /* We have separate RUN and LOAD areas */
806                 MemoryInsert (S->Load, S);
807             }
808         } else {
809             /* Print a warning if the segment is not optional */
810             if ((S->Flags & SF_OPTIONAL) == 0) {
811                 CfgWarning ("Segment `%s' does not exist", GetString (S->Name));
812             }
813             /* Discard the descriptor */
814             FreeSegDesc (S);
815         }
816
817         /* Skip the semicolon */
818         CfgConsumeSemi ();
819     }
820
821     /* Remember we had this section */
822     SectionsEncountered |= SE_SEGMENTS;
823 }
824
825
826
827 static void ParseO65 (void)
828 /* Parse the o65 format section */
829 {
830     static const IdentTok Attributes [] = {
831         {   "EXPORT",   CFGTOK_EXPORT           },
832         {   "IMPORT",   CFGTOK_IMPORT           },
833         {   "TYPE",     CFGTOK_TYPE             },
834         {   "OS",       CFGTOK_OS               },
835         {   "ID",       CFGTOK_ID               },
836         {   "VERSION",  CFGTOK_VERSION          },
837     };
838     static const IdentTok Types [] = {
839         {   "SMALL",    CFGTOK_SMALL            },
840         {   "LARGE",    CFGTOK_LARGE            },
841     };
842     static const IdentTok OperatingSystems [] = {
843         {   "LUNIX",    CFGTOK_LUNIX            },
844         {   "OSA65",    CFGTOK_OSA65            },
845         {   "CC65",     CFGTOK_CC65             },
846         {   "OPENCBM",  CFGTOK_OPENCBM          },
847     };
848
849     /* Bitmask to remember the attributes we got already */
850     enum {
851         atNone          = 0x0000,
852         atOS            = 0x0001,
853         atOSVersion     = 0x0002,
854         atType          = 0x0004,
855         atImport        = 0x0008,
856         atExport        = 0x0010,
857         atID            = 0x0020,
858         atVersion       = 0x0040
859     };
860     unsigned AttrFlags = atNone;
861
862     /* Remember the attributes read */
863     unsigned CfgSValId;
864     unsigned OS = 0;            /* Initialize to keep gcc happy */
865     unsigned Version = 0;
866
867     /* Read the attributes */
868     while (CfgTok == CFGTOK_IDENT) {
869
870         /* Map the identifier to a token */
871         cfgtok_t AttrTok;
872         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
873         AttrTok = CfgTok;
874
875         /* An optional assignment follows */
876         CfgNextTok ();
877         CfgOptionalAssign ();
878
879         /* Check which attribute was given */
880         switch (AttrTok) {
881
882             case CFGTOK_EXPORT:
883                 /* Remember we had this token (maybe more than once) */
884                 AttrFlags |= atExport;
885                 /* We expect an identifier */
886                 CfgAssureIdent ();
887                 /* Convert the string into a string index */
888                 CfgSValId = GetStrBufId (&CfgSVal);
889                 /* Check if the export symbol is also defined as an import. */
890                 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
891                     CfgError ("Exported symbol `%s' cannot be an import",
892                               SB_GetConstBuf (&CfgSVal));
893                 }
894                 /* Check if we have this symbol defined already. The entry
895                  * routine will check this also, but we get a more verbose
896                  * error message when checking it here.
897                  */
898                 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
899                     CfgError ("Duplicate exported symbol: `%s'",
900                               SB_GetConstBuf (&CfgSVal));
901                 }
902                 /* Insert the symbol into the table */
903                 O65SetExport (O65FmtDesc, CfgSValId);
904                 /* Eat the identifier token */
905                 CfgNextTok ();
906                 break;
907
908             case CFGTOK_IMPORT:
909                 /* Remember we had this token (maybe more than once) */
910                 AttrFlags |= atImport;
911                 /* We expect an identifier */
912                 CfgAssureIdent ();
913                 /* Convert the string into a string index */
914                 CfgSValId = GetStrBufId (&CfgSVal);
915                 /* Check if the imported symbol is also defined as an export. */
916                 if (O65GetExport (O65FmtDesc, CfgSValId) != 0) {
917                     CfgError ("Imported symbol `%s' cannot be an export",
918                               SB_GetConstBuf (&CfgSVal));
919                 }
920                 /* Check if we have this symbol defined already. The entry
921                  * routine will check this also, but we get a more verbose
922                  * error message when checking it here.
923                  */
924                 if (O65GetImport (O65FmtDesc, CfgSValId) != 0) {
925                     CfgError ("Duplicate imported symbol: `%s'",
926                               SB_GetConstBuf (&CfgSVal));
927                 }
928                 /* Insert the symbol into the table */
929                 O65SetImport (O65FmtDesc, CfgSValId);
930                 /* Eat the identifier token */
931                 CfgNextTok ();
932                 break;
933
934             case CFGTOK_TYPE:
935                 /* Cannot have this attribute twice */
936                 FlagAttr (&AttrFlags, atType, "TYPE");
937                 /* Get the type of the executable */
938                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
939                 switch (CfgTok) {
940
941                     case CFGTOK_SMALL:
942                         O65SetSmallModel (O65FmtDesc);
943                         break;
944
945                     case CFGTOK_LARGE:
946                         O65SetLargeModel (O65FmtDesc);
947                         break;
948
949                     default:
950                         CfgError ("Unexpected type token");
951                 }
952                 /* Eat the attribute token */
953                 CfgNextTok ();
954                 break;
955
956             case CFGTOK_OS:
957                 /* Cannot use this attribute twice */
958                 FlagAttr (&AttrFlags, atOS, "OS");
959                 /* Get the operating system. It may be specified as name or
960                  * as a number in the range 1..255.
961                  */
962                 if (CfgTok == CFGTOK_INTCON) {
963                     CfgRangeCheck (O65OS_MIN, O65OS_MAX);
964                     OS = (unsigned) CfgIVal;
965                 } else {
966                     CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
967                     switch (CfgTok) {
968                         case CFGTOK_LUNIX:    OS = O65OS_LUNIX;     break;
969                         case CFGTOK_OSA65:    OS = O65OS_OSA65;     break;
970                         case CFGTOK_CC65:     OS = O65OS_CC65;      break;
971                         case CFGTOK_OPENCBM:  OS = O65OS_OPENCBM;   break;
972                         default:              CfgError ("Unexpected OS token");
973                     }
974                 }
975                 CfgNextTok ();
976                 break;
977
978             case CFGTOK_ID:
979                 /* Cannot have this attribute twice */
980                 FlagAttr (&AttrFlags, atID, "ID");
981                 /* We're expecting a number in the 0..$FFFF range*/
982                 ModuleId = (unsigned) CfgCheckedIntExpr (0, 0xFFFF);
983                 break;
984
985             case CFGTOK_VERSION:
986                 /* Cannot have this attribute twice */
987                 FlagAttr (&AttrFlags, atVersion, "VERSION");
988                 /* We're expecting a number in byte range */
989                 Version = (unsigned) CfgCheckedIntExpr (0, 0xFF);
990                 break;
991
992             default:
993                 FAIL ("Unexpected attribute token");
994
995         }
996
997         /* Skip an optional comma */
998         CfgOptionalComma ();
999     }
1000
1001     /* Check if we have all mandatory attributes */
1002     AttrCheck (AttrFlags, atOS, "OS");
1003
1004     /* Check for attributes that may not be combined */
1005     if (OS == O65OS_CC65) {
1006         if ((AttrFlags & (atImport | atExport)) != 0 && ModuleId < 0x8000) {
1007             CfgError ("OS type CC65 may not have imports or exports for ids < $8000");
1008         }
1009     } else {
1010         if (AttrFlags & atID) {
1011             CfgError ("Operating system does not support the ID attribute");
1012         }
1013     }
1014
1015     /* Set the O65 operating system to use */
1016     O65SetOS (O65FmtDesc, OS, Version, ModuleId);
1017 }
1018
1019
1020
1021 static void ParseFormats (void)
1022 /* Parse a target format section */
1023 {
1024     static const IdentTok Formats [] = {
1025         {   "O65",      CFGTOK_O65      },
1026         {   "BIN",      CFGTOK_BIN      },
1027         {   "BINARY",   CFGTOK_BIN      },
1028     };
1029
1030     while (CfgTok == CFGTOK_IDENT) {
1031
1032         /* Map the identifier to a token */
1033         cfgtok_t FormatTok;
1034         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
1035         FormatTok = CfgTok;
1036
1037         /* Skip the name and the following colon */
1038         CfgNextTok ();
1039         CfgConsumeColon ();
1040
1041         /* Parse the format options */
1042         switch (FormatTok) {
1043
1044             case CFGTOK_O65:
1045                 ParseO65 ();
1046                 break;
1047
1048             case CFGTOK_BIN:
1049                 /* No attribibutes available */
1050                 break;
1051
1052             default:
1053                 Error ("Unexpected format token");
1054         }
1055
1056         /* Skip the semicolon */
1057         CfgConsumeSemi ();
1058     }
1059
1060
1061     /* Remember we had this section */
1062     SectionsEncountered |= SE_FORMATS;
1063 }
1064
1065
1066
1067 static void ParseConDes (void)
1068 /* Parse the CONDES feature */
1069 {
1070     static const IdentTok Attributes [] = {
1071         {   "SEGMENT",          CFGTOK_SEGMENT          },
1072         {   "LABEL",            CFGTOK_LABEL            },
1073         {   "COUNT",            CFGTOK_COUNT            },
1074         {   "TYPE",             CFGTOK_TYPE             },
1075         {   "ORDER",            CFGTOK_ORDER            },
1076     };
1077
1078     static const IdentTok Types [] = {
1079         {   "CONSTRUCTOR",      CFGTOK_CONSTRUCTOR      },
1080         {   "DESTRUCTOR",       CFGTOK_DESTRUCTOR       },
1081         {   "INTERRUPTOR",      CFGTOK_INTERRUPTOR      },
1082     };
1083
1084     static const IdentTok Orders [] = {
1085         {   "DECREASING",       CFGTOK_DECREASING       },
1086         {   "INCREASING",       CFGTOK_INCREASING       },
1087     };
1088
1089     /* Attribute values. */
1090     unsigned SegName = INVALID_STRING_ID;
1091     unsigned Label   = INVALID_STRING_ID;
1092     unsigned Count   = INVALID_STRING_ID;
1093     /* Initialize to avoid gcc warnings: */
1094     int Type = -1;
1095     ConDesOrder Order = cdIncreasing;
1096
1097     /* Bitmask to remember the attributes we got already */
1098     enum {
1099         atNone          = 0x0000,
1100         atSegName       = 0x0001,
1101         atLabel         = 0x0002,
1102         atCount         = 0x0004,
1103         atType          = 0x0008,
1104         atOrder         = 0x0010
1105     };
1106     unsigned AttrFlags = atNone;
1107
1108     /* Parse the attributes */
1109     while (1) {
1110
1111         /* Map the identifier to a token */
1112         cfgtok_t AttrTok;
1113         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1114         AttrTok = CfgTok;
1115
1116         /* An optional assignment follows */
1117         CfgNextTok ();
1118         CfgOptionalAssign ();
1119
1120         /* Check which attribute was given */
1121         switch (AttrTok) {
1122
1123             case CFGTOK_SEGMENT:
1124                 /* Don't allow this twice */
1125                 FlagAttr (&AttrFlags, atSegName, "SEGMENT");
1126                 /* We expect an identifier */
1127                 CfgAssureIdent ();
1128                 /* Remember the value for later */
1129                 SegName = GetStrBufId (&CfgSVal);
1130                 break;
1131
1132             case CFGTOK_LABEL:
1133                 /* Don't allow this twice */
1134                 FlagAttr (&AttrFlags, atLabel, "LABEL");
1135                 /* We expect an identifier */
1136                 CfgAssureIdent ();
1137                 /* Remember the value for later */
1138                 Label = GetStrBufId (&CfgSVal);
1139                 break;
1140
1141             case CFGTOK_COUNT:
1142                 /* Don't allow this twice */
1143                 FlagAttr (&AttrFlags, atCount, "COUNT");
1144                 /* We expect an identifier */
1145                 CfgAssureIdent ();
1146                 /* Remember the value for later */
1147                 Count = GetStrBufId (&CfgSVal);
1148                 break;
1149
1150             case CFGTOK_TYPE:
1151                 /* Don't allow this twice */
1152                 FlagAttr (&AttrFlags, atType, "TYPE");
1153                 /* The type may be given as id or numerical */
1154                 if (CfgTok == CFGTOK_INTCON) {
1155                     CfgRangeCheck (CD_TYPE_MIN, CD_TYPE_MAX);
1156                     Type = (int) CfgIVal;
1157                 } else {
1158                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
1159                     switch (CfgTok) {
1160                         case CFGTOK_CONSTRUCTOR: Type = CD_TYPE_CON;    break;
1161                         case CFGTOK_DESTRUCTOR:  Type = CD_TYPE_DES;    break;
1162                         case CFGTOK_INTERRUPTOR: Type = CD_TYPE_INT;    break;
1163                         default: FAIL ("Unexpected type token");
1164                     }
1165                 }
1166                 break;
1167
1168             case CFGTOK_ORDER:
1169                 /* Don't allow this twice */
1170                 FlagAttr (&AttrFlags, atOrder, "ORDER");
1171                 CfgSpecialToken (Orders, ENTRY_COUNT (Orders), "Order");
1172                 switch (CfgTok) {
1173                     case CFGTOK_DECREASING: Order = cdDecreasing;       break;
1174                     case CFGTOK_INCREASING: Order = cdIncreasing;       break;
1175                     default: FAIL ("Unexpected order token");
1176                 }
1177                 break;
1178
1179             default:
1180                 FAIL ("Unexpected attribute token");
1181
1182         }
1183
1184         /* Skip the attribute value */
1185         CfgNextTok ();
1186
1187         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1188         if (CfgTok == CFGTOK_SEMI) {
1189             break;
1190         } else if (CfgTok == CFGTOK_COMMA) {
1191             CfgNextTok ();
1192         }
1193     }
1194
1195     /* Check if we have all mandatory attributes */
1196     AttrCheck (AttrFlags, atSegName, "SEGMENT");
1197     AttrCheck (AttrFlags, atLabel, "LABEL");
1198     AttrCheck (AttrFlags, atType, "TYPE");
1199
1200     /* Check if the condes has already attributes defined */
1201     if (ConDesHasSegName(Type) || ConDesHasLabel(Type)) {
1202         CfgError ("CONDES attributes for type %d are already defined", Type);
1203     }
1204
1205     /* Define the attributes */
1206     ConDesSetSegName (Type, SegName);
1207     ConDesSetLabel (Type, Label);
1208     if (AttrFlags & atCount) {
1209         ConDesSetCountSym (Type, Count);
1210     }
1211     if (AttrFlags & atOrder) {
1212         ConDesSetOrder (Type, Order);
1213     }
1214 }
1215
1216
1217
1218 static void ParseStartAddress (void)
1219 /* Parse the STARTADDRESS feature */
1220 {
1221     static const IdentTok Attributes [] = {
1222         {   "DEFAULT",  CFGTOK_DEFAULT },
1223     };
1224
1225
1226     /* Attribute values. */
1227     unsigned long DefStartAddr = 0;
1228
1229     /* Bitmask to remember the attributes we got already */
1230     enum {
1231         atNone          = 0x0000,
1232         atDefault       = 0x0001
1233     };
1234     unsigned AttrFlags = atNone;
1235
1236     /* Parse the attributes */
1237     while (1) {
1238
1239         /* Map the identifier to a token */
1240         cfgtok_t AttrTok;
1241         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1242         AttrTok = CfgTok;
1243
1244         /* An optional assignment follows */
1245         CfgNextTok ();
1246         CfgOptionalAssign ();
1247
1248         /* Check which attribute was given */
1249         switch (AttrTok) {
1250
1251             case CFGTOK_DEFAULT:
1252                 /* Don't allow this twice */
1253                 FlagAttr (&AttrFlags, atDefault, "DEFAULT");
1254                 /* We expect a numeric expression */
1255                 DefStartAddr = CfgCheckedIntExpr (0, 0xFFFFFF);
1256                 break;
1257
1258             default:
1259                 FAIL ("Unexpected attribute token");
1260
1261         }
1262
1263         /* Semicolon ends the ConDes decl, otherwise accept an optional comma */
1264         if (CfgTok == CFGTOK_SEMI) {
1265             break;
1266         } else if (CfgTok == CFGTOK_COMMA) {
1267             CfgNextTok ();
1268         }
1269     }
1270
1271     /* Check if we have all mandatory attributes */
1272     AttrCheck (AttrFlags, atDefault, "DEFAULT");
1273
1274     /* If no start address was given on the command line, use the one given
1275      * here
1276      */
1277     if (!HaveStartAddr) {
1278         StartAddr = DefStartAddr;
1279     }
1280 }
1281
1282
1283
1284 static void ParseFeatures (void)
1285 /* Parse a features section */
1286 {
1287     static const IdentTok Features [] = {
1288         {   "CONDES",       CFGTOK_CONDES       },
1289         {   "STARTADDRESS", CFGTOK_STARTADDRESS },
1290     };
1291
1292     while (CfgTok == CFGTOK_IDENT) {
1293
1294         /* Map the identifier to a token */
1295         cfgtok_t FeatureTok;
1296         CfgSpecialToken (Features, ENTRY_COUNT (Features), "Feature");
1297         FeatureTok = CfgTok;
1298
1299         /* Skip the name and the following colon */
1300         CfgNextTok ();
1301         CfgConsumeColon ();
1302
1303         /* Parse the format options */
1304         switch (FeatureTok) {
1305
1306             case CFGTOK_CONDES:
1307                 ParseConDes ();
1308                 break;
1309
1310             case CFGTOK_STARTADDRESS:
1311                 ParseStartAddress ();
1312                 break;
1313
1314
1315             default:
1316                 FAIL ("Unexpected feature token");
1317         }
1318
1319         /* Skip the semicolon */
1320         CfgConsumeSemi ();
1321     }
1322
1323     /* Remember we had this section */
1324     SectionsEncountered |= SE_FEATURES;
1325 }
1326
1327
1328
1329 static void ParseSymbols (void)
1330 /* Parse a symbols section */
1331 {
1332     static const IdentTok Attributes[] = {
1333         {   "VALUE",    CFGTOK_VALUE    },
1334         {   "WEAK",     CFGTOK_WEAK     },
1335     };
1336
1337     while (CfgTok == CFGTOK_IDENT) {
1338
1339         long Val = 0L;
1340         int  Weak = 0;
1341         Export* E;
1342
1343         /* Remember the name */
1344         unsigned Name = GetStrBufId (&CfgSVal);
1345         CfgNextTok ();
1346
1347         /* Support both, old and new syntax here. New syntax is a colon
1348          * followed by an attribute list, old syntax is an optional equal
1349          * sign plus a value.
1350          */
1351         if (CfgTok != CFGTOK_COLON) {
1352
1353             /* Old syntax */
1354
1355             /* Allow an optional assignment */
1356             CfgOptionalAssign ();
1357
1358             /* Make sure the next token is an integer expression, read and
1359              * skip it.
1360              */
1361             Val = CfgIntExpr ();
1362
1363         } else {
1364
1365             /* Bitmask to remember the attributes we got already */
1366             enum {
1367                 atNone          = 0x0000,
1368                 atValue         = 0x0001,
1369                 atWeak          = 0x0002
1370             };
1371             unsigned AttrFlags = atNone;
1372
1373
1374             /* New syntax - skip the colon */
1375             CfgNextTok ();
1376
1377             /* Parse the attributes */
1378             while (1) {
1379
1380                 /* Map the identifier to a token */
1381                 cfgtok_t AttrTok;
1382                 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
1383                 AttrTok = CfgTok;
1384
1385                 /* Skip the attribute name */
1386                 CfgNextTok ();
1387
1388                 /* An optional assignment follows */
1389                 CfgOptionalAssign ();
1390
1391                 /* Check which attribute was given */
1392                 switch (AttrTok) {
1393
1394                     case CFGTOK_VALUE:
1395                         /* Don't allow this twice */
1396                         FlagAttr (&AttrFlags, atValue, "VALUE");
1397                         /* We expect a numeric expression */
1398                         Val = CfgIntExpr ();
1399                         break;
1400
1401                     case CFGTOK_WEAK:
1402                         /* Don't allow this twice */
1403                         FlagAttr (&AttrFlags, atWeak, "WEAK");
1404                         CfgBoolToken ();
1405                         Weak = (CfgTok == CFGTOK_TRUE);
1406                         CfgNextTok ();
1407                         break;
1408
1409                     default:
1410                         FAIL ("Unexpected attribute token");
1411
1412                 }
1413
1414                 /* Semicolon ends the decl, otherwise accept an optional comma */
1415                 if (CfgTok == CFGTOK_SEMI) {
1416                     break;
1417                 } else if (CfgTok == CFGTOK_COMMA) {
1418                     CfgNextTok ();
1419                 }
1420             }
1421
1422             /* Check if we have all mandatory attributes */
1423             AttrCheck (AttrFlags, atValue, "VALUE");
1424
1425             /* Weak is optional, the default are non weak symbols */
1426             if ((AttrFlags & atWeak) == 0) {
1427                 Weak = 0;
1428             }
1429
1430         }
1431
1432         /* Check if the symbol is already defined */
1433         if ((E = FindExport (Name)) != 0 && !IsUnresolvedExport (E)) {
1434             /* If the symbol is not marked as weak, this is an error.
1435              * Otherwise ignore the symbol from the config.
1436              */
1437             if (!Weak) {
1438                 CfgError ("Symbol `%s' is already defined", GetString (Name));
1439             }
1440         } else {
1441             /* The symbol is undefined, generate an export */
1442             CreateConstExport (Name, Val);
1443         }
1444
1445         /* Skip the semicolon */
1446         CfgConsumeSemi ();
1447     }
1448
1449     /* Remember we had this section */
1450     SectionsEncountered |= SE_SYMBOLS;
1451 }
1452
1453
1454
1455 static void ParseConfig (void)
1456 /* Parse the config file */
1457 {
1458     static const IdentTok BlockNames [] = {
1459         {   "MEMORY",   CFGTOK_MEMORY   },
1460         {   "FILES",    CFGTOK_FILES    },
1461         {   "SEGMENTS", CFGTOK_SEGMENTS },
1462         {   "FORMATS",  CFGTOK_FORMATS  },
1463         {   "FEATURES", CFGTOK_FEATURES },
1464         {   "SYMBOLS",  CFGTOK_SYMBOLS  },
1465     };
1466     cfgtok_t BlockTok;
1467
1468     do {
1469
1470         /* Read the block ident */
1471         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
1472         BlockTok = CfgTok;
1473         CfgNextTok ();
1474
1475         /* Expected a curly brace */
1476         CfgConsume (CFGTOK_LCURLY, "`{' expected");
1477
1478         /* Read the block */
1479         switch (BlockTok) {
1480
1481             case CFGTOK_MEMORY:
1482                 ParseMemory ();
1483                 break;
1484
1485             case CFGTOK_FILES:
1486                 ParseFiles ();
1487                 break;
1488
1489             case CFGTOK_SEGMENTS:
1490                 ParseSegments ();
1491                 break;
1492
1493             case CFGTOK_FORMATS:
1494                 ParseFormats ();
1495                 break;
1496
1497             case CFGTOK_FEATURES:
1498                 ParseFeatures ();
1499                 break;
1500
1501             case CFGTOK_SYMBOLS:
1502                 ParseSymbols ();
1503                 break;
1504
1505             default:
1506                 FAIL ("Unexpected block token");
1507
1508         }
1509
1510         /* Skip closing brace */
1511         CfgConsume (CFGTOK_RCURLY, "`}' expected");
1512
1513     } while (CfgTok != CFGTOK_EOF);
1514 }
1515
1516
1517
1518 void CfgRead (void)
1519 /* Read the configuration */
1520 {
1521     /* Create the descriptors for the binary formats */
1522     BinFmtDesc = NewBinDesc ();
1523     O65FmtDesc = NewO65Desc ();
1524
1525     /* If we have a config name given, open the file, otherwise we will read
1526      * from a buffer.
1527      */
1528     CfgOpenInput ();
1529
1530     /* Parse the file */
1531     ParseConfig ();
1532
1533     /* Close the input file */
1534     CfgCloseInput ();
1535 }
1536
1537
1538
1539 static void CreateRunDefines (SegDesc* S, unsigned long SegAddr)
1540 /* Create the defines for a RUN segment */
1541 {
1542     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1543
1544     SB_Printf (&Buf, "__%s_RUN__", GetString (S->Name));
1545     CreateMemoryExport (GetStrBufId (&Buf), S->Run, SegAddr - S->Run->Start);
1546     SB_Printf (&Buf, "__%s_SIZE__", GetString (S->Name));
1547     CreateConstExport (GetStrBufId (&Buf), S->Seg->Size);
1548     S->Flags |= SF_RUN_DEF;
1549     SB_Done (&Buf);
1550 }
1551
1552
1553
1554 static void CreateLoadDefines (SegDesc* S, unsigned long SegAddr)
1555 /* Create the defines for a LOAD segment */
1556 {
1557     StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1558
1559     SB_Printf (&Buf, "__%s_LOAD__", GetString (S->Name));
1560     CreateMemoryExport (GetStrBufId (&Buf), S->Load, SegAddr - S->Load->Start);
1561     S->Flags |= SF_LOAD_DEF;
1562     SB_Done (&Buf);
1563 }
1564
1565
1566
1567 unsigned CfgAssignSegments (void)
1568 /* Assign segments, define linker symbols where requested. The function will
1569  * return the number of memory area overflows (so zero means anything went ok).
1570  * In case of overflows, a short mapfile can be generated later, to ease the
1571  * task of rearranging segments for the user.
1572  */
1573 {
1574     unsigned Overflows = 0;
1575
1576     /* Walk through each of the memory sections. Add up the sizes and check
1577      * for an overflow of the section. Assign the start addresses of the
1578      * segments while doing this.
1579      */
1580     unsigned I;
1581     for (I = 0; I < CollCount (&MemoryList); ++I) {
1582
1583         MemListNode* N;
1584
1585         /* Get this entry */
1586         Memory* M = CollAtUnchecked (&MemoryList, I);
1587
1588         /* Get the start address of this memory area */
1589         unsigned long Addr = M->Start;
1590
1591         /* Remember if this is a relocatable memory area */
1592         M->Relocatable = RelocatableBinFmt (M->F->Format);
1593
1594         /* Walk through the segments in this memory area */
1595         N = M->SegList;
1596         while (N) {
1597
1598             /* Get the segment from the node */
1599             SegDesc* S = N->Seg;
1600
1601             /* Some actions depend on wether this is the load or run memory
1602              * area.
1603              */
1604             if (S->Run == M) {
1605
1606                 /* This is the run (and maybe load) memory area. Handle
1607                  * alignment and explict start address and offset.
1608                  */
1609                 if (S->Flags & SF_ALIGN) {
1610                     /* Align the address */
1611                     unsigned long Val = (0x01UL << S->Align) - 1;
1612                     Addr = (Addr + Val) & ~Val;
1613                 } else if (S->Flags & (SF_OFFSET | SF_START)) {
1614                     /* Give the segment a fixed starting address */
1615                     unsigned long NewAddr = S->Addr;
1616                     if (S->Flags & SF_OFFSET) {
1617                         /* An offset was given, no address, make an address */
1618                         NewAddr += M->Start;
1619                     }
1620                     if (Addr > NewAddr) {
1621                         /* Offset already too large */
1622                         if (S->Flags & SF_OFFSET) {
1623                             Error ("Offset too small in `%s', segment `%s'",
1624                                    GetString (M->Name), GetString (S->Name));
1625                         } else {
1626                             Error ("Start address too low in `%s', segment `%s'",
1627                                    GetString (M->Name), GetString (S->Name));
1628                         }
1629                     }
1630                     Addr = NewAddr;
1631                 }
1632
1633                 /* Set the start address of this segment, set the readonly flag
1634                  * in the segment and and remember if the segment is in a
1635                  * relocatable file or not.
1636                  */
1637                 S->Seg->PC = Addr;
1638                 S->Seg->ReadOnly = (S->Flags & SF_RO) != 0;
1639                 S->Seg->Relocatable = M->Relocatable;
1640
1641             } else if (S->Load == M) {
1642
1643                 /* This is the load memory area, *and* run and load are
1644                  * different (because of the "else" above). Handle alignment.
1645                  */
1646                 if (S->Flags & SF_ALIGN_LOAD) {
1647                     /* Align the address */
1648                     unsigned long Val = (0x01UL << S->AlignLoad) - 1;
1649                     Addr = (Addr + Val) & ~Val;
1650                 }
1651
1652             }
1653
1654             /* Increment the fill level of the memory area and check for an
1655              * overflow.
1656              */
1657             M->FillLevel = Addr + S->Seg->Size - M->Start;
1658             if (M->FillLevel > M->Size && (M->Flags & MF_OVERFLOW) == 0) {
1659                 ++Overflows;
1660                 M->Flags |= MF_OVERFLOW;
1661                 Warning ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1662                          GetString (M->Name), GetString (S->Name),
1663                          M->FillLevel - M->Size);
1664             }
1665
1666             /* If requested, define symbols for the start and size of the
1667              * segment.
1668              */
1669             if (S->Flags & SF_DEFINE) {
1670                 if (S->Run == M && (S->Flags & SF_RUN_DEF) == 0) {
1671                     CreateRunDefines (S, Addr);
1672                 }
1673                 if (S->Load == M && (S->Flags & SF_LOAD_DEF) == 0) {
1674                     CreateLoadDefines (S, Addr);
1675                 }
1676             }
1677
1678             /* Calculate the new address */
1679             Addr += S->Seg->Size;
1680
1681             /* Next segment */
1682             N = N->Next;
1683         }
1684
1685         /* If requested, define symbols for start and size of the memory area */
1686         if (M->Flags & MF_DEFINE) {
1687             StrBuf Buf = STATIC_STRBUF_INITIALIZER;
1688             SB_Printf (&Buf, "__%s_START__", GetString (M->Name));
1689             CreateMemoryExport (GetStrBufId (&Buf), M, 0);
1690             SB_Printf (&Buf, "__%s_SIZE__", GetString (M->Name));
1691             CreateConstExport (GetStrBufId (&Buf), M->Size);
1692             SB_Printf (&Buf, "__%s_LAST__", GetString (M->Name));
1693             CreateMemoryExport (GetStrBufId (&Buf), M, M->FillLevel);
1694             SB_Done (&Buf);
1695         }
1696
1697     }
1698
1699     /* Return the number of memory area overflows */
1700     return Overflows;
1701 }
1702
1703
1704
1705 void CfgWriteTarget (void)
1706 /* Write the target file(s) */
1707 {
1708     unsigned I;
1709
1710     /* Walk through the files list */
1711     for (I = 0; I < CollCount (&FileList); ++I) {
1712
1713         /* Get this entry */
1714         File* F = CollAtUnchecked (&FileList, I);
1715
1716         /* We don't need to look at files with no memory areas */
1717         if (CollCount (&F->MemList) > 0) {
1718
1719             /* Is there an output file? */
1720             if (SB_GetLen (GetStrBuf (F->Name)) > 0) {
1721
1722                 /* Assign a proper binary format */
1723                 if (F->Format == BINFMT_DEFAULT) {
1724                     F->Format = DefaultBinFmt;
1725                 }
1726
1727                 /* Call the apropriate routine for the binary format */
1728                 switch (F->Format) {
1729
1730                     case BINFMT_BINARY:
1731                         BinWriteTarget (BinFmtDesc, F);
1732                         break;
1733
1734                     case BINFMT_O65:
1735                         O65WriteTarget (O65FmtDesc, F);
1736                         break;
1737
1738                     default:
1739                         Internal ("Invalid binary format: %u", F->Format);
1740
1741                 }
1742
1743             } else {
1744
1745                 /* No output file. Walk through the list and mark all segments
1746                  * loading into these memory areas in this file as dumped.
1747                  */ 
1748                 unsigned J;
1749                 for (J = 0; J < CollCount (&F->MemList); ++J) {
1750
1751                     MemListNode* N;
1752
1753                     /* Get this entry */
1754                     Memory* M = CollAtUnchecked (&F->MemList, J);
1755
1756                     /* Debugging */
1757                     Print (stdout, 2, "Skipping `%s'...\n", GetString (M->Name));
1758
1759                     /* Walk throught the segments */
1760                     N = M->SegList;
1761                     while (N) {
1762                         if (N->Seg->Load == M) {
1763                             /* Load area - mark the segment as dumped */
1764                             N->Seg->Seg->Dumped = 1;
1765                         }
1766
1767                         /* Next segment node */
1768                         N = N->Next;
1769                     }
1770                 }
1771             }
1772         }
1773     }
1774 }
1775
1776
1777