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