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