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