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 /*****************************************************************************/
60 /*****************************************************************************/
62 /*****************************************************************************/
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.
72 CfgError ("%s is already defined", Name);
79 static void AttrCheck (unsigned Attr, unsigned Mask, const char* Name)
80 /* Check that a mandatory attribute was given */
82 if ((Attr & Mask) == 0) {
83 CfgError ("%s attribute is missing", Name);
89 static void ParseCPU (void)
90 /* Parse a CPU section */
92 static const IdentTok Attributes [] = {
93 { "TYPE", CFGTOK_TYPE },
94 { "ADDRSPACE", CFGTOK_ADDRSPACE },
103 unsigned long Size = 0;
106 while (CfgTok == CFGTOK_IDENT) {
109 CfgSpecialToken (Attributes, ENTRY_COUNT (Attributes), "Attribute");
112 /* An optional assignment follows */
114 CfgOptionalAssign ();
116 /* Check which attribute was given */
120 FlagAttr (&Attr, atType, "TYPE");
125 case CFGTOK_ADDRSPACE:
126 FlagAttr (&Attr, atAddrSpace, "ADDRSPACE");
128 CfgRangeCheck (0x1000, 0x1000000);
133 FAIL ("Unexpected attribute token");
137 /* Skip the attribute value and an optional comma */
142 /* Must have some attributes */
143 AttrCheck (Attr, atType, "TYPE");
144 AttrCheck (Attr, atAddrSpace, "ADDRSPACE");
146 /* Skip the semicolon */
152 static void ParseMemory (void)
153 /* Parse a MEMORY section */
158 while (CfgTok == CFGTOK_INTCON) {
162 /* Remember the start address and skip it */
163 unsigned long Start = CfgIVal;
167 CfgConsume (CFGTOK_DOTDOT, "`..' expected");
169 /* End address must follow and must be greater than start */
171 if (CfgIVal < Start) {
172 CfgError ("Start address must be greater than end address");
175 /* Create a new location and add it to the list */
176 L = NewLocation (Start, CfgIVal);
177 CollAppend (&Locations, L);
179 /* Skip the end address and the following colon */
183 /* Parse attributes terminated by a semicolon */
184 while (CfgTok == CFGTOK_IDENT) {
186 /* Generate a new attribute with the given name, then skip it */
187 CfgData* D = NewCfgData ();
190 /* An optional assignment follows */
191 CfgOptionalAssign ();
193 /* Check and assign the attribute value */
197 D->Type = CfgDataNumber;
202 D->Type = CfgDataString;
203 D->V.SVal = xstrdup (CfgSVal);
208 D->V.SVal = xstrdup (CfgSVal);
212 CfgError ("Invalid attribute type");
215 /* Add the attribute to the location */
216 CollAppend (&L->Attributes, D);
218 /* Skip the attribute value and an optional comma */
223 /* Skip the semicolon */
227 /* Sort all memory locations */
228 LocationSort (&Locations);
230 /* Check the locations for overlaps and other problems */
231 LocationCheck (&Locations);
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.
236 for (I = 0; I < CollCount (&Locations); ++I) {
240 unsigned Range; /* Address range for this chip */
243 /* Get this location */
244 Location* L = CollAtUnchecked (&Locations, I);
247 if (LocationIsMirror (L)) {
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);
256 /* Remove the "name" attribute from the attribute list */
257 CollDelete (&L->Attributes, Index);
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);
263 /* Delete the "name" attribute */
266 /* Assign the chip instance to memory */
267 MemAssignChip (CI, L->Start, Range);
270 /* Create the mirrors */
271 for (I = 0; I < CollCount (&Locations); ++I) {
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 */
280 /* Get this location */
281 const Location* L = CollAtUnchecked (&Locations, I);
283 /* Skip non mirrors */
284 if (!LocationIsMirror (L)) {
288 /* Calculate the address range */
289 Range = L->End - L->Start;
291 /* Get the mirror address */
292 D = CollConstAt (&L->Attributes, 0);
293 MirrorAddr = (unsigned) D->V.IVal;
295 /* For simplicity, get the chip instance we're mirroring from the
296 * memory, instead of searching for the range in the list.
298 CI = MemGetChip (MirrorAddr);
300 /* We are mirroring an unassigned address */
301 Error ("%s(%u): Mirroring an unassigned address",
302 CfgGetName (), L->Line);
305 /* Make sure we're mirroring the correct chip */
306 CHECK (MirrorAddr >= CI->Addr && MirrorAddr < CI->Addr + CI->Size);
308 /* Calculate the offset of the mirror */
309 Offs = MirrorAddr - CI->Addr;
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);
316 /* Clone the chip instance for the new location */
317 MCI = MirrorChipInstance (CI, L->Start - Offs);
319 /* Assign the chip instance to memory */
320 MemAssignChip (MCI, L->Start, Range);
326 static void ParseConfig (void)
327 /* Parse the config file */
329 static const IdentTok BlockNames [] = {
330 { "CPU", CFGTOK_CPU },
331 { "MEMORY", CFGTOK_MEMORY },
337 /* Read the block ident */
338 CfgSpecialToken (BlockNames, ENTRY_COUNT (BlockNames), "Block identifier");
342 /* Expected a curly brace */
343 CfgConsume (CFGTOK_LCURLY, "`{' expected");
357 FAIL ("Unexpected block token");
361 /* Skip closing brace */
364 } while (CfgTok != CFGTOK_EOF);
370 /* Read the configuration */
372 /* If we have a config name given, open the file, otherwise we will read
380 /* Close the input file */