]> git.sur5r.net Git - cc65/blob - src/sim65/config.c
Working
[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 "scanner.h"
55 #include "config.h"
56
57
58
59 /*****************************************************************************/
60 /*                                   Data                                    */
61 /*****************************************************************************/
62
63
64
65 /* List of all memory locations */
66 static Collection Locations;
67
68 /* One memory location */
69 typedef struct Location Location;
70 struct Location {
71     unsigned    Start;          /* Start of memory location */
72     unsigned    End;            /* End memory location */
73     Collection  Attributes;     /* Attributes given */
74     unsigned    Line;           /* Line in config file */
75     unsigned    Col;            /* Column in config file */
76 };
77
78
79
80 /*****************************************************************************/
81 /*                              struct CfgData                               */
82 /*****************************************************************************/
83
84
85
86 static void CfgDataCheckType (const CfgData* D, unsigned Type)
87 /* Check the config data type */
88 {
89     if (D->Type != Type) {
90         Error ("%s(%u): Attribute `%s' has invalid type",
91                CfgGetName (), D->Line, D->Attr);
92     }
93 }
94
95
96
97 /*****************************************************************************/
98 /*                              struct Location                              */
99 /*****************************************************************************/
100
101
102
103 static Location* NewLocation (unsigned long Start, unsigned long End)
104 /* Create a new location, initialize and return it */
105 {
106     /* Allocate memory */
107     Location* L = xmalloc (sizeof (Location));
108
109     /* Initialize the fields */
110     L->Start      = Start;
111     L->End        = End;
112     L->Attributes = EmptyCollection;
113     L->Line       = CfgErrorLine;
114     L->Col        = CfgErrorCol;
115
116     /* Return the new struct */
117     return L;
118 }
119
120
121
122 static int CmpLocations (void* Data attribute ((unused)),
123                          const void* lhs, const void* rhs)
124 /* Compare function for CollSort */
125 {
126     /* Cast the object pointers */
127     const Location* Left  = (const Location*) rhs;
128     const Location* Right = (const Location*) lhs;
129
130     /* Do the compare */
131     if (Left->Start < Right->Start) {
132         return 1;
133     } else if (Left->Start > Right->Start) {
134         return -1;
135     } else {
136         return 0;
137     }
138 }
139
140
141
142 static int LocationGetAttr (const Location* L, const char* AttrName)
143 /* Find the attribute with the given name and return it. Call Error() if the
144  * attribute was not found.
145  */
146 {
147     int I = CfgDataFind (&L->Attributes, AttrName);
148     if (I < 0) {
149         Error ("%s(%u): Attribute `%s' missing", CfgGetName(), L->Line, AttrName);
150     }
151     return I;
152 }
153
154
155
156 static int LocationIsMirror (const Location* L)
157 /* Return true if the given location is a mirror of another one. */
158 {
159     /* Find the "mirror" attribute */
160     return (CfgDataFind (&L->Attributes, "mirror") >= 0);
161 }
162
163
164
165 /*****************************************************************************/
166 /*                                   Code                                    */
167 /*****************************************************************************/
168
169
170
171 static void ParseMemory (void)
172 /* Parse a MEMORY section */
173 {
174     unsigned I;
175     const Location* Last;
176
177
178     while (CfgTok == CFGTOK_INTCON) {
179
180         Location* L;
181
182         /* Remember the start address and skip it */
183         unsigned long Start = CfgIVal;
184         CfgNextTok ();
185
186         /* .. must follow */
187         CfgConsume (CFGTOK_DOTDOT, "`..' expected");
188
189         /* End address must follow and must be greater than start */
190         CfgAssureInt ();
191         if (CfgIVal < Start) {
192             CfgError ("Start address must be greater than end address");
193         }
194
195         /* Create a new location and add it to the list */
196         L = NewLocation (Start, CfgIVal);
197         CollAppend (&Locations, L);
198
199         /* Skip the end address and the following colon */
200         CfgNextTok ();
201         CfgConsumeColon ();
202
203         /* Parse attributes terminated by a semicolon */
204         while (CfgTok == CFGTOK_IDENT) {
205
206             /* Generate a new attribute with the given name, then skip it */
207             CfgData* D = NewCfgData ();
208             CfgNextTok ();
209
210             /* An optional assignment follows */
211             CfgOptionalAssign ();
212
213             /* Check and assign the attribute value */
214             switch (CfgTok) {
215
216                 case CFGTOK_INTCON:
217                     D->Type   = CfgDataNumber;
218                     D->V.IVal = CfgIVal;
219                     break;
220
221                 case CFGTOK_STRCON:
222                     D->Type   = CfgDataString;
223                     D->V.SVal = xstrdup (CfgSVal);
224                     break;
225
226                 case CFGTOK_IDENT:
227                     D->Type   = CfgDataId;
228                     D->V.SVal = xstrdup (CfgSVal);
229                     break;
230
231                 default:
232                     CfgError ("Invalid attribute type");
233             }
234
235             /* Add the attribute to the location */
236             CollAppend (&L->Attributes, D);
237
238             /* Skip the attribute value and an optional comma */
239             CfgNextTok ();
240             CfgOptionalComma ();
241         }
242
243         /* Skip the semicolon */
244         CfgConsumeSemi ();
245     }
246
247     /* Sort all memory locations */
248     CollSort (&Locations, CmpLocations, 0);
249
250     /* Check for overlaps and other problems */
251     Last = 0;
252     for (I = 0; I < CollCount (&Locations); ++I) {
253
254         /* Get this location */
255         const Location* L = CollAtUnchecked (&Locations, I);
256
257         /* Check for an overlap with the following location */
258         if (Last && Last->End >= L->Start) {
259             Error ("%s(%u): Address range overlap (overlapping entry is in line %u)",
260                    CfgGetName(), L->Line, Last->Line);
261         }
262
263         /* If the location is a mirror, it must not have other attributes,
264          * and the mirror attribute must be an integer.
265          */
266         if (LocationIsMirror (L)) {
267             const CfgData* D;
268             if (CollCount (&L->Attributes) > 1) {
269                 Error ("%s(%u): Location at address $%06X is a mirror "
270                        "but has attributes", CfgGetName(), L->Line, L->Start);
271             }
272             D = CollConstAt (&L->Attributes, 0);
273             CfgDataCheckType (D, CfgDataNumber);
274         }
275
276         /* Remember this entry */
277         Last = L;
278     }
279
280     /* Now create the chip instances. Since we can only mirror existing chips,
281      * we will first create all real chips and the mirrors in a second run.
282      */
283     for (I = 0; I < CollCount (&Locations); ++I) {
284
285         int Index;
286         CfgData* D;
287         unsigned Range;         /* Address range for this chip */
288         ChipInstance* CI;
289
290         /* Get this location */
291         Location* L = CollAtUnchecked (&Locations, I);
292
293         /* Skip mirrors */
294         if (LocationIsMirror (L)) {
295             continue;
296         }
297
298         /* The chip must have an attribute "name" of type string */
299         Index = LocationGetAttr (L, "name");
300         D = CollAt (&L->Attributes, Index);
301         CfgDataCheckType (D, CfgDataString);
302
303         /* Remove the "name" attribute from the attribute list */
304         CollDelete (&L->Attributes, Index);
305
306         /* Create the chip instance for the address range */
307         Range = L->End - L->Start + 1;
308         CI = NewChipInstance (D->V.SVal, L->Start, Range, &L->Attributes);
309
310         /* Delete the "name" attribute */
311         FreeCfgData (D);
312
313         /* Assign the chip instance to memory */
314         MemAssignChip (CI, L->Start, Range);
315     }
316
317     /* Create the mirrors */
318     for (I = 0; I < CollCount (&Locations); ++I) {
319
320         const CfgData* D;
321         unsigned MirrorAddr;    /* Mirror address */
322         unsigned Range;         /* Address range for this chip */
323         unsigned Offs;          /* Offset of the mirror */
324         const ChipInstance* CI; /* Original chip instance */
325         ChipInstance* MCI;      /* Mirrored chip instance */
326
327         /* Get this location */
328         const Location* L = CollAtUnchecked (&Locations, I);
329
330         /* Skip non mirrors */
331         if (!LocationIsMirror (L)) {
332             continue;
333         }
334
335         /* Calculate the address range */
336         Range = L->End - L->Start;
337
338         /* Get the mirror address */
339         D = CollConstAt (&L->Attributes, 0);
340         MirrorAddr = (unsigned) D->V.IVal;
341
342         /* For simplicity, get the chip instance we're mirroring from the
343          * memory, instead of searching for the range in the list.
344          */
345         CI = MemGetChip (MirrorAddr);
346         if (CI == 0) {
347             /* We are mirroring an unassigned address */
348             Error ("%s(%u): Mirroring an unassigned address",
349                    CfgGetName (), L->Line);
350         }
351
352         /* Make sure we're mirroring the correct chip */
353         CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
354
355         /* Calculate the offset of the mirror */
356         Offs = MirrorAddr - CI->Addr;
357
358         /* Check if the mirror range is ok */
359         if (Offs + Range > CI->Size) {
360             Error ("%s(%u): Mirror range is too large", CfgGetName (), L->Line);
361         }
362
363         /* Clone the chip instance for the new location */
364         MCI = MirrorChipInstance (CI, L->Start - Offs);
365
366         /* Assign the chip instance to memory */
367         MemAssignChip (MCI, L->Start, Range);
368     }
369 }
370
371
372
373 static void ParseConfig (void)
374 /* Parse the config file */
375 {
376     static const IdentTok BlockNames [] = {
377         {   "MEMORY",   CFGTOK_MEMORY   },
378     };
379     cfgtok_t BlockTok;
380
381     do {
382
383         /* Read the block ident */
384         CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
385         BlockTok = CfgTok;
386         CfgNextTok ();
387
388         /* Expected a curly brace */
389         CfgConsume (CFGTOK_LCURLY, "`{' expected");
390
391         /* Read the block */
392         switch (BlockTok) {
393
394             case CFGTOK_MEMORY:
395                 ParseMemory ();
396                 break;
397
398             default:
399                 FAIL ("Unexpected block token");
400
401         }
402
403         /* Skip closing brace */
404         CfgConsume (CFGTOK_RCURLY, "`}' expected");
405
406     } while (CfgTok != CFGTOK_EOF);
407 }
408
409
410
411 void CfgRead (void)
412 /* Read the configuration */
413 {
414     /* If we have a config name given, open the file, otherwise we will read
415      * from a buffer.
416      */
417     CfgOpenInput ();
418
419     /* Parse the file */
420     ParseConfig ();
421
422     /* Close the input file */
423     CfgCloseInput ();
424 }
425
426
427