]> git.sur5r.net Git - cc65/blob - src/ld65/config.c
Fix problematic code. Use more stuff from the shared modules.
[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-2000 Ullrich von Bassewitz                                       */
10 /*               Wacholderweg 14                                             */
11 /*               D-70597 Stuttgart                                           */
12 /* EMail:        uz@musoftware.de                                            */
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 #include "../common/bitops.h"
42 #include "../common/xmalloc.h"
43
44 #include "error.h"
45 #include "global.h"
46 #include "bin.h"
47 #include "o65.h"
48 #include "binfmt.h"
49 #include "exports.h"
50 #include "scanner.h"
51 #include "config.h"
52
53
54
55 /*****************************************************************************/
56 /*                                   Data                                    */
57 /*****************************************************************************/
58
59
60
61 /* File list */
62 static File*            FileList;       /* Single linked list */
63 static unsigned         FileCount;      /* Number of entries in the list */
64
65
66
67 /* Memory list */
68 static Memory*          MemoryList;     /* Single linked list */
69 static Memory*          MemoryLast;     /* Last element in list */
70 static unsigned         MemoryCount;    /* Number of entries in the list */
71
72 /* Memory attributes */
73 #define MA_START        0x0001
74 #define MA_SIZE         0x0002
75 #define MA_TYPE         0x0004
76 #define MA_FILE         0x0008
77 #define MA_DEFINE       0x0010
78 #define MA_FILL         0x0020
79 #define MA_FILLVAL      0x0040
80
81
82
83 /* Segment list */
84 SegDesc*                SegDescList;    /* Single linked list */
85 unsigned                SegDescCount;   /* Number of entries in list */
86
87 /* Segment attributes */
88 #define SA_TYPE         0x0001
89 #define SA_LOAD         0x0002
90 #define SA_RUN          0x0004
91 #define SA_ALIGN        0x0008
92 #define SA_DEFINE       0x0010
93 #define SA_OFFSET       0x0020
94 #define SA_START        0x0040
95
96
97
98 /* Descriptor holding information about the binary formats */
99 static BinDesc* BinFmtDesc      = 0;
100 static O65Desc* O65FmtDesc      = 0;
101
102 /* Attributes for the o65 format */
103 static unsigned O65Attr = 0;
104 #define OA_OS           0x0001
105 #define OA_TYPE         0x0002
106 #define OA_VERSION      0x0004
107 #define OA_OSVERSION    0x0008
108 #define OA_TEXT         0x0010
109 #define OA_DATA         0x0020
110 #define OA_BSS          0x0040
111 #define OA_ZP           0x0080
112
113
114
115 /*****************************************************************************/
116 /*                         Constructors/Destructors                          */
117 /*****************************************************************************/
118
119
120
121 static File* NewFile (const char* Name)
122 /* Create a new file descriptor and insert it into the list */
123 {
124     /* Get the length of the name */
125     unsigned Len = strlen (Name);
126
127     /* Allocate memory */
128     File* F = xmalloc (sizeof (File) + Len);
129
130     /* Initialize the fields */
131     F->Flags   = 0;
132     F->Format  = BINFMT_DEFAULT;
133     F->MemList = 0;
134     F->MemLast = 0;
135     memcpy (F->Name, Name, Len);
136     F->Name [Len] = '\0';
137
138     /* Insert the struct into the list */
139     F->Next  = FileList;
140     FileList = F;
141     ++FileCount;
142
143     /* ...and return it */
144     return F;
145 }
146
147
148
149 static Memory* NewMemory (const char* Name)
150 /* Create a new memory section and insert it into the list */
151 {
152     /* Get the length of the name */
153     unsigned Len = strlen (Name);
154
155     /* Check for duplicate names */
156     Memory* M = MemoryList;
157     while (M) {
158         if (strcmp (M->Name, Name) == 0) {
159             CfgError ("Memory area `%s' defined twice", Name);
160             break;
161         }
162         M = M->Next;
163     }
164
165     /* Allocate memory */
166     M = xmalloc (sizeof (Memory) + Len);
167
168     /* Initialize the fields */
169     M->Next      = 0;
170     M->FNext     = 0;
171     M->Attr      = 0;
172     M->Flags     = 0;
173     M->Start     = 0;
174     M->Size      = 0;
175     M->FillLevel = 0;
176     M->FillVal   = 0;
177     M->SegList   = 0;
178     M->SegLast   = 0;
179     M->F         = 0;
180     memcpy (M->Name, Name, Len);
181     M->Name [Len] = '\0';
182
183     /* Insert the struct into the list */
184     if (MemoryLast == 0) {
185         /* First element */
186         MemoryList = M;
187     } else {
188         MemoryLast->Next = M;
189     }
190     MemoryLast = M;
191     ++MemoryCount;
192
193     /* ...and return it */
194     return M;
195 }
196
197
198
199 static SegDesc* NewSegDesc (const char* Name)
200 /* Create a segment descriptor */
201 {
202     Segment* Seg;
203
204     /* Get the length of the name */
205     unsigned Len = strlen (Name);
206
207     /* Check for duplicate names */
208     SegDesc* S = SegDescList;
209     while (S) {
210         if (strcmp (S->Name, Name) == 0) {
211             CfgError ("Segment `%s' defined twice", Name);
212             break;
213         }
214         S = S->Next;
215     }
216
217     /* Verify that the given segment does really exist */
218     Seg = SegFind (Name);
219     if (Seg == 0) {
220         CfgWarning ("Segment `%s' does not exist", Name);
221     }
222
223     /* Allocate memory */
224     S = xmalloc (sizeof (SegDesc) + Len);
225
226     /* Initialize the fields */
227     S->Next    = 0;
228     S->Seg     = Seg;
229     S->Attr    = 0;
230     S->Flags   = 0;
231     S->Align   = 0;
232     memcpy (S->Name, Name, Len);
233     S->Name [Len] = '\0';
234
235     /* ...and return it */
236     return S;
237 }
238
239
240
241 static void FreeSegDesc (SegDesc* S)
242 /* Free a segment descriptor */
243 {
244     xfree (S);
245 }
246
247
248
249 /*****************************************************************************/
250 /*                                   Code                                    */
251 /*****************************************************************************/
252
253
254
255 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
256 /* Check if the item is already defined. Print an error if so. If not, set
257  * the marker that we have a definition now.
258  */
259 {
260     if (*Flags & Mask) {
261         CfgError ("%s is already defined", Name);
262     }
263     *Flags |= Mask;
264 }
265
266
267
268 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
269 /* Check that a mandatory attribute was given */
270 {
271     if ((Attr & Mask) == 0) {
272         CfgError ("%s attribute is missing", Name);
273     }
274 }
275
276
277
278 static File* FindFile (const char* Name)
279 /* Find a file with a given name. */
280 {
281     File* F = FileList;
282     while (F) {
283         if (strcmp (F->Name, Name) == 0) {
284             return F;
285         }
286         F = F->Next;
287     }
288     return 0;
289 }
290
291
292
293 static File* GetFile (const char* Name)
294 /* Get a file entry with the given name. Create a new one if needed. */
295 {
296     File* F = FindFile (Name);
297     if (F == 0) {
298         /* Create a new one */
299         F = NewFile (Name);
300     }
301     return F;
302 }
303
304
305
306 static void FileInsert (File* F, Memory* M)
307 /* Insert the memory area into the files list */
308 {
309     M->F = F;
310     if (F->MemList == 0) {
311         /* First entry */
312         F->MemList = M;
313     } else {
314         F->MemLast->FNext = M;
315     }
316     F->MemLast = M;
317 }
318
319
320
321 static void ParseMemory (void)
322 /* Parse a MEMORY section */
323 {
324     static const IdentTok Attributes [] = {
325         {   "START",    CFGTOK_START    },
326         {   "SIZE",     CFGTOK_SIZE     },
327         {   "TYPE",     CFGTOK_TYPE     },
328         {   "FILE",     CFGTOK_FILE     },
329         {   "DEFINE",   CFGTOK_DEFINE   },
330         {   "FILL",     CFGTOK_FILL     },
331         {   "FILLVAL",  CFGTOK_FILLVAL  },
332     };
333     static const IdentTok Types [] = {
334         {   "RO",       CFGTOK_RO       },
335         {   "RW",       CFGTOK_RW       },
336     };
337
338     while (CfgTok == CFGTOK_IDENT) {
339
340         /* Create a new entry on the heap */
341         Memory* M = NewMemory (CfgSVal);
342
343         /* Skip the name and the following colon */
344         CfgNextTok ();
345         CfgConsumeColon ();
346
347         /* Read the attributes */
348         while (CfgTok == CFGTOK_IDENT) {
349
350             /* Map the identifier to a token */
351             unsigned AttrTok;
352             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
353             AttrTok = CfgTok;
354
355             /* An optional assignment follows */
356             CfgNextTok ();
357             CfgOptionalAssign ();
358
359             /* Check which attribute was given */
360             switch (AttrTok) {
361
362                 case CFGTOK_START:
363                     FlagAttr (&M->Attr, MA_START, "START");
364                     CfgAssureInt ();
365                     M->Start = CfgIVal;
366                     break;
367
368                 case CFGTOK_SIZE:
369                     FlagAttr (&M->Attr, MA_SIZE, "SIZE");
370                     CfgAssureInt ();
371                     M->Size = CfgIVal;
372                     break;
373
374                 case CFGTOK_TYPE:
375                     FlagAttr (&M->Attr, MA_TYPE, "TYPE");
376                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
377                     if (CfgTok == CFGTOK_RO) {
378                         M->Flags |= MF_RO;
379                     }
380                     break;
381
382                 case CFGTOK_FILE:
383                     FlagAttr (&M->Attr, MA_FILE, "FILE");
384                     CfgAssureStr ();
385                     /* Get the file entry and insert the memory area */
386                     FileInsert (GetFile (CfgSVal), M);
387                     break;
388
389                 case CFGTOK_DEFINE:
390                     FlagAttr (&M->Attr, MA_DEFINE, "DEFINE");
391                     /* Map the token to a boolean */
392                     CfgBoolToken ();
393                     if (CfgTok == CFGTOK_TRUE) {
394                         M->Flags |= MF_DEFINE;
395                     }
396                     break;
397
398                 case CFGTOK_FILL:
399                     FlagAttr (&M->Attr, MA_FILL, "FILL");
400                     /* Map the token to a boolean */
401                     CfgBoolToken ();
402                     if (CfgTok == CFGTOK_TRUE) {
403                         M->Flags |= MF_FILL;
404                     }
405                     break;
406
407                 case CFGTOK_FILLVAL:
408                     FlagAttr (&M->Attr, MA_FILLVAL, "FILLVAL");
409                     CfgAssureInt ();
410                     CfgRangeCheck (0, 0xFF);
411                     M->FillVal = (unsigned char) CfgIVal;
412                     break;
413
414                 default:
415                     FAIL ("Unexpected attribute token");
416
417             }
418
419             /* Skip the attribute value and an optional comma */
420             CfgNextTok ();
421             CfgOptionalComma ();
422         }
423
424         /* Skip the semicolon */
425         CfgConsumeSemi ();
426
427         /* Check for mandatory parameters */
428         AttrCheck (M->Attr, MA_START, "START");
429         AttrCheck (M->Attr, MA_SIZE, "SIZE");
430
431         /* If we don't have a file name for output given, use the default
432          * file name.
433          */
434         if ((M->Attr & MA_FILE) == 0) {
435             FileInsert (GetFile (OutputName), M);
436         }
437     }
438 }
439
440
441
442 static void ParseFiles (void)
443 /* Parse a FILES section */
444 {
445     static const IdentTok Attributes [] = {
446         {   "FORMAT",   CFGTOK_FORMAT   },
447     };
448     static const IdentTok Formats [] = {
449         {   "O65",      CFGTOK_O65           },
450         {   "BIN",      CFGTOK_BIN      },
451         {   "BINARY",   CFGTOK_BIN      },
452     };
453
454
455     /* Parse all files */
456     while (CfgTok != CFGTOK_RCURLY) {
457
458         File* F;
459
460         /* We expect a string value here */
461         CfgAssureStr ();
462
463         /* Search for the file, it must exist */
464         F = FindFile (CfgSVal);
465         if (F == 0) {
466             CfgError ("No such file: `%s'", CfgSVal);
467         }
468
469         /* Skip the token and the following colon */
470         CfgNextTok ();
471         CfgConsumeColon ();
472
473         /* Read the attributes */
474         while (CfgTok == CFGTOK_IDENT) {
475
476             /* Map the identifier to a token */
477             unsigned AttrTok;
478             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
479             AttrTok = CfgTok;
480
481             /* An optional assignment follows */
482             CfgNextTok ();
483             CfgOptionalAssign ();
484
485             /* Check which attribute was given */
486             switch (AttrTok) {
487
488                 case CFGTOK_FORMAT:
489                     if (F->Format != BINFMT_DEFAULT) {
490                         /* We've set the format already! */
491                         Error ("Cannot set a file format twice");
492                     }
493                     /* Read the format token */
494                     CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
495                     switch (CfgTok) {
496
497                         case CFGTOK_BIN:
498                             F->Format = BINFMT_BINARY;
499                             break;
500
501                         case CFGTOK_O65:
502                             F->Format = BINFMT_O65;
503                             break;
504
505                         default:
506                             Error ("Unexpected format token");
507                     }
508                     break;
509
510                 default:
511                     FAIL ("Unexpected attribute token");
512
513             }
514
515             /* Skip the attribute value and an optional comma */
516             CfgNextTok ();
517             CfgOptionalComma ();
518         }
519
520         /* Skip the semicolon */
521         CfgConsumeSemi ();
522
523     }
524 }
525
526
527
528 static Memory* CfgFindMemory (const char* Name)
529 /* Find the memory are with the given name. Return NULL if not found */
530 {
531     Memory* M = MemoryList;
532     while (M) {
533         if (strcmp (M->Name, Name) == 0) {
534             return M;
535         }
536         M = M->Next;
537     }
538     return 0;
539 }
540
541
542
543 static Memory* CfgGetMemory (const char* Name)
544 /* Find the memory are with the given name. Print an error on an invalid name */
545 {
546     Memory* M = CfgFindMemory (Name);
547     if (M == 0) {
548         CfgError ("Invalid memory area `%s'", Name);
549     }
550     return M;
551 }
552
553
554
555 static void SegDescInsert (SegDesc* S)
556 /* Insert a segment descriptor into the list of segment descriptors */
557 {
558     /* Insert the struct into the list */
559     S->Next = SegDescList;
560     SegDescList = S;
561     ++SegDescCount;
562 }
563
564
565
566 static void MemoryInsert (Memory* M, SegDesc* S)
567 /* Insert the segment descriptor into the memory area list */
568 {
569     /* Create a new node for the entry */
570     MemListNode* N = xmalloc (sizeof (MemListNode));
571     N->Seg  = S;
572     N->Next = 0;
573
574     if (M->SegLast == 0) {
575         /* First entry */
576         M->SegList = N;
577     } else {
578         M->SegLast->Next = N;
579     }
580     M->SegLast = N;
581 }
582
583
584
585 static void ParseSegments (void)
586 /* Parse a SEGMENTS section */
587 {
588     static const IdentTok Attributes [] = {
589         {   "LOAD",     CFGTOK_LOAD     },
590         {   "RUN",      CFGTOK_RUN      },
591         {   "TYPE",     CFGTOK_TYPE     },
592         {   "ALIGN",    CFGTOK_ALIGN    },
593         {   "DEFINE",   CFGTOK_DEFINE   },
594         {   "OFFSET",   CFGTOK_OFFSET   },
595         {   "START",    CFGTOK_START    },
596     };
597     static const IdentTok Types [] = {
598         {   "RO",       CFGTOK_RO       },
599         {   "RW",       CFGTOK_RW       },
600         {   "BSS",      CFGTOK_BSS      },
601         {   "ZP",       CFGTOK_ZP       },
602         {   "WP",       CFGTOK_WPROT    },
603         {   "WPROT",    CFGTOK_WPROT    },
604     };
605
606     unsigned Count;
607
608     while (CfgTok == CFGTOK_IDENT) {
609
610         SegDesc* S;
611
612         /* Create a new entry on the heap */
613         S = NewSegDesc (CfgSVal);
614
615         /* Skip the name and the following colon */
616         CfgNextTok ();
617         CfgConsumeColon ();
618
619         /* Read the attributes */
620         while (CfgTok == CFGTOK_IDENT) {
621
622             /* Map the identifier to a token */
623             unsigned AttrTok;
624             CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
625             AttrTok = CfgTok;
626
627             /* An optional assignment follows */
628             CfgNextTok ();
629             CfgOptionalAssign ();
630
631             /* Check which attribute was given */
632             switch (AttrTok) {
633
634                 case CFGTOK_LOAD:
635                     FlagAttr (&S->Attr, SA_LOAD, "LOAD");
636                     S->Load = CfgGetMemory (CfgSVal);
637                     break;
638
639                 case CFGTOK_RUN:
640                     FlagAttr (&S->Attr, SA_RUN, "RUN");
641                     S->Run = CfgGetMemory (CfgSVal);
642                     break;
643
644                 case CFGTOK_TYPE:
645                     FlagAttr (&S->Attr, SA_TYPE, "TYPE");
646                     CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
647                     switch (CfgTok) {
648                         case CFGTOK_RO:    S->Flags |= SF_RO;               break;
649                         case CFGTOK_BSS:   S->Flags |= SF_BSS;              break;
650                         case CFGTOK_ZP:    S->Flags |= (SF_BSS | SF_ZP);    break;
651                         case CFGTOK_WPROT: S->Flags |= (SF_RO | SF_WPROT);  break;
652                     }
653                     break;
654
655                 case CFGTOK_ALIGN:
656                     CfgAssureInt ();
657                     FlagAttr (&S->Attr, SA_ALIGN, "ALIGN");
658                     CfgRangeCheck (1, 0x10000);
659                     S->Align = BitFind (CfgIVal);
660                     if ((0x01UL << S->Align) != CfgIVal) {
661                         CfgError ("Alignment must be a power of 2");
662                     }
663                     S->Flags |= SF_ALIGN;
664                     break;
665
666                 case CFGTOK_DEFINE:
667                     FlagAttr (&S->Attr, SA_DEFINE, "DEFINE");
668                     /* Map the token to a boolean */
669                     CfgBoolToken ();
670                     if (CfgTok == CFGTOK_TRUE) {
671                         S->Flags |= SF_DEFINE;
672                     }
673                     break;
674
675                 case CFGTOK_OFFSET:
676                     CfgAssureInt ();
677                     FlagAttr (&S->Attr, SA_OFFSET, "OFFSET");
678                     CfgRangeCheck (1, 0x1000000);
679                     S->Addr   = CfgIVal;
680                     S->Flags |= SF_OFFSET;
681                     break;
682
683                 case CFGTOK_START:
684                     CfgAssureInt ();
685                     FlagAttr (&S->Attr, SA_START, "START");
686                     CfgRangeCheck (1, 0x1000000);
687                     S->Addr   = CfgIVal;
688                     S->Flags |= SF_START;
689                     break;
690
691                 default:
692                     FAIL ("Unexpected attribute token");
693
694             }
695
696             /* Skip the attribute value and an optional comma */
697             CfgNextTok ();
698             CfgOptionalComma ();
699         }
700
701         /* Skip the semicolon */
702         CfgConsumeSemi ();
703
704         /* Check for mandatory parameters */
705         AttrCheck (S->Attr, SA_LOAD, "LOAD");
706
707         /* Set defaults for stuff not given */
708         if ((S->Attr & SA_RUN) == 0) {
709             S->Attr |= SA_RUN;
710             S->Run = S->Load;
711         } else {
712             /* Both attributes given */
713             S->Flags |= SF_LOAD_AND_RUN;
714         }
715         if ((S->Attr & SA_ALIGN) == 0) {
716             S->Attr |= SA_ALIGN;
717             S->Align = 0;
718         }
719
720         /* If the segment is marked as BSS style, check that there's no
721          * initialized data in the segment.
722          */
723         if ((S->Flags & SF_BSS) != 0 && !IsBSSType (S->Seg)) {
724             Warning ("%s(%u): Segment with type `bss' contains initialized data",
725                      CfgGetName (), CfgErrorLine);
726         }
727
728         /* Don't allow read/write data to be put into a readonly area */
729         if ((S->Flags & SF_RO) == 0) {
730             if (S->Run->Flags & MF_RO) {
731                 CfgError ("Cannot put r/w segment `%s' in r/o memory area `%s'",
732                           S->Name, S->Run->Name);
733             }
734         }
735
736         /* Only one of ALIGN, START and OFFSET may be used */
737         Count = ((S->Flags & SF_ALIGN)  != 0) +
738                 ((S->Flags & SF_OFFSET) != 0) +
739                 ((S->Flags & SF_START)  != 0);
740         if (Count > 1) {
741             CfgError ("Only one of ALIGN, START, OFFSET may be used");
742         }
743
744         /* If this segment does exist in any of the object files, insert the
745          * descriptor into the list of segment descriptors. Otherwise discard
746          * it silently, because the segment pointer in the descriptor is
747          * invalid.
748          */
749         if (S->Seg != 0) {
750             /* Insert the descriptor into the list of all descriptors */
751             SegDescInsert (S);
752             /* Insert the segment into the memory area list */
753             MemoryInsert (S->Run, S);
754             if ((S->Flags & SF_LOAD_AND_RUN) != 0) {
755                 /* We have a separate RUN area given */
756                 MemoryInsert (S->Load, S);
757             }
758         } else {
759             /* Segment does not exist, discard the descriptor */
760             FreeSegDesc (S);
761         }
762     }
763 }
764
765
766
767 static void ParseO65 (void)
768 /* Parse the o65 format section */
769 {
770     static const IdentTok Attributes [] = {
771         {   "EXPORT",    CFGTOK_EXPORT          },
772         {   "IMPORT",    CFGTOK_IMPORT          },
773         {   "TYPE",      CFGTOK_TYPE            },
774         {   "OS",        CFGTOK_OS              },
775     };
776     static const IdentTok Types [] = {
777         {   "SMALL",     CFGTOK_SMALL           },
778         {   "LARGE",     CFGTOK_LARGE           },
779     };
780     static const IdentTok OperatingSystems [] = {
781         {   "LUNIX",     CFGTOK_LUNIX           },
782         {   "OSA65",     CFGTOK_OSA65           },
783     };
784
785     while (CfgTok == CFGTOK_IDENT) {
786
787         /* Map the identifier to a token */
788         unsigned AttrTok;
789         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
790         AttrTok = CfgTok;
791
792         /* An optional assignment follows */
793         CfgNextTok ();
794         CfgOptionalAssign ();
795
796         /* Check which attribute was given */
797         switch (AttrTok) {
798
799             case CFGTOK_EXPORT:
800                 /* We expect an identifier */
801                 CfgAssureIdent ();
802                 /* Check if we have this symbol defined already. The entry
803                  * routine will check this also, but we get a more verbose
804                  * error message when checking it here.
805                  */
806                 if (O65GetExport (O65FmtDesc, CfgSVal) != 0) {
807                     CfgError ("Duplicate exported symbol: `%s'", CfgSVal);
808                 }
809                 /* Insert the symbol into the table */
810                 O65SetExport (O65FmtDesc, CfgSVal);
811                 break;
812
813             case CFGTOK_IMPORT:
814                 /* We expect an identifier */
815                 CfgAssureIdent ();
816                 /* Check if we have this symbol defined already. The entry
817                  * routine will check this also, but we get a more verbose
818                  * error message when checking it here.
819                  */
820                 if (O65GetImport (O65FmtDesc, CfgSVal) != 0) {
821                     CfgError ("Duplicate imported symbol: `%s'", CfgSVal);
822                 }
823                 /* Insert the symbol into the table */
824                 O65SetImport (O65FmtDesc, CfgSVal);
825                 break;
826
827             case CFGTOK_TYPE:
828                 /* Cannot have this attribute twice */
829                 FlagAttr (&O65Attr, OA_TYPE, "TYPE");
830                 /* Get the type of the executable */
831                 CfgSpecialToken (Types, ENTRY_COUNT (Types), "Type");
832                 switch (CfgTok) {
833
834                     case CFGTOK_SMALL:
835                         /* Default, nothing to do */
836                         break;
837
838                     case CFGTOK_LARGE:
839                         O65SetLargeModel (O65FmtDesc);
840                         break;
841
842                     default:
843                         Error ("Unexpected type token");
844                 }
845                 break;
846
847             case CFGTOK_OS:
848                 /* Cannot use this attribute twice */
849                 FlagAttr (&O65Attr, OA_OS, "OS");
850                 /* Get the operating system */
851                 CfgSpecialToken (OperatingSystems, ENTRY_COUNT (OperatingSystems), "OS type");
852                 switch (CfgTok) {
853
854                     case CFGTOK_LUNIX:
855                         O65SetOS (O65FmtDesc, O65OS_LUNIX);
856                         break;
857
858                     case CFGTOK_OSA65:
859                         O65SetOS (O65FmtDesc, O65OS_OSA65);
860                         break;
861
862                     default:
863                         Error ("Unexpected OS token");
864                 }
865                 break;
866
867             default:
868                 FAIL ("Unexpected attribute token");
869
870         }
871
872         /* Skip the attribute value and an optional comma */
873         CfgNextTok ();
874         CfgOptionalComma ();
875     }
876 }
877
878
879
880 static void ParseFormats (void)
881 /* Parse a target format section */
882 {
883     static const IdentTok Formats [] = {
884         {   "O65",      CFGTOK_O65      },
885         {   "BIN",      CFGTOK_BIN      },
886         {   "BINARY",   CFGTOK_BIN      },
887     };
888
889     while (CfgTok == CFGTOK_IDENT) {
890
891         /* Map the identifier to a token */
892         unsigned FormatTok;
893         CfgSpecialToken (Formats, ENTRY_COUNT (Formats), "Format");
894         FormatTok = CfgTok;
895
896         /* Skip the name and the following colon */
897         CfgNextTok ();
898         CfgConsumeColon ();
899
900         /* Parse the format options */
901         switch (FormatTok) {
902
903             case CFGTOK_O65:
904                 ParseO65 ();
905                 break;
906
907             case CFGTOK_BIN:
908                 /* No attribibutes available */
909                 break;
910
911             default:
912                 Error ("Unexpected format token");
913         }
914
915         /* Skip the semicolon */
916         CfgConsumeSemi ();
917     }
918 }
919
920
921
922 static void ParseConfig (void)
923 /* Parse the config file */
924 {
925     static const IdentTok BlockNames [] = {
926         {   "MEMORY",   CFGTOK_MEMORY    },
927         {   "FILES",    CFGTOK_FILES     },
928         {   "SEGMENTS", CFGTOK_SEGMENTS  },
929         {   "FORMATS",  CFGTOK_FORMATS   },
930     };
931     unsigned BlockTok;
932
933     do {
934
935         /* Read the block ident */
936         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
937         BlockTok = CfgTok;
938         CfgNextTok ();
939
940         /* Expected a curly brace */
941         CfgConsume (CFGTOK_LCURLY, "`{' expected");
942
943         /* Read the block */
944         switch (BlockTok) {
945
946             case CFGTOK_MEMORY:
947                 ParseMemory ();
948                 break;
949
950             case CFGTOK_FILES:
951                 ParseFiles ();
952                 break;
953
954             case CFGTOK_SEGMENTS:
955                 ParseSegments ();
956                 break;
957
958             case CFGTOK_FORMATS:
959                 ParseFormats ();
960                 break;
961
962             default:
963                 FAIL ("Unexpected block token");
964
965         }
966
967         /* Skip closing brace */
968         CfgConsume (CFGTOK_RCURLY, "`}' expected");
969
970     } while (CfgTok != CFGTOK_EOF);
971 }
972
973
974
975 void CfgRead (void)
976 /* Read the configuration */
977 {
978     /* Create the descriptors for the binary formats */
979     BinFmtDesc = NewBinDesc ();
980     O65FmtDesc = NewO65Desc ();
981
982     /* If we have a config name given, open the file, otherwise we will read
983      * from a buffer.
984      */
985     CfgOpenInput ();
986
987     /* Parse the file */
988     ParseConfig ();
989
990     /* Close the input file */
991     CfgCloseInput ();
992 }
993
994
995
996 static void CreateRunDefines (Memory* M, SegDesc* S, unsigned long Addr)
997 /* Create the defines for a RUN segment */
998 {
999     char Buf [256];
1000
1001     sprintf (Buf, "__%s_RUN__", S->Name);
1002     CreateMemExport (Buf, M, Addr - M->Start);
1003     sprintf (Buf, "__%s_SIZE__", S->Name);
1004     CreateConstExport (Buf, S->Seg->Size);
1005     S->Flags |= SF_RUN_DEF;
1006 }
1007
1008
1009
1010 static void CreateLoadDefines (Memory* M, SegDesc* S, unsigned long Addr)
1011 /* Create the defines for a LOAD segment */
1012 {
1013     char Buf [256];
1014
1015     sprintf (Buf, "__%s_LOAD__", S->Name);
1016     CreateMemExport (Buf, M, Addr - M->Start);
1017     S->Flags |= SF_LOAD_DEF;
1018 }
1019
1020
1021
1022 void CfgAssignSegments (void)
1023 /* Assign segments, define linker symbols where requested */
1024 {
1025     /* Walk through each of the memory sections. Add up the sizes and check
1026      * for an overflow of the section. Assign the start addresses of the
1027      * segments while doing this.
1028      */
1029     Memory* M = MemoryList;
1030     while (M) {
1031
1032         /* Get the start address of this memory area */
1033         unsigned long Addr = M->Start;
1034
1035         /* Walk through the segments in this memory area */
1036         MemListNode* N = M->SegList;
1037         while (N) {
1038
1039             /* Get the segment from the node */
1040             SegDesc* S = N->Seg;
1041
1042             /* Handle ALIGN and OFFSET/START */
1043             if (S->Flags & SF_ALIGN) {
1044                 /* Align the address */
1045                 unsigned long Val = (0x01UL << S->Align) - 1;
1046                 Addr = (Addr + Val) & ~Val;
1047             } else if (S->Flags & (SF_OFFSET | SF_START)) {
1048                 /* Give the segment a fixed starting address */
1049                 unsigned long NewAddr = S->Addr;
1050                 if (S->Flags & SF_OFFSET) {
1051                     /* An offset was given, no address, make an address */
1052                     NewAddr += M->Start;
1053                 }
1054                 if (Addr > NewAddr) {
1055                     /* Offset already too large */
1056                     if (S->Flags & SF_OFFSET) {
1057                         Error ("Offset too small in `%s', segment `%s'",
1058                                M->Name, S->Name);
1059                     } else {
1060                         Error ("Start address too low in `%s', segment `%s'",
1061                                M->Name, S->Name);
1062                     }
1063                 }
1064                 Addr = NewAddr;
1065             }
1066
1067             /* If this is the run area, set the start address of this segment */
1068             if (S->Run == M) {
1069                 S->Seg->PC = Addr;
1070             }
1071
1072             /* Increment the fill level of the memory area and check for an
1073              * overflow.
1074              */
1075             M->FillLevel = Addr + S->Seg->Size - M->Start;
1076             if (M->FillLevel > M->Size) {
1077                 Error ("Memory area overflow in `%s', segment `%s' (%lu bytes)",
1078                        M->Name, S->Name, M->FillLevel - M->Size);
1079             }
1080
1081             /* If requested, define symbols for the start and size of the
1082              * segment.
1083              */
1084             if (S->Flags & SF_DEFINE) {
1085                 if ((S->Flags & SF_LOAD_AND_RUN) && S->Run == S->Load) {
1086                     /* RUN and LOAD given and in one memory area.
1087                      * Be careful: We will encounter this code twice, the
1088                      * first time when walking the RUN list, second time when
1089                      * walking the LOAD list. Be sure to define only the
1090                      * relevant symbols on each walk.
1091                      */
1092                     if (S->Load == M) {
1093                         if ((S->Flags & SF_LOAD_DEF) == 0) {
1094                             CreateLoadDefines (M, S, Addr);
1095                         } else {
1096                             CHECK ((S->Flags & SF_RUN_DEF) == 0);
1097                             CreateRunDefines (M, S, Addr);
1098                         }
1099                     }
1100                 } else {
1101                     /* RUN and LOAD in different memory areas, or RUN not
1102                      * given, so RUN defaults to LOAD. In the latter case, we
1103                      * have only one copy of the segment in the area.
1104                      */
1105                     if (S->Run == M) {
1106                         CreateRunDefines (M, S, Addr);
1107                     }
1108                     if (S->Load == M) {
1109                         CreateLoadDefines (M, S, Addr);
1110                     }
1111                 }
1112             }
1113
1114             /* Calculate the new address */
1115             Addr += S->Seg->Size;
1116
1117             /* Next segment */
1118             N = N->Next;
1119         }
1120
1121         /* If requested, define symbols for start and size of the memory area */
1122         if (M->Flags & MF_DEFINE) {
1123             char Buf [256];
1124             sprintf (Buf, "__%s_START__", M->Name);
1125             CreateMemExport (Buf, M, 0);
1126             sprintf (Buf, "__%s_SIZE__", M->Name);
1127             CreateConstExport (Buf, M->Size);
1128             sprintf (Buf, "__%s_LAST__", M->Name);
1129             CreateConstExport (Buf, M->FillLevel);
1130         }
1131
1132         /* Next memory area */
1133         M = M->Next;
1134     }
1135 }
1136
1137
1138
1139 void CfgWriteTarget (void)
1140 /* Write the target file(s) */
1141 {
1142     Memory* M;
1143
1144     /* Walk through the files list */
1145     File* F = FileList;
1146     while (F) {
1147         /* We don't need to look at files with no memory areas */
1148         if (F->MemList) {
1149
1150             /* Is there an output file? */
1151             if (strlen (F->Name) > 0) {
1152
1153                 /* Assign a proper binary format */
1154                 if (F->Format == BINFMT_DEFAULT) {
1155                     F->Format = DefaultBinFmt;
1156                 }
1157
1158                 /* Call the apropriate routine for the binary format */
1159                 switch (F->Format) {
1160
1161                     case BINFMT_BINARY:
1162                         BinWriteTarget (BinFmtDesc, F);
1163                         break;
1164
1165                     case BINFMT_O65:
1166                         O65WriteTarget (O65FmtDesc, F);
1167                         break;
1168
1169                     default:
1170                         Internal ("Invalid binary format: %u", F->Format);
1171
1172                 }
1173
1174             } else {
1175
1176                 /* No output file. Walk through the list and mark all segments
1177                  * assigned to the memory areas in this file as dumped.
1178                  */
1179                 M = F->MemList;
1180                 while (M) {
1181                     /* Walk throught the segments */
1182                     MemListNode* N = M->SegList;
1183                     while (N) {
1184                         /* Mark the segment as dumped */
1185                         N->Seg->Seg->Dumped = 1;
1186
1187                         /* Next segment node */
1188                         N = N->Next;
1189                     }
1190                     /* Next memory area */
1191                     M = M->FNext;
1192                 }
1193             }
1194         }
1195
1196         /* Next file */
1197         F = F->Next;
1198     }
1199 }
1200
1201
1202