1 /*****************************************************************************/
5 /* Configuration file parsing for the sim65 6502 simulator */
9 /* (C) 1998-2003 Ullrich von Bassewitz */
10 /* Römerstrasse 52 */
11 /* D-70794 Filderstadt */
12 /* EMail: uz@cc65.org */
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. */
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: */
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 */
32 /*****************************************************************************/
59 /*****************************************************************************/
61 /*****************************************************************************/
65 /* List of all memory locations */
66 static Collection Locations;
68 /* One memory location */
69 typedef struct Location 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 */
80 /*****************************************************************************/
82 /*****************************************************************************/
86 static void CfgDataCheckType (const CfgData* D, unsigned Type)
87 /* Check the config data type */
89 if (D->Type != Type) {
90 Error ("%s(%u): Attribute `%s' has invalid type",
91 CfgGetName (), D->Line, D->Attr);
97 /*****************************************************************************/
99 /*****************************************************************************/
103 static Location* NewLocation (unsigned long Start, unsigned long End)
104 /* Create a new location, initialize and return it */
106 /* Allocate memory */
107 Location* L = xmalloc (sizeof (Location));
109 /* Initialize the fields */
112 L->Attributes = EmptyCollection;
113 L->Line = CfgErrorLine;
114 L->Col = CfgErrorCol;
116 /* Return the new struct */
122 static int CmpLocations (void* Data attribute ((unused)),
123 const void* lhs, const void* rhs)
124 /* Compare function for CollSort */
126 /* Cast the object pointers */
127 const Location* Left = (const Location*) rhs;
128 const Location* Right = (const Location*) lhs;
131 if (Left->Start < Right->Start) {
133 } else if (Left->Start > Right->Start) {
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.
147 int I = CfgDataFind (&L->Attributes, AttrName);
149 Error ("%s(%u): Attribute `%s' missing", CfgGetName(), L->Line, AttrName);
156 static int LocationIsMirror (const Location* L)
157 /* Return true if the given location is a mirror of another one. */
159 /* Find the "mirror" attribute */
160 return (CfgDataFind (&L->Attributes, "mirror") >= 0);
165 /*****************************************************************************/
167 /*****************************************************************************/
171 static void ParseMemory (void)
172 /* Parse a MEMORY section */
175 const Location* Last;
178 while (CfgTok == CFGTOK_INTCON) {
182 /* Remember the start address and skip it */
183 unsigned long Start = CfgIVal;
187 CfgConsume (CFGTOK_DOTDOT, "`..' expected");
189 /* End address must follow and must be greater than start */
191 if (CfgIVal < Start) {
192 CfgError ("Start address must be greater than end address");
195 /* Create a new location and add it to the list */
196 L = NewLocation (Start, CfgIVal);
197 CollAppend (&Locations, L);
199 /* Skip the end address and the following colon */
203 /* Parse attributes terminated by a semicolon */
204 while (CfgTok == CFGTOK_IDENT) {
206 /* Generate a new attribute with the given name, then skip it */
207 CfgData* D = NewCfgData ();
210 /* An optional assignment follows */
211 CfgOptionalAssign ();
213 /* Check and assign the attribute value */
217 D->Type = CfgDataNumber;
222 D->Type = CfgDataString;
223 D->V.SVal = xstrdup (CfgSVal);
228 D->V.SVal = xstrdup (CfgSVal);
232 CfgError ("Invalid attribute type");
235 /* Add the attribute to the location */
236 CollAppend (&L->Attributes, D);
238 /* Skip the attribute value and an optional comma */
243 /* Skip the semicolon */
247 /* Sort all memory locations */
248 CollSort (&Locations, CmpLocations, 0);
250 /* Check for overlaps and other problems */
252 for (I = 0; I < CollCount (&Locations); ++I) {
254 /* Get this location */
255 const Location* L = CollAtUnchecked (&Locations, I);
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);
263 /* If the location is a mirror, it must not have other attributes,
264 * and the mirror attribute must be an integer.
266 if (LocationIsMirror (L)) {
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);
272 D = CollConstAt (&L->Attributes, 0);
273 CfgDataCheckType (D, CfgDataNumber);
276 /* Remember this entry */
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.
283 for (I = 0; I < CollCount (&Locations); ++I) {
287 unsigned Range; /* Address range for this chip */
290 /* Get this location */
291 Location* L = CollAtUnchecked (&Locations, I);
294 if (LocationIsMirror (L)) {
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);
303 /* Remove the "name" attribute from the attribute list */
304 CollDelete (&L->Attributes, Index);
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);
310 /* Delete the "name" attribute */
313 /* Assign the chip instance to memory */
314 MemAssignChip (CI, L->Start, Range);
317 /* Create the mirrors */
318 for (I = 0; I < CollCount (&Locations); ++I) {
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 */
327 /* Get this location */
328 const Location* L = CollAtUnchecked (&Locations, I);
330 /* Skip non mirrors */
331 if (!LocationIsMirror (L)) {
335 /* Calculate the address range */
336 Range = L->End - L->Start;
338 /* Get the mirror address */
339 D = CollConstAt (&L->Attributes, 0);
340 MirrorAddr = (unsigned) D->V.IVal;
342 /* For simplicity, get the chip instance we're mirroring from the
343 * memory, instead of searching for the range in the list.
345 CI = MemGetChip (MirrorAddr);
347 /* We are mirroring an unassigned address */
348 Error ("%s(%u): Mirroring an unassigned address",
349 CfgGetName (), L->Line);
352 /* Make sure we're mirroring the correct chip */
353 CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
355 /* Calculate the offset of the mirror */
356 Offs = MirrorAddr - CI->Addr;
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);
363 /* Clone the chip instance for the new location */
364 MCI = MirrorChipInstance (CI, L->Start - Offs);
366 /* Assign the chip instance to memory */
367 MemAssignChip (MCI, L->Start, Range);
373 static void ParseConfig (void)
374 /* Parse the config file */
376 static const IdentTok BlockNames [] = {
377 { "MEMORY", CFGTOK_MEMORY },
383 /* Read the block ident */
384 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
388 /* Expected a curly brace */
389 CfgConsume (CFGTOK_LCURLY, "`{' expected");
399 FAIL ("Unexpected block token");
403 /* Skip closing brace */
404 CfgConsume (CFGTOK_RCURLY, "`}' expected");
406 } while (CfgTok != CFGTOK_EOF);
412 /* Read the configuration */
414 /* If we have a config name given, open the file, otherwise we will read
422 /* Close the input file */