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