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