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