]> git.sur5r.net Git - cc65/blob - src/sim65/config.c
Added gcc attributes
[cc65] / src / sim65 / config.c
1 /*****************************************************************************/
2 /*                                                                           */
3 /*                                 config.c                                  */
4 /*                                                                           */
5 /*            Configuration file parsing for the sim65 6502 simulator        */
6 /*                                                                           */
7 /*                                                                           */
8 /*                                                                           */
9 /* (C) 1998-2003 Ullrich von Bassewitz                                       */
10 /*               Römerstrasse 52                                             */
11 /*               D-70794 Filderstadt                                         */
12 /* EMail:        uz@cc65.org                                                 */
13 /*                                                                           */
14 /*                                                                           */
15 /* This software is provided 'as-is', without any expressed or implied       */
16 /* warranty.  In no event will the authors be held liable for any damages    */
17 /* arising from the use of this software.                                    */
18 /*                                                                           */
19 /* Permission is granted to anyone to use this software for any purpose,     */
20 /* including commercial applications, and to alter it and redistribute it    */
21 /* freely, subject to the following restrictions:                            */
22 /*                                                                           */
23 /* 1. The origin of this software must not be misrepresented; you must not   */
24 /*    claim that you wrote the original software. If you use this software   */
25 /*    in a product, an acknowledgment in the product documentation would be  */
26 /*    appreciated but is not required.                                       */
27 /* 2. Altered source versions must be plainly marked as such, and must not   */
28 /*    be misrepresented as being the original software.                      */
29 /* 3. This notice may not be removed or altered from any source              */
30 /*    distribution.                                                          */
31 /*                                                                           */
32 /*****************************************************************************/
33
34
35
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <string.h>
39 #include <errno.h>
40
41 /* common */
42 #include "check.h"
43 #include "bitops.h"
44 #include "print.h"
45 #include "strutil.h"
46 #include "xmalloc.h"
47
48 /* sim65 */
49 #include "cfgdata.h"
50 #include "chip.h"
51 #include "error.h"
52 #include "global.h"
53 #include "memory.h"
54 #include "location.h"
55 #include "scanner.h"
56 #include "config.h"
57
58
59
60 /*****************************************************************************/
61 /*                                   Code                                    */
62 /*****************************************************************************/
63
64
65
66 static void FlagAttr (unsigned* Flags, unsigned Mask, const char* Name)
67 /* Check if the item is already defined. Print an error if so. If not, set
68  * the marker that we have a definition now.
69  */
70 {
71     if (*Flags & Mask) {
72         CfgError ("%s is already defined", Name);
73     }
74     *Flags |= Mask;
75 }
76
77
78
79 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
80 /* Check that a mandatory attribute was given */
81 {
82     if ((Attr & Mask) == 0) {
83         CfgError ("%s attribute is missing", Name);
84     }
85 }
86
87
88
89 static void ParseCPU (void)
90 /* Parse a CPU section */
91 {
92     static const IdentTok Attributes [] = {
93         {   "TYPE",             CFGTOK_TYPE             },
94         {   "ADDRSPACE",        CFGTOK_ADDRSPACE        },
95     };
96
97     enum {
98         atNone      = 0x0000,
99         atType      = 0x0001,
100         atAddrSpace = 0x0002
101     };
102     unsigned Attr = 0;
103     unsigned long Size = 0;
104
105
106     while (CfgTok == CFGTOK_IDENT) {
107
108         cfgtok_t AttrTok;
109         CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
110         AttrTok = CfgTok;
111
112         /* An optional assignment follows */
113         CfgNextTok ();
114         CfgOptionalAssign ();
115
116         /* Check which attribute was given */
117         switch (AttrTok) {
118
119             case CFGTOK_TYPE:
120                 FlagAttr (&Attr, atType, "TYPE");
121                 CfgAssureIdent ();
122                 /* ### */
123                 break;
124
125             case CFGTOK_ADDRSPACE:
126                 FlagAttr (&Attr, atAddrSpace, "ADDRSPACE");
127                 CfgAssureInt ();
128                 CfgRangeCheck (0x1000, 0x1000000);
129                 Size = CfgIVal;
130                 break;
131
132             default:
133                 FAIL ("Unexpected attribute token");
134
135         }
136
137         /* Skip the attribute value and an optional comma */
138         CfgNextTok ();
139         CfgOptionalComma ();
140     }
141
142     /* Must have some attributes */
143     AttrCheck (Attr, atType, "TYPE");
144     AttrCheck (Attr, atAddrSpace, "ADDRSPACE");
145
146     /* Skip the semicolon */
147     CfgConsumeSemi ();
148 }
149
150
151
152 static void ParseMemory (void)
153 /* Parse a MEMORY section */
154 {
155     unsigned I;
156
157
158     while (CfgTok == CFGTOK_INTCON) {
159
160         Location* L;
161
162         /* Remember the start address and skip it */
163         unsigned long Start = CfgIVal;
164         CfgNextTok ();
165
166         /* .. must follow */
167         CfgConsume (CFGTOK_DOTDOT, "`..' expected");
168
169         /* End address must follow and must be greater than start */
170         CfgAssureInt ();
171         if (CfgIVal < Start) {
172             CfgError ("Start address must be greater than end address");
173         }
174
175         /* Create a new location and add it to the list */
176         L = NewLocation (Start, CfgIVal);
177         CollAppend (&Locations, L);
178
179         /* Skip the end address and the following colon */
180         CfgNextTok ();
181         CfgConsumeColon ();
182
183         /* Parse attributes terminated by a semicolon */
184         while (CfgTok == CFGTOK_IDENT) {
185
186             /* Generate a new attribute with the given name, then skip it */
187             CfgData* D = NewCfgData ();
188             CfgNextTok ();
189
190             /* An optional assignment follows */
191             CfgOptionalAssign ();
192
193             /* Check and assign the attribute value */
194             switch (CfgTok) {
195
196                 case CFGTOK_INTCON:
197                     D->Type   = CfgDataNumber;
198                     D->V.IVal = CfgIVal;
199                     break;
200
201                 case CFGTOK_STRCON:
202                     D->Type   = CfgDataString;
203                     D->V.SVal = xstrdup (CfgSVal);
204                     break;
205
206                 case CFGTOK_IDENT:
207                     D->Type   = CfgDataId;
208                     D->V.SVal = xstrdup (CfgSVal);
209                     break;
210
211                 default:
212                     CfgError ("Invalid attribute type");
213             }
214
215             /* Add the attribute to the location */
216             CollAppend (&L->Attributes, D);
217
218             /* Skip the attribute value and an optional comma */
219             CfgNextTok ();
220             CfgOptionalComma ();
221         }
222
223         /* Skip the semicolon */
224         CfgConsumeSemi ();
225     }
226
227     /* Sort all memory locations */
228     LocationSort (&Locations);
229
230     /* Check the locations for overlaps and other problems */
231     LocationCheck (&Locations);
232
233     /* Now create the chip instances. Since we can only mirror existing chips,
234      * we will first create all real chips and the mirrors in a second run.
235      */
236     for (I = 0; I < CollCount (&Locations); ++I) {
237
238         int Index;
239         CfgData* D;
240         unsigned Range;         /* Address range for this chip */
241         ChipInstance* CI;
242
243         /* Get this location */
244         Location* L = CollAtUnchecked (&Locations, I);
245
246         /* Skip mirrors */
247         if (LocationIsMirror (L)) {
248             continue;
249         }
250
251         /* The chip must have an attribute "name" of type string */
252         Index = LocationGetAttr (L, "name");
253         D = CollAt (&L->Attributes, Index);
254         CfgDataCheckType (D, CfgDataString);
255
256         /* Remove the "name" attribute from the attribute list */
257         CollDelete (&L->Attributes, Index);
258
259         /* Create the chip instance for the address range */
260         Range = L->End - L->Start + 1;
261         CI = NewChipInstance (D->V.SVal, L->Start, Range, &L->Attributes);
262
263         /* Delete the "name" attribute */
264         FreeCfgData (D);
265
266         /* Assign the chip instance to memory */
267         MemAssignChip (CI, L->Start, Range);
268     }
269
270     /* Create the mirrors */
271     for (I = 0; I < CollCount (&Locations); ++I) {
272
273         const CfgData* D;
274         unsigned MirrorAddr;    /* Mirror address */
275         unsigned Range;         /* Address range for this chip */
276         unsigned Offs;          /* Offset of the mirror */
277         const ChipInstance* CI; /* Original chip instance */
278         ChipInstance* MCI;      /* Mirrored chip instance */
279
280         /* Get this location */
281         const Location* L = CollAtUnchecked (&Locations, I);
282
283         /* Skip non mirrors */
284         if (!LocationIsMirror (L)) {
285             continue;
286         }
287
288         /* Calculate the address range */
289         Range = L->End - L->Start;
290
291         /* Get the mirror address */
292         D = CollConstAt (&L->Attributes, 0);
293         MirrorAddr = (unsigned) D->V.IVal;
294
295         /* For simplicity, get the chip instance we're mirroring from the
296          * memory, instead of searching for the range in the list.
297          */
298         CI = MemGetChip (MirrorAddr);
299         if (CI == 0) {
300             /* We are mirroring an unassigned address */
301             Error ("%s(%u): Mirroring an unassigned address",
302                    CfgGetName (), L->Line);
303         }
304
305         /* Make sure we're mirroring the correct chip */
306         CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
307
308         /* Calculate the offset of the mirror */
309         Offs = MirrorAddr - CI->Addr;
310
311         /* Check if the mirror range is ok */
312         if (Offs + Range > CI->Size) {
313             Error ("%s(%u): Mirror range is too large", CfgGetName (), L->Line);
314         }
315
316         /* Clone the chip instance for the new location */
317         MCI = MirrorChipInstance (CI, L->Start - Offs);
318
319         /* Assign the chip instance to memory */
320         MemAssignChip (MCI, L->Start, Range);
321     }
322 }
323
324
325
326 static void ParseConfig (void)
327 /* Parse the config file */
328 {
329     static const IdentTok BlockNames [] = {
330         {   "CPU",      CFGTOK_CPU      },
331         {   "MEMORY",   CFGTOK_MEMORY   },
332     };
333     cfgtok_t BlockTok;
334
335     do {
336
337         /* Read the block ident */
338         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
339         BlockTok = CfgTok;
340         CfgNextTok ();
341
342         /* Expected a curly brace */
343         CfgConsume (CFGTOK_LCURLY, "`{' expected");
344
345         /* Read the block */
346         switch (BlockTok) {
347
348             case CFGTOK_CPU:
349                 ParseCPU ();
350                 break;
351
352             case CFGTOK_MEMORY:
353                 ParseMemory ();
354                 break;
355
356             default:
357                 FAIL ("Unexpected block token");
358
359         }
360
361         /* Skip closing brace */
362         CfgConsumeRCurly ();
363
364     } while (CfgTok != CFGTOK_EOF);
365 }
366
367
368
369 void CfgRead (void)
370 /* Read the configuration */
371 {
372     /* If we have a config name given, open the file, otherwise we will read
373      * from a buffer.
374      */
375     CfgOpenInput ();
376
377     /* Parse the file */
378     ParseConfig ();
379
380     /* Close the input file */
381     CfgCloseInput ();
382 }
383
384
385