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